Merge master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb
diff --git a/Documentation/fb/cyblafb/bugs b/Documentation/fb/cyblafb/bugs
index f90cc66..9443a6d 100644
--- a/Documentation/fb/cyblafb/bugs
+++ b/Documentation/fb/cyblafb/bugs
@@ -11,4 +11,3 @@
 
 All LCD stuff is untested. If it worked in tridentfb, it should work in
 cyblafb. Please test and report the results to Knut_Petersen@t-online.de.
-
diff --git a/Documentation/fb/cyblafb/fb.modes b/Documentation/fb/cyblafb/fb.modes
index cf4351f..fe0e522 100644
--- a/Documentation/fb/cyblafb/fb.modes
+++ b/Documentation/fb/cyblafb/fb.modes
@@ -14,142 +14,141 @@
 #
 
 mode "640x480-50"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 47619 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-60"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 39682 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-70"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 34013 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-72"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 33068 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-75"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 31746 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-80"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 29761 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-85"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 28011 4294967256 24 17 0 216 3
 endmode
 
 mode "800x600-50"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 30303 96 24 14 0 136 11
 endmode
 
 mode "800x600-60"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 25252 96 24 14 0 136 11
 endmode
 
 mode "800x600-70"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 21645 96 24 14 0 136 11
 endmode
 
 mode "800x600-72"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 21043 96 24 14 0 136 11
 endmode
 
 mode "800x600-75"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 20202 96 24 14 0 136 11
 endmode
 
 mode "800x600-80"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 18939 96 24 14 0 136 11
 endmode
 
 mode "800x600-85"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 17825 96 24 14 0 136 11
 endmode
 
 mode "1024x768-50"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 19054 144 24 29 0 120 3
 endmode
 
 mode "1024x768-60"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 15880 144 24 29 0 120 3
 endmode
 
 mode "1024x768-70"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 13610 144 24 29 0 120 3
 endmode
 
 mode "1024x768-72"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 13232 144 24 29 0 120 3
 endmode
 
 mode "1024x768-75"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 12703 144 24 29 0 120 3
 endmode
 
 mode "1024x768-80"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 11910 144 24 29 0 120 3
 endmode
 
 mode "1024x768-85"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 11209 144 24 29 0 120 3
 endmode
 
 mode "1280x1024-50"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 11114 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-60"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 9262 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-70"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 7939 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-72"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 7719 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-75"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 7410 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-80"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 6946 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-85"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 6538 232 16 39 0 160 3
 endmode
-
diff --git a/Documentation/fb/cyblafb/performance b/Documentation/fb/cyblafb/performance
index eb4e47a..8d15d5d 100644
--- a/Documentation/fb/cyblafb/performance
+++ b/Documentation/fb/cyblafb/performance
@@ -77,4 +77,3 @@
 |	    |		      | 		|		  |
 |	    |		      | 		|		  |
 +-----------+-----------------+-----------------+-----------------+
-
diff --git a/Documentation/fb/cyblafb/todo b/Documentation/fb/cyblafb/todo
index 80fb2f8..c5f6d0e 100644
--- a/Documentation/fb/cyblafb/todo
+++ b/Documentation/fb/cyblafb/todo
@@ -22,11 +22,10 @@
 				everything else is done using color expanding
 				blitting of 1bpp character bitmaps.
 
-xpanning			Who needs it?
-
 ioctls				Who needs it?
 
-TV-out				Will be done later
+TV-out				Will be done later. Use "vga= " at boot time
+				to set a suitable video mode.
 
 ???				Feel free to contact me if you have any
 				feature requests
diff --git a/Documentation/fb/cyblafb/usage b/Documentation/fb/cyblafb/usage
index e627c8f..a39bb3d 100644
--- a/Documentation/fb/cyblafb/usage
+++ b/Documentation/fb/cyblafb/usage
@@ -40,6 +40,16 @@
 	None of the modes possible to select as startup modes are affected by
 	the problems described at the end of the next subsection.
 
+	For all startup modes cyblafb chooses a virtual x resolution of 2048,
+	the only exception is mode 1280x1024 in combination with 32 bpp. This
+	allows ywrap scrolling for all those modes if rotation is 0 or 2, and
+	also fast scrolling if rotation is 1 or 3. The default virtual y reso-
+	lution is 4096 for bpp == 8, 2048 for bpp==16 and 1024 for bpp == 32,
+	again with the only exception of 1280x1024 at 32 bpp.
+
+	Please do set your video memory size to 8 Mb in the Bios setup. Other
+	values will work, but performace is decreased for a lot of modes.
+
 	Mode changes using fbset
 	========================
 
@@ -54,20 +64,26 @@
 		- if a flat panel is found, cyblafb does not allow you
 		  to program a resolution higher than the physical
 		  resolution of the flat panel monitor
-		- cyblafb does not allow xres to differ from xres_virtual
 		- cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp
 		  and (currently) 24 bit modes use a doubled vclk internally,
 		  the dotclock limit as seen by fbset is 115 MHz for those
 		  modes and 230 MHz for 8 and 16 bpp modes.
+		- cyblafb will allow you to select very high resolutions as
+		  long as the hardware can be programmed to these modes. The
+		  documented limit 1600x1200 is not enforced, but don't expect
+		  perfect signal quality.
 
-	Any request that violates the rules given above will be ignored and
-	fbset will return an error.
+	Any request that violates the rules given above will be either changed
+	to something the hardware supports or an error value will be returned.
 
 	If you program a virtual y resolution higher than the hardware limit,
 	cyblafb will silently decrease that value to the highest possible
-	value.
+	value. The same is true for a virtual x resolution that is not
+	supported by the hardware. Cyblafb tries to adapt vyres first because
+	vxres decides if ywrap scrolling is possible or not.
 
-	Attempts to disable acceleration are ignored.
+	Attempts to disable acceleration are ignored, I believe that this is
+	safe.
 
 	Some video modes that should work do not work as expected. If you use
 	the standard fb.modes, fbset 640x480-60 will program that mode, but
@@ -129,10 +145,6 @@
 verbosity	0 is the default, increase to at least 2 for every
 		bug report!
 
-vesafb		allows cyblafb to be loaded after vesafb has been
-		loaded. See sections "Module unloading ...".
-
-
 Development hints
 =================
 
@@ -195,7 +207,7 @@
 After booting, load cyblafb without any mode and bpp parameter and assign
 cyblafb to individual ttys using con2fb, e.g.:
 
-	modprobe cyblafb vesafb=1
+	modprobe cyblafb
 	con2fb /dev/fb1 /dev/tty1
 
 Unloading cyblafb works without problems after you assign vesafb to all
@@ -203,4 +215,3 @@
 
 	con2fb /dev/fb0 /dev/tty1
 	rmmod cyblafb
-
diff --git a/Documentation/fb/cyblafb/whatsnew b/Documentation/fb/cyblafb/whatsnew
new file mode 100644
index 0000000..76c07a2
--- /dev/null
+++ b/Documentation/fb/cyblafb/whatsnew
@@ -0,0 +1,29 @@
+0.62
+====
+
+      - the vesafb parameter has been removed as I decided to allow the
+      	feature without any special parameter.
+
+      - Cyblafb does not use the vga style of panning any longer, now the
+      	"right view" register in the graphics engine IO space is used. Without
+	that change it was impossible to use all available memory, and without
+	access to all available memory it is impossible to ywrap.
+
+      - The imageblit function now uses hardware acceleration for all font
+        widths. Hardware blitting across pixel column 2048 is broken in the
+	cyberblade/i1 graphics core, but we work around that hardware bug.
+
+      - modes with vxres != xres are supported now.
+
+      - ywrap scrolling is supported now and the default. This is a big
+        performance gain.
+
+      - default video modes use vyres > yres and vxres > xres to allow
+        almost optimal scrolling speed for normal and rotated screens
+
+      - some features mainly usefull for debugging the upper layers of the
+        framebuffer system have been added, have a look at the code
+
+      - fixed: Oops after unloading cyblafb when reading /proc/io*
+
+      - we work around some bugs of the higher framebuffer layers.
diff --git a/Documentation/filesystems/spufs.txt b/Documentation/filesystems/spufs.txt
new file mode 100644
index 0000000..8edc395
--- /dev/null
+++ b/Documentation/filesystems/spufs.txt
@@ -0,0 +1,521 @@
+SPUFS(2)                   Linux Programmer's Manual                  SPUFS(2)
+
+
+
+NAME
+       spufs - the SPU file system
+
+
+DESCRIPTION
+       The SPU file system is used on PowerPC machines that implement the Cell
+       Broadband Engine Architecture in order to access Synergistic  Processor
+       Units (SPUs).
+
+       The file system provides a name space similar to posix shared memory or
+       message queues. Users that have write permissions on  the  file  system
+       can use spu_create(2) to establish SPU contexts in the spufs root.
+
+       Every SPU context is represented by a directory containing a predefined
+       set of files. These files can be used for manipulating the state of the
+       logical SPU. Users can change permissions on those files, but not actu-
+       ally add or remove files.
+
+
+MOUNT OPTIONS
+       uid=<uid>
+              set the user owning the mount point, the default is 0 (root).
+
+       gid=<gid>
+              set the group owning the mount point, the default is 0 (root).
+
+
+FILES
+       The files in spufs mostly follow the standard behavior for regular sys-
+       tem  calls like read(2) or write(2), but often support only a subset of
+       the operations supported on regular file systems. This list details the
+       supported  operations  and  the  deviations  from  the behaviour in the
+       respective man pages.
+
+       All files that support the read(2) operation also support readv(2)  and
+       all  files  that support the write(2) operation also support writev(2).
+       All files support the access(2) and stat(2) family of  operations,  but
+       only  the  st_mode,  st_nlink,  st_uid and st_gid fields of struct stat
+       contain reliable information.
+
+       All files support the chmod(2)/fchmod(2) and chown(2)/fchown(2)  opera-
+       tions,  but  will  not be able to grant permissions that contradict the
+       possible operations, e.g. read access on the wbox file.
+
+       The current set of files is:
+
+
+   /mem
+       the contents of the local storage memory  of  the  SPU.   This  can  be
+       accessed  like  a regular shared memory file and contains both code and
+       data in the address space of the SPU.  The possible  operations  on  an
+       open mem file are:
+
+       read(2), pread(2), write(2), pwrite(2), lseek(2)
+              These  operate  as  documented, with the exception that seek(2),
+              write(2) and pwrite(2) are not supported beyond the end  of  the
+              file. The file size is the size of the local storage of the SPU,
+              which normally is 256 kilobytes.
+
+       mmap(2)
+              Mapping mem into the process address space gives access  to  the
+              SPU  local  storage  within  the  process  address  space.  Only
+              MAP_SHARED mappings are allowed.
+
+
+   /mbox
+       The first SPU to CPU communication mailbox. This file is read-only  and
+       can  be  read  in  units of 32 bits.  The file can only be used in non-
+       blocking mode and it even poll() will not block on  it.   The  possible
+       operations on an open mbox file are:
+
+       read(2)
+              If  a  count smaller than four is requested, read returns -1 and
+              sets errno to EINVAL.  If there is no data available in the mail
+              box,  the  return  value  is set to -1 and errno becomes EAGAIN.
+              When data has been read successfully, four bytes are  placed  in
+              the data buffer and the value four is returned.
+
+
+   /ibox
+       The  second  SPU  to CPU communication mailbox. This file is similar to
+       the first mailbox file, but can be read in blocking I/O mode,  and  the
+       poll  familiy of system calls can be used to wait for it.  The possible
+       operations on an open ibox file are:
+
+       read(2)
+              If a count smaller than four is requested, read returns  -1  and
+              sets errno to EINVAL.  If there is no data available in the mail
+              box and the file descriptor has been opened with O_NONBLOCK, the
+              return value is set to -1 and errno becomes EAGAIN.
+
+              If  there  is  no  data  available  in the mail box and the file
+              descriptor has been opened without  O_NONBLOCK,  the  call  will
+              block  until  the  SPU  writes to its interrupt mailbox channel.
+              When data has been read successfully, four bytes are  placed  in
+              the data buffer and the value four is returned.
+
+       poll(2)
+              Poll  on  the  ibox  file returns (POLLIN | POLLRDNORM) whenever
+              data is available for reading.
+
+
+   /wbox
+       The CPU to SPU communation mailbox. It is write-only can can be written
+       in  units  of  32  bits. If the mailbox is full, write() will block and
+       poll can be used to wait for it becoming  empty  again.   The  possible
+       operations  on  an open wbox file are: write(2) If a count smaller than
+       four is requested, write returns -1 and sets errno to EINVAL.  If there
+       is  no space available in the mail box and the file descriptor has been
+       opened with O_NONBLOCK, the return value is set to -1 and errno becomes
+       EAGAIN.
+
+       If  there is no space available in the mail box and the file descriptor
+       has been opened without O_NONBLOCK, the call will block until  the  SPU
+       reads  from  its PPE mailbox channel.  When data has been read success-
+       fully, four bytes are placed in the data buffer and the value  four  is
+       returned.
+
+       poll(2)
+              Poll  on  the  ibox file returns (POLLOUT | POLLWRNORM) whenever
+              space is available for writing.
+
+
+   /mbox_stat
+   /ibox_stat
+   /wbox_stat
+       Read-only files that contain the length of the current queue, i.e.  how
+       many  words  can  be  read  from  mbox or ibox or how many words can be
+       written to wbox without blocking.  The files can be read only in 4-byte
+       units  and  return  a  big-endian  binary integer number.  The possible
+       operations on an open *box_stat file are:
+
+       read(2)
+              If a count smaller than four is requested, read returns  -1  and
+              sets errno to EINVAL.  Otherwise, a four byte value is placed in
+              the data buffer, containing the number of elements that  can  be
+              read  from  (for  mbox_stat  and  ibox_stat)  or written to (for
+              wbox_stat) the respective mail box without blocking or resulting
+              in EAGAIN.
+
+
+   /npc
+   /decr
+   /decr_status
+   /spu_tag_mask
+   /event_mask
+   /srr0
+       Internal  registers  of  the SPU. The representation is an ASCII string
+       with the numeric value of the next instruction to  be  executed.  These
+       can  be  used in read/write mode for debugging, but normal operation of
+       programs should not rely on them because access to any of  them  except
+       npc requires an SPU context save and is therefore very inefficient.
+
+       The contents of these files are:
+
+       npc                 Next Program Counter
+
+       decr                SPU Decrementer
+
+       decr_status         Decrementer Status
+
+       spu_tag_mask        MFC tag mask for SPU DMA
+
+       event_mask          Event mask for SPU interrupts
+
+       srr0                Interrupt Return address register
+
+
+       The   possible   operations   on   an   open  npc,  decr,  decr_status,
+       spu_tag_mask, event_mask or srr0 file are:
+
+       read(2)
+              When the count supplied to the read call  is  shorter  than  the
+              required  length for the pointer value plus a newline character,
+              subsequent reads from the same file descriptor  will  result  in
+              completing  the string, regardless of changes to the register by
+              a running SPU task.  When a complete string has been  read,  all
+              subsequent read operations will return zero bytes and a new file
+              descriptor needs to be opened to read the value again.
+
+       write(2)
+              A write operation on the file results in setting the register to
+              the  value  given  in  the string. The string is parsed from the
+              beginning to the first non-numeric character or the end  of  the
+              buffer.  Subsequent writes to the same file descriptor overwrite
+              the previous setting.
+
+
+   /fpcr
+       This file gives access to the Floating Point Status and Control  Regis-
+       ter as a four byte long file. The operations on the fpcr file are:
+
+       read(2)
+              If  a  count smaller than four is requested, read returns -1 and
+              sets errno to EINVAL.  Otherwise, a four byte value is placed in
+              the data buffer, containing the current value of the fpcr regis-
+              ter.
+
+       write(2)
+              If a count smaller than four is requested, write returns -1  and
+              sets  errno  to  EINVAL.  Otherwise, a four byte value is copied
+              from the data buffer, updating the value of the fpcr register.
+
+
+   /signal1
+   /signal2
+       The two signal notification channels of an SPU.  These  are  read-write
+       files  that  operate  on  a 32 bit word.  Writing to one of these files
+       triggers an interrupt on the SPU. The  value  writting  to  the  signal
+       files can be read from the SPU through a channel read or from host user
+       space through the file.  After the value has been read by the  SPU,  it
+       is  reset  to zero.  The possible operations on an open signal1 or sig-
+       nal2 file are:
+
+       read(2)
+              If a count smaller than four is requested, read returns  -1  and
+              sets errno to EINVAL.  Otherwise, a four byte value is placed in
+              the data buffer, containing the current value of  the  specified
+              signal notification register.
+
+       write(2)
+              If  a count smaller than four is requested, write returns -1 and
+              sets errno to EINVAL.  Otherwise, a four byte  value  is  copied
+              from the data buffer, updating the value of the specified signal
+              notification register.  The signal  notification  register  will
+              either be replaced with the input data or will be updated to the
+              bitwise OR or the old value and the input data, depending on the
+              contents  of  the  signal1_type,  or  signal2_type respectively,
+              file.
+
+
+   /signal1_type
+   /signal2_type
+       These two files change the behavior of the signal1 and signal2  notifi-
+       cation  files.  The  contain  a numerical ASCII string which is read as
+       either "1" or "0".  In mode 0 (overwrite), the  hardware  replaces  the
+       contents of the signal channel with the data that is written to it.  in
+       mode 1 (logical OR), the hardware accumulates the bits that are  subse-
+       quently written to it.  The possible operations on an open signal1_type
+       or signal2_type file are:
+
+       read(2)
+              When the count supplied to the read call  is  shorter  than  the
+              required  length  for the digit plus a newline character, subse-
+              quent reads from the same file descriptor will  result  in  com-
+              pleting  the  string.  When a complete string has been read, all
+              subsequent read operations will return zero bytes and a new file
+              descriptor needs to be opened to read the value again.
+
+       write(2)
+              A write operation on the file results in setting the register to
+              the value given in the string. The string  is  parsed  from  the
+              beginning  to  the first non-numeric character or the end of the
+              buffer.  Subsequent writes to the same file descriptor overwrite
+              the previous setting.
+
+
+EXAMPLES
+       /etc/fstab entry
+              none      /spu      spufs     gid=spu   0    0
+
+
+AUTHORS
+       Arnd  Bergmann  <arndb@de.ibm.com>,  Mark  Nutter <mnutter@us.ibm.com>,
+       Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+SEE ALSO
+       capabilities(7), close(2), spu_create(2), spu_run(2), spufs(7)
+
+
+
+Linux                             2005-09-28                          SPUFS(2)
+
+------------------------------------------------------------------------------
+
+SPU_RUN(2)                 Linux Programmer's Manual                SPU_RUN(2)
+
+
+
+NAME
+       spu_run - execute an spu context
+
+
+SYNOPSIS
+       #include <sys/spu.h>
+
+       int spu_run(int fd, unsigned int *npc, unsigned int *event);
+
+DESCRIPTION
+       The  spu_run system call is used on PowerPC machines that implement the
+       Cell Broadband Engine Architecture in order to access Synergistic  Pro-
+       cessor  Units  (SPUs).  It  uses the fd that was returned from spu_cre-
+       ate(2) to address a specific SPU context. When the context gets  sched-
+       uled  to a physical SPU, it starts execution at the instruction pointer
+       passed in npc.
+
+       Execution of SPU code happens synchronously, meaning that spu_run  does
+       not  return  while the SPU is still running. If there is a need to exe-
+       cute SPU code in parallel with other code on either  the  main  CPU  or
+       other  SPUs,  you  need to create a new thread of execution first, e.g.
+       using the pthread_create(3) call.
+
+       When spu_run returns, the current value of the SPU instruction  pointer
+       is  written back to npc, so you can call spu_run again without updating
+       the pointers.
+
+       event can be a NULL pointer or point to an extended  status  code  that
+       gets  filled  when spu_run returns. It can be one of the following con-
+       stants:
+
+       SPE_EVENT_DMA_ALIGNMENT
+              A DMA alignment error
+
+       SPE_EVENT_SPE_DATA_SEGMENT
+              A DMA segmentation error
+
+       SPE_EVENT_SPE_DATA_STORAGE
+              A DMA storage error
+
+       If NULL is passed as the event argument, these errors will result in  a
+       signal delivered to the calling process.
+
+RETURN VALUE
+       spu_run  returns the value of the spu_status register or -1 to indicate
+       an error and set errno to one of the error  codes  listed  below.   The
+       spu_status  register  value  contains  a  bit  mask of status codes and
+       optionally a 14 bit code returned from the stop-and-signal  instruction
+       on the SPU. The bit masks for the status codes are:
+
+       0x02   SPU was stopped by stop-and-signal.
+
+       0x04   SPU was stopped by halt.
+
+       0x08   SPU is waiting for a channel.
+
+       0x10   SPU is in single-step mode.
+
+       0x20   SPU has tried to execute an invalid instruction.
+
+       0x40   SPU has tried to access an invalid channel.
+
+       0x3fff0000
+              The  bits  masked with this value contain the code returned from
+              stop-and-signal.
+
+       There are always one or more of the lower eight bits set  or  an  error
+       code is returned from spu_run.
+
+ERRORS
+       EAGAIN or EWOULDBLOCK
+              fd is in non-blocking mode and spu_run would block.
+
+       EBADF  fd is not a valid file descriptor.
+
+       EFAULT npc is not a valid pointer or status is neither NULL nor a valid
+              pointer.
+
+       EINTR  A signal occured while spu_run was in progress.  The  npc  value
+              has  been updated to the new program counter value if necessary.
+
+       EINVAL fd is not a file descriptor returned from spu_create(2).
+
+       ENOMEM Insufficient memory was available to handle a page fault result-
+              ing from an MFC direct memory access.
+
+       ENOSYS the functionality is not provided by the current system, because
+              either the hardware does not provide SPUs or the spufs module is
+              not loaded.
+
+
+NOTES
+       spu_run  is  meant  to  be  used  from  libraries that implement a more
+       abstract interface to SPUs, not to be used from  regular  applications.
+       See  http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec-
+       ommended libraries.
+
+
+CONFORMING TO
+       This call is Linux specific and only implemented by the ppc64 architec-
+       ture. Programs using this system call are not portable.
+
+
+BUGS
+       The code does not yet fully implement all features lined out here.
+
+
+AUTHOR
+       Arnd Bergmann <arndb@de.ibm.com>
+
+SEE ALSO
+       capabilities(7), close(2), spu_create(2), spufs(7)
+
+
+
+Linux                             2005-09-28                        SPU_RUN(2)
+
+------------------------------------------------------------------------------
+
+SPU_CREATE(2)              Linux Programmer's Manual             SPU_CREATE(2)
+
+
+
+NAME
+       spu_create - create a new spu context
+
+
+SYNOPSIS
+       #include <sys/types.h>
+       #include <sys/spu.h>
+
+       int spu_create(const char *pathname, int flags, mode_t mode);
+
+DESCRIPTION
+       The  spu_create  system call is used on PowerPC machines that implement
+       the Cell Broadband Engine Architecture in order to  access  Synergistic
+       Processor  Units (SPUs). It creates a new logical context for an SPU in
+       pathname and returns a handle to associated  with  it.   pathname  must
+       point  to  a  non-existing directory in the mount point of the SPU file
+       system (spufs).  When spu_create is successful, a directory  gets  cre-
+       ated on pathname and it is populated with files.
+
+       The  returned  file  handle can only be passed to spu_run(2) or closed,
+       other operations are not defined on it. When it is closed, all  associ-
+       ated  directory entries in spufs are removed. When the last file handle
+       pointing either inside  of  the  context  directory  or  to  this  file
+       descriptor is closed, the logical SPU context is destroyed.
+
+       The  parameter flags can be zero or any bitwise or'd combination of the
+       following constants:
+
+       SPU_RAWIO
+              Allow mapping of some of the hardware registers of the SPU  into
+              user space. This flag requires the CAP_SYS_RAWIO capability, see
+              capabilities(7).
+
+       The mode parameter specifies the permissions used for creating the  new
+       directory  in  spufs.   mode is modified with the user's umask(2) value
+       and then used for both the directory and the files contained in it. The
+       file permissions mask out some more bits of mode because they typically
+       support only read or write access. See stat(2) for a full list  of  the
+       possible mode values.
+
+
+RETURN VALUE
+       spu_create  returns a new file descriptor. It may return -1 to indicate
+       an error condition and set errno to  one  of  the  error  codes  listed
+       below.
+
+
+ERRORS
+       EACCESS
+              The  current  user does not have write access on the spufs mount
+              point.
+
+       EEXIST An SPU context already exists at the given path name.
+
+       EFAULT pathname is not a valid string pointer in  the  current  address
+              space.
+
+       EINVAL pathname is not a directory in the spufs mount point.
+
+       ELOOP  Too many symlinks were found while resolving pathname.
+
+       EMFILE The process has reached its maximum open file limit.
+
+       ENAMETOOLONG
+              pathname was too long.
+
+       ENFILE The system has reached the global open file limit.
+
+       ENOENT Part of pathname could not be resolved.
+
+       ENOMEM The kernel could not allocate all resources required.
+
+       ENOSPC There  are  not  enough  SPU resources available to create a new
+              context or the user specific limit for the number  of  SPU  con-
+              texts has been reached.
+
+       ENOSYS the functionality is not provided by the current system, because
+              either the hardware does not provide SPUs or the spufs module is
+              not loaded.
+
+       ENOTDIR
+              A part of pathname is not a directory.
+
+
+
+NOTES
+       spu_create  is  meant  to  be used from libraries that implement a more
+       abstract interface to SPUs, not to be used from  regular  applications.
+       See  http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec-
+       ommended libraries.
+
+
+FILES
+       pathname must point to a location beneath the mount point of spufs.  By
+       convention, it gets mounted in /spu.
+
+
+CONFORMING TO
+       This call is Linux specific and only implemented by the ppc64 architec-
+       ture. Programs using this system call are not portable.
+
+
+BUGS
+       The code does not yet fully implement all features lined out here.
+
+
+AUTHOR
+       Arnd Bergmann <arndb@de.ibm.com>
+
+SEE ALSO
+       capabilities(7), close(2), spu_run(2), spufs(7)
+
+
+
+Linux                             2005-09-28                     SPU_CREATE(2)
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index 0541fe1..0ea5a0c 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -411,7 +411,8 @@
 		printk("Couldn't find %s to plant kprobe\n", "do_fork");
 		return -1;
 	}
-	if ((ret = register_kprobe(&kp) < 0)) {
+	ret = register_kprobe(&kp);
+	if (ret < 0) {
 		printk("register_kprobe failed, returned %d\n", ret);
 		return -1;
 	}
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index b0fe41d..8d8b4e5 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -945,7 +945,6 @@
           collisions:0 txqueuelen:0
 
 eth0      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4
-          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
           UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
           RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0
           TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0
@@ -953,7 +952,6 @@
           Interrupt:10 Base address:0x1080
 
 eth1      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4
-          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
           UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
           RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0
           TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0
diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX
index e7bea0a..d6d65b9 100644
--- a/Documentation/powerpc/00-INDEX
+++ b/Documentation/powerpc/00-INDEX
@@ -8,12 +8,18 @@
 cpu_features.txt
 	- info on how we support a variety of CPUs with minimal compile-time
 	options.
+eeh-pci-error-recovery.txt
+	- info on PCI Bus EEH Error Recovery
+hvcs.txt
+	- IBM "Hypervisor Virtual Console Server" Installation Guide
+mpc52xx.txt
+	- Linux 2.6.x on MPC52xx family
 ppc_htab.txt
 	- info about the Linux/PPC /proc/ppc_htab entry
-smp.txt
-	- use and state info about Linux/PPC on MP machines
 SBC8260_memory_mapping.txt
 	- EST SBC8260 board info
+smp.txt
+	- use and state info about Linux/PPC on MP machines
 sound.txt
 	- info on sound support under Linux/PPC
 zImage_layout.txt
diff --git a/MAINTAINERS b/MAINTAINERS
index 76dc820..270e28c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1697,7 +1697,6 @@
 
 MARVELL MV64340 ETHERNET DRIVER
 P:	Manish Lachwani
-M:	Manish_Lachwani@pmc-sierra.com
 L:	linux-mips@linux-mips.org
 L:	netdev@vger.kernel.org
 S:	Supported
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 06be405..9c89eeb 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -1171,7 +1171,8 @@
 		return -ENODEV;
 	}
 
-	if ((major = register_chrdev(0, module_name, &vpe_fops) < 0)) {
+	major = register_chrdev(0, module_name, &vpe_fops);
+	if (major < 0) {
 		printk("VPE loader: unable to register character device\n");
 		return major;
 	}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 331483a..28004f0 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -47,7 +47,7 @@
 
 config EARLY_PRINTK
 	bool
-	default y if PPC64
+	default y
 
 config COMPAT
 	bool
@@ -297,6 +297,7 @@
 	bool
 	depends on PPC_PMAC && POWER4
 	select U3_DART
+	select MPIC_BROKEN_U3
 	select GENERIC_TBSYNC
 	default y
 
@@ -325,9 +326,7 @@
 	select MMIO_NVRAM
 
 config PPC_OF
-	bool
-	depends on PPC_MULTIPLATFORM	# for now
-	default y
+	def_bool y
 
 config XICS
 	depends on PPC_PSERIES
@@ -376,11 +375,28 @@
 	bool
 	default y
 
+config CRASH_DUMP
+	bool "kernel crash dumps (EXPERIMENTAL)"
+	depends on PPC_MULTIPLATFORM
+	depends on EXPERIMENTAL
+	help
+	  Build a kernel suitable for use as a kdump capture kernel.
+	  The kernel will be linked at a different address than normal, and
+	  so can only be used for Kdump.
+
+	  Don't change this unless you know what you are doing.
+
 config IBMVIO
 	depends on PPC_PSERIES || PPC_ISERIES
 	bool
 	default y
 
+config IBMEBUS
+	depends on PPC_PSERIES
+	bool "Support for GX bus based adapters"
+	help
+	  Bus device driver for GX bus based adapters.
+
 config PPC_MPC106
 	bool
 	default n
@@ -472,6 +488,7 @@
 source arch/powerpc/platforms/4xx/Kconfig
 source arch/powerpc/platforms/85xx/Kconfig
 source arch/powerpc/platforms/8xx/Kconfig
+source arch/powerpc/platforms/cell/Kconfig
 
 menu "Kernel options"
 
@@ -575,11 +592,12 @@
 	depends on PPC64
 
 config ARCH_FLATMEM_ENABLE
-       def_bool y
-       depends on PPC64 && !NUMA
+	def_bool y
+	depends on (PPC64 && !NUMA) || PPC32
 
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
+	depends on PPC64
 
 config ARCH_SPARSEMEM_DEFAULT
 	def_bool y
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index a13eb57..5f80e58 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -151,7 +151,7 @@
 # All the instructions talk about "make bzImage".
 bzImage: zImage
 
-BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm
+BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage
 
 .PHONY: $(BOOT_TARGETS)
 
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 9770f58..22726ae 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -143,6 +143,36 @@
 	@cp -f $< $@
 	$(call if_changed,addnote)
 
+#-----------------------------------------------------------
+# build u-boot images
+#-----------------------------------------------------------
+quiet_cmd_mygzip = GZIP $@
+cmd_mygzip = gzip -f -9 < $< > $@.$$$$ && mv $@.$$$$ $@
+
+quiet_cmd_objbin = OBJCOPY $@
+      cmd_objbin = $(OBJCOPY) -O binary $< $@
+
+quiet_cmd_uimage = UIMAGE $@
+      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A ppc -O linux -T kernel \
+               -C gzip -a 00000000 -e 00000000 -n 'Linux-$(KERNELRELEASE)' \
+               -d $< $@
+
+MKIMAGE		:= $(srctree)/scripts/mkuboot.sh
+targets		+= uImage
+extra-y		+= vmlinux.bin vmlinux.gz
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+	$(call if_changed,objbin)
+
+$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+	$(call if_changed,mygzip)
+
+$(obj)/uImage: $(obj)/vmlinux.gz
+	$(Q)rm -f $@
+	$(call cmd,uimage)
+	@echo -n '  Image: $@ '
+	@if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
+
 install: $(CONFIGURE) $(BOOTIMAGE)
 	sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
 
diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
new file mode 100644
index 0000000..398203b
--- /dev/null
+++ b/arch/powerpc/configs/pmac32_defconfig
@@ -0,0 +1,1729 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc5
+# Tue Dec 13 17:24:05 2005
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_LBD=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
+# CONFIG_PPC_CHRP is not set
+CONFIG_PPC_PMAC=y
+CONFIG_PPC_OF=y
+CONFIG_MPIC=y
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PPC_MPC106=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_PMAC=y
+CONFIG_PPC601_SYNC_FIX=y
+# CONFIG_TAU is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_KEXEC is not set
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+CONFIG_PM_DEBUG=y
+CONFIG_SOFTWARE_SUSPEND=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=m
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=m
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# 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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+# CONFIG_IP_NF_MATCH_SCTP is not set
+CONFIG_IP_NF_MATCH_DCCP=m
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_TARGET_NFQUEUE is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+# CONFIG_IP_NF_MANGLE is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+# CONFIG_IP_DCCP_UNLOAD_HACK is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE 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_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+# CONFIG_BT_HCIUART is not set
+CONFIG_BT_HCIBCM203X=m
+# CONFIG_BT_HCIBPA10X is not set
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_MAC_FLOPPY=y
+# 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 is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_UB=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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=y
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_BLINK=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST 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=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC 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_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA24XX 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_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MESH_RESET_DELAY_MS=1000
+CONFIG_SCSI_MAC53C94=y
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+# CONFIG_IEEE1394_EXPORT_FULL_API is not set
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+# CONFIG_IEEE1394_CMP is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+CONFIG_ADB=y
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_PMU=y
+CONFIG_PMAC_APM_EMU=y
+CONFIG_PMAC_MEDIABAY=y
+CONFIG_PMAC_BACKLIGHT=y
+CONFIG_INPUT_ADBHID=y
+CONFIG_MAC_EMUMOUSEBTN=y
+CONFIG_THERM_WINDTUNNEL=m
+CONFIG_THERM_ADT746X=m
+# CONFIG_WINDFARM is not set
+# CONFIG_ANSLCD is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACE=y
+# CONFIG_MACE_AAUI_PORT is not set
+CONFIG_BMAC=y
+# CONFIG_HAPPYMEAL is not set
+CONFIG_SUNGEM=y
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 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_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 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_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_MV643XX_ETH is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+CONFIG_APPLE_AIRPORT=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_NORTEL_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_PCMCIA_SPECTRUM is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+# CONFIG_HOSTAP is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=m
+# CONFIG_SERIAL_PMACZILOG is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+CONFIG_AGP=m
+CONFIG_AGP_UNINORTH=m
+CONFIG_DRM=m
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_KEYWEST=m
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_MACMODES=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_CT65550=y
+# CONFIG_FB_ASILIANT is not set
+CONFIG_FB_IMSTT=y
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=y
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_FB_RIVA is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_FB_MATROX_G is not set
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY_CT=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+# CONFIG_FB_ATY_XL_INIT is not set
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+CONFIG_FB_3DFX=y
+# CONFIG_FB_3DFX_ACCEL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_CYBLA is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+CONFIG_DMASOUND_PMAC=m
+CONFIG_DMASOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_GENERIC_DRIVER=y
+
+#
+# Generic devices
+#
+CONFIG_SND_DUMMY=m
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_HDA_INTEL is not set
+
+#
+# ALSA PowerMac devices
+#
+CONFIG_SND_POWERMAC=m
+# CONFIG_SND_POWERMAC_AUTO_DRC is not set
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+# CONFIG_SND_USB_USX2Y is not set
+
+#
+# PCMCIA devices
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+CONFIG_USB_APPLETOUCH=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# 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=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=m
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=m
+# CONFIG_USB_ZD1201 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_RELAYFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_LOCKD=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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
+# CONFIG_9P_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=y
+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_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# 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 is not set
+CONFIG_NLS_ISO8859_1=m
+# 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=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+
+#
+# Instrumentation Support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+# CONFIG_BDI_SWITCH is not set
+CONFIG_BOOTX_TEXT=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 9ed551b..6e03b59 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -17,11 +17,11 @@
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
 				   signal_64.o ptrace32.o systbl.o \
 				   paca.o ioctl32.o cpu_setup_power4.o \
-				   firmware.o sysfs.o udbg.o idle_64.o
+				   firmware.o sysfs.o idle_64.o
 obj-$(CONFIG_PPC64)		+= vdso64/
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
 obj-$(CONFIG_POWER4)		+= idle_power4.o
-obj-$(CONFIG_PPC_OF)		+= of_device.o
+obj-$(CONFIG_PPC_OF)		+= of_device.o prom_parse.o
 procfs-$(CONFIG_PPC64)		:= proc_ppc64.o
 obj-$(CONFIG_PROC_FS)		+= $(procfs-y)
 rtaspci-$(CONFIG_PPC64)		:= rtas_pci.o
@@ -30,12 +30,10 @@
 obj-$(CONFIG_RTAS_PROC)		+= rtas-proc.o
 obj-$(CONFIG_LPARCFG)		+= lparcfg.o
 obj-$(CONFIG_IBMVIO)		+= vio.o
+obj-$(CONFIG_IBMEBUS)           += ibmebus.o
 obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsync.o
-obj-$(CONFIG_PPC_PSERIES)	+= udbg_16550.o
-obj-$(CONFIG_PPC_MAPLE)		+= udbg_16550.o
-udbgscc-$(CONFIG_PPC64)		:= udbg_scc.o
-obj-$(CONFIG_PPC_PMAC)		+= $(udbgscc-y)
 obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o
+obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 
@@ -48,25 +46,25 @@
 extra-y				+= vmlinux.lds
 
 obj-y				+= process.o init_task.o time.o \
-				   prom.o traps.o setup-common.o
+				   prom.o traps.o setup-common.o udbg.o
 obj-$(CONFIG_PPC32)		+= entry_32.o setup_32.o misc_32.o systbl.o
 obj-$(CONFIG_PPC64)		+= misc_64.o dma_64.o iommu.o
-obj-$(CONFIG_PPC_OF)		+= prom_init.o
+obj-$(CONFIG_PPC_MULTIPLATFORM)	+= prom_init.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 obj-$(CONFIG_6xx)		+= idle_6xx.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
-
+obj-$(CONFIG_SERIAL_8250)	+= legacy_serial.o udbg_16550.o
 module-$(CONFIG_PPC64)		+= module_64.o
 obj-$(CONFIG_MODULES)		+= $(module-y)
 
 pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o pci_iommu.o \
 				   pci_direct_iommu.o iomap.o
 obj-$(CONFIG_PCI)		+= $(pci64-y)
-
-kexec64-$(CONFIG_PPC64)		+= machine_kexec_64.o
-obj-$(CONFIG_KEXEC)		+= $(kexec64-y)
+kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
+kexec-$(CONFIG_PPC32)		:= machine_kexec_32.o
+obj-$(CONFIG_KEXEC)		+= machine_kexec.o crash.o $(kexec-y)
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
 $(obj)/head_64.o: $(obj)/lparmap.s
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 91538d2..56399c5 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -92,9 +92,9 @@
 
 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
 	DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
-	DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
-#ifdef CONFIG_PPC32
+	DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame));
 	DEFINE(TI_TASK, offsetof(struct thread_info, task));
+#ifdef CONFIG_PPC32
 	DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
 	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 #endif /* CONFIG_PPC32 */
@@ -131,11 +131,9 @@
 	DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
 	DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
 #endif /* CONFIG_HUGETLB_PAGE */
-	DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
 	DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
 	DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
 	DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
-	DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi));
 	DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
 	DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca));
 	DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
index bdfba92..6223d39 100644
--- a/arch/powerpc/kernel/btext.c
+++ b/arch/powerpc/kernel/btext.c
@@ -31,15 +31,18 @@
 static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
 static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
 
-static int g_loc_X;
-static int g_loc_Y;
-static int g_max_loc_X;
-static int g_max_loc_Y;
+#define __force_data __attribute__((__section__(".data")))
 
-static int dispDeviceRowBytes;
-static int dispDeviceDepth;
-static int dispDeviceRect[4];
-static unsigned char *dispDeviceBase, *logicalDisplayBase;
+static int g_loc_X __force_data;
+static int g_loc_Y __force_data;
+static int g_max_loc_X __force_data;
+static int g_max_loc_Y __force_data;
+
+static int dispDeviceRowBytes __force_data;
+static int dispDeviceDepth  __force_data;
+static int dispDeviceRect[4] __force_data;
+static unsigned char *dispDeviceBase __force_data;
+static unsigned char *logicalDisplayBase __force_data;
 
 unsigned long disp_BAT[2] __initdata = {0, 0};
 
@@ -47,7 +50,7 @@
 
 static unsigned char vga_font[cmapsz];
 
-int boot_text_mapped;
+int boot_text_mapped __force_data = 0;
 int force_printk_to_btext = 0;
 
 #ifdef CONFIG_PPC32
@@ -57,7 +60,7 @@
  *
  * The display is mapped to virtual address 0xD0000000, rather
  * than 1:1, because some some CHRP machines put the frame buffer
- * in the region starting at 0xC0000000 (KERNELBASE).
+ * in the region starting at 0xC0000000 (PAGE_OFFSET).
  * This mapping is temporary and will disappear as soon as the
  * setup done by MMU_Init() is applied.
  *
@@ -66,10 +69,9 @@
  * is really badly aligned, but I didn't encounter this case
  * yet.
  */
-void __init
-btext_prepare_BAT(void)
+void __init btext_prepare_BAT(void)
 {
-	unsigned long vaddr = KERNELBASE + 0x10000000;
+	unsigned long vaddr = PAGE_OFFSET + 0x10000000;
 	unsigned long addr;
 	unsigned long lowbits;
 
@@ -95,12 +97,13 @@
 }
 #endif
 
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
+
+/* This function can be used to enable the early boot text when doing
+ * OF booting or within bootx init. It must be followed by a btext_unmap()
+ * call before the logical address becomes unuseable
  */
-void __init
-btext_setup_display(int width, int height, int depth, int pitch,
-		    unsigned long address)
+void __init btext_setup_display(int width, int height, int depth, int pitch,
+				unsigned long address)
 {
 	g_loc_X = 0;
 	g_loc_Y = 0;
@@ -116,6 +119,11 @@
 	boot_text_mapped = 1;
 }
 
+void __init btext_unmap(void)
+{
+	boot_text_mapped = 0;
+}
+
 /* Here's a small text engine to use during early boot
  * or for debugging purposes
  *
@@ -127,7 +135,7 @@
  *    changes.
  */
 
-void map_boot_text(void)
+static void map_boot_text(void)
 {
 	unsigned long base, offset, size;
 	unsigned char *vbase;
@@ -175,8 +183,9 @@
 	if (prop)
 		address = *prop;
 
-	/* FIXME: Add support for PCI reg properties */
-
+	/* FIXME: Add support for PCI reg properties. Right now, only
+	 * reliable on macs
+	 */
 	if (address == 0)
 		return -EINVAL;
 
@@ -184,7 +193,6 @@
 	g_loc_Y = 0;
 	g_max_loc_X = width / 8;
 	g_max_loc_Y = height / 16;
-	logicalDisplayBase = (unsigned char *)address;
 	dispDeviceBase = (unsigned char *)address;
 	dispDeviceRowBytes = pitch;
 	dispDeviceDepth = depth;
@@ -197,14 +205,12 @@
 	return 0;
 }
 
-void __init init_boot_display(void)
+int __init btext_find_display(int allow_nonstdout)
 {
 	char *name;
 	struct device_node *np = NULL; 
 	int rc = -ENODEV;
 
-	printk("trying to initialize btext ...\n");
-
 	name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
 	if (name != NULL) {
 		np = of_find_node_by_path(name);
@@ -218,8 +224,8 @@
 	}
 	if (np)
 		rc = btext_initialize(np);
-	if (rc == 0)
-		return;
+	if (rc == 0 || !allow_nonstdout)
+		return rc;
 
 	for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
 		if (get_property(np, "linux,opened", NULL)) {
@@ -228,8 +234,9 @@
 			printk("result: %d\n", rc);
 		}
 		if (rc == 0)
-			return;
+			break;
 	}
+	return rc;
 }
 
 /* Calc the base address of a given point (x,y) */
@@ -277,44 +284,83 @@
 
 void btext_clearscreen(void)
 {
-	unsigned long *base	= (unsigned long *)calc_base(0, 0);
+	unsigned int *base	= (unsigned int *)calc_base(0, 0);
 	unsigned long width 	= ((dispDeviceRect[2] - dispDeviceRect[0]) *
-					(dispDeviceDepth >> 3)) >> 3;
+					(dispDeviceDepth >> 3)) >> 2;
 	int i,j;
 
 	for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
 	{
-		unsigned long *ptr = base;
+		unsigned int *ptr = base;
 		for(j=width; j; --j)
 			*(ptr++) = 0;
-		base += (dispDeviceRowBytes >> 3);
+		base += (dispDeviceRowBytes >> 2);
 	}
 }
 
+void btext_flushscreen(void)
+{
+	unsigned int *base	= (unsigned int *)calc_base(0, 0);
+	unsigned long width 	= ((dispDeviceRect[2] - dispDeviceRect[0]) *
+					(dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+
+	for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++)
+	{
+		unsigned int *ptr = base;
+		for(j = width; j > 0; j -= 8) {
+			__asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
+			ptr += 8;
+		}
+		base += (dispDeviceRowBytes >> 2);
+	}
+	__asm__ __volatile__ ("sync" ::: "memory");
+}
+
+void btext_flushline(void)
+{
+	unsigned int *base	= (unsigned int *)calc_base(0, g_loc_Y << 4);
+	unsigned long width 	= ((dispDeviceRect[2] - dispDeviceRect[0]) *
+					(dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+
+	for (i=0; i < 16; i++)
+	{
+		unsigned int *ptr = base;
+		for(j = width; j > 0; j -= 8) {
+			__asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
+			ptr += 8;
+		}
+		base += (dispDeviceRowBytes >> 2);
+	}
+	__asm__ __volatile__ ("sync" ::: "memory");
+}
+
+
 #ifndef NO_SCROLL
 static void scrollscreen(void)
 {
-	unsigned long *src     	= (unsigned long *)calc_base(0,16);
-	unsigned long *dst     	= (unsigned long *)calc_base(0,0);
+	unsigned int *src     	= (unsigned int *)calc_base(0,16);
+	unsigned int *dst     	= (unsigned int *)calc_base(0,0);
 	unsigned long width    	= ((dispDeviceRect[2] - dispDeviceRect[0]) *
-				   (dispDeviceDepth >> 3)) >> 3;
+				   (dispDeviceDepth >> 3)) >> 2;
 	int i,j;
 
 	for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
 	{
-		unsigned long *src_ptr = src;
-		unsigned long *dst_ptr = dst;
+		unsigned int *src_ptr = src;
+		unsigned int *dst_ptr = dst;
 		for(j=width; j; --j)
 			*(dst_ptr++) = *(src_ptr++);
-		src += (dispDeviceRowBytes >> 3);
-		dst += (dispDeviceRowBytes >> 3);
+		src += (dispDeviceRowBytes >> 2);
+		dst += (dispDeviceRowBytes >> 2);
 	}
 	for (i=0; i<16; i++)
 	{
-		unsigned long *dst_ptr = dst;
+		unsigned int *dst_ptr = dst;
 		for(j=width; j; --j)
 			*(dst_ptr++) = 0;
-		dst += (dispDeviceRowBytes >> 3);
+		dst += (dispDeviceRowBytes >> 2);
 	}
 }
 #endif /* ndef NO_SCROLL */
@@ -377,6 +423,14 @@
 		btext_drawchar(*c++);
 }
 
+void btext_drawtext(const char *c, unsigned int len)
+{
+	if (!boot_text_mapped)
+		return;
+	while (len--)
+		btext_drawchar(*c++);
+}
+
 void btext_drawhex(unsigned long v)
 {
 	char *hex_table = "0123456789abcdef";
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 1d85ced..43c74a6 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -78,10 +78,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/power3",
-		.oprofile_model		= &op_model_rs64,
-#endif
+		.oprofile_type		= RS64,
 	},
 	{	/* Power3+ */
 		.pvr_mask		= 0xffff0000,
@@ -93,10 +91,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/power3",
-		.oprofile_model		= &op_model_rs64,
-#endif
+		.oprofile_type		= RS64,
 	},
 	{	/* Northstar */
 		.pvr_mask		= 0xffff0000,
@@ -108,10 +104,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/rs64",
-		.oprofile_model		= &op_model_rs64,
-#endif
+		.oprofile_type		= RS64,
 	},
 	{	/* Pulsar */
 		.pvr_mask		= 0xffff0000,
@@ -123,10 +117,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/rs64",
-		.oprofile_model		= &op_model_rs64,
-#endif
+		.oprofile_type		= RS64,
 	},
 	{	/* I-star */
 		.pvr_mask		= 0xffff0000,
@@ -138,10 +130,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/rs64",
-		.oprofile_model		= &op_model_rs64,
-#endif
+		.oprofile_type		= RS64,
 	},
 	{	/* S-star */
 		.pvr_mask		= 0xffff0000,
@@ -153,10 +143,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/rs64",
-		.oprofile_model		= &op_model_rs64,
-#endif
+		.oprofile_type		= RS64,
 	},
 	{	/* Power4 */
 		.pvr_mask		= 0xffff0000,
@@ -168,10 +156,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/power4",
-		.oprofile_model		= &op_model_rs64,
-#endif
+		.oprofile_type		= POWER4,
 	},
 	{	/* Power4+ */
 		.pvr_mask		= 0xffff0000,
@@ -183,10 +169,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/power4",
-		.oprofile_model		= &op_model_power4,
-#endif
+		.oprofile_type		= POWER4,
 	},
 	{	/* PPC970 */
 		.pvr_mask		= 0xffff0000,
@@ -199,10 +183,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/970",
-		.oprofile_model		= &op_model_power4,
-#endif
+		.oprofile_type		= POWER4,
 	},
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_PPC64) || defined(CONFIG_POWER4)
@@ -221,10 +203,8 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/970",
-		.oprofile_model		= &op_model_power4,
-#endif
+		.oprofile_type		= POWER4,
 	},
 #endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */
 #ifdef CONFIG_PPC64
@@ -238,10 +218,8 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.cpu_setup		= __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/970",
-		.oprofile_model		= &op_model_power4,
-#endif
+		.oprofile_type		= POWER4,
 	},
 	{	/* Power5 GR */
 		.pvr_mask		= 0xffff0000,
@@ -253,27 +231,23 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
 		.oprofile_cpu_type	= "ppc64/power5",
-		.oprofile_model		= &op_model_power4,
-#endif
+		.oprofile_type		= POWER4,
 	},
 	{	/* Power5 GS */
 		.pvr_mask		= 0xffff0000,
 		.pvr_value		= 0x003b0000,
-		.cpu_name		= "POWER5 (gs)",
+		.cpu_name		= "POWER5+ (gs)",
 		.cpu_features		= CPU_FTRS_POWER5,
 		.cpu_user_features	= COMMON_USER_POWER5_PLUS,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
-		.oprofile_cpu_type	= "ppc64/power5",
-		.oprofile_model		= &op_model_power4,
-#endif
+		.oprofile_cpu_type	= "ppc64/power5+",
+		.oprofile_type		= POWER4,
 	},
-	{	/* BE DD1.x */
+	{	/* Cell Broadband Engine */
 		.pvr_mask		= 0xffff0000,
 		.pvr_value		= 0x00700000,
 		.cpu_name		= "Cell Broadband Engine",
@@ -545,7 +519,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7450 2.1 */
 		.pvr_mask		= 0xffffffff,
@@ -556,7 +532,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7450 2.3 and newer */
 		.pvr_mask		= 0xffff0000,
@@ -567,7 +545,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7455 rev 1.x */
 		.pvr_mask		= 0xffffff00,
@@ -578,7 +558,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7455 rev 2.0 */
 		.pvr_mask		= 0xffffffff,
@@ -589,7 +571,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7455 others */
 		.pvr_mask		= 0xffff0000,
@@ -600,7 +584,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7447/7457 Rev 1.0 */
 		.pvr_mask		= 0xffffffff,
@@ -611,7 +597,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7447/7457 Rev 1.1 */
 		.pvr_mask		= 0xffffffff,
@@ -622,7 +610,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7447/7457 Rev 1.2 and later */
 		.pvr_mask		= 0xffff0000,
@@ -633,7 +623,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7447A */
 		.pvr_mask		= 0xffff0000,
@@ -644,7 +636,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 7448 */
 		.pvr_mask		= 0xffff0000,
@@ -655,7 +649,9 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
-		.cpu_setup		= __setup_cpu_745x
+		.cpu_setup		= __setup_cpu_745x,
+		.oprofile_cpu_type      = "ppc/7450",
+		.oprofile_type		= G4,
 	},
 	{	/* 82xx (8240, 8245, 8260 are all 603e cores) */
 		.pvr_mask		= 0x7fff0000,
@@ -979,6 +975,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
+		.oprofile_cpu_type	= "ppc/e500",
+		.oprofile_type		= BOOKE,
 	},
 	{	/* e500v2 */
 		.pvr_mask		= 0xffff0000,
@@ -992,6 +990,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
+		.oprofile_cpu_type	= "ppc/e500",
+		.oprofile_type		= BOOKE,
 	},
 #endif
 #if !CLASSIC_PPC
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
new file mode 100644
index 0000000..4681155
--- /dev/null
+++ b/arch/powerpc/kernel/crash.c
@@ -0,0 +1,264 @@
+/*
+ * Architecture specific (PPC64) functions for kexec based crash dumps.
+ *
+ * Copyright (C) 2005, IBM Corp.
+ *
+ * Created by: Haren Myneni
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/reboot.h>
+#include <linux/kexec.h>
+#include <linux/bootmem.h>
+#include <linux/crash_dump.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/kdump.h>
+#include <asm/lmb.h>
+#include <asm/firmware.h>
+
+#ifdef DEBUG
+#include <asm/udbg.h>
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/* This keeps a track of which one is crashing cpu. */
+int crashing_cpu = -1;
+
+static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
+							       size_t data_len)
+{
+	struct elf_note note;
+
+	note.n_namesz = strlen(name) + 1;
+	note.n_descsz = data_len;
+	note.n_type   = type;
+	memcpy(buf, &note, sizeof(note));
+	buf += (sizeof(note) +3)/4;
+	memcpy(buf, name, note.n_namesz);
+	buf += (note.n_namesz + 3)/4;
+	memcpy(buf, data, note.n_descsz);
+	buf += (note.n_descsz + 3)/4;
+
+	return buf;
+}
+
+static void final_note(u32 *buf)
+{
+	struct elf_note note;
+
+	note.n_namesz = 0;
+	note.n_descsz = 0;
+	note.n_type   = 0;
+	memcpy(buf, &note, sizeof(note));
+}
+
+static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
+{
+	struct elf_prstatus prstatus;
+	u32 *buf;
+
+	if ((cpu < 0) || (cpu >= NR_CPUS))
+		return;
+
+	/* Using ELF notes here is opportunistic.
+	 * I need a well defined structure format
+	 * for the data I pass, and I need tags
+	 * on the data to indicate what information I have
+	 * squirrelled away.  ELF notes happen to provide
+	 * all of that that no need to invent something new.
+	 */
+	buf = &crash_notes[cpu][0];
+	memset(&prstatus, 0, sizeof(prstatus));
+	prstatus.pr_pid = current->pid;
+	elf_core_copy_regs(&prstatus.pr_reg, regs);
+	buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
+			sizeof(prstatus));
+	final_note(buf);
+}
+
+/* FIXME Merge this with xmon_save_regs ?? */
+static inline void crash_get_current_regs(struct pt_regs *regs)
+{
+	unsigned long tmp1, tmp2;
+
+	__asm__ __volatile__ (
+		"std    0,0(%2)\n"
+		"std    1,8(%2)\n"
+		"std    2,16(%2)\n"
+		"std    3,24(%2)\n"
+		"std    4,32(%2)\n"
+		"std    5,40(%2)\n"
+		"std    6,48(%2)\n"
+		"std    7,56(%2)\n"
+		"std    8,64(%2)\n"
+		"std    9,72(%2)\n"
+		"std    10,80(%2)\n"
+		"std    11,88(%2)\n"
+		"std    12,96(%2)\n"
+		"std    13,104(%2)\n"
+		"std    14,112(%2)\n"
+		"std    15,120(%2)\n"
+		"std    16,128(%2)\n"
+		"std    17,136(%2)\n"
+		"std    18,144(%2)\n"
+		"std    19,152(%2)\n"
+		"std    20,160(%2)\n"
+		"std    21,168(%2)\n"
+		"std    22,176(%2)\n"
+		"std    23,184(%2)\n"
+		"std    24,192(%2)\n"
+		"std    25,200(%2)\n"
+		"std    26,208(%2)\n"
+		"std    27,216(%2)\n"
+		"std    28,224(%2)\n"
+		"std    29,232(%2)\n"
+		"std    30,240(%2)\n"
+		"std    31,248(%2)\n"
+		"mfmsr  %0\n"
+		"std    %0, 264(%2)\n"
+		"mfctr  %0\n"
+		"std    %0, 280(%2)\n"
+		"mflr   %0\n"
+		"std    %0, 288(%2)\n"
+		"bl     1f\n"
+	"1:      mflr   %1\n"
+		"std    %1, 256(%2)\n"
+		"mtlr   %0\n"
+		"mfxer  %0\n"
+		"std    %0, 296(%2)\n"
+		: "=&r" (tmp1), "=&r" (tmp2)
+		: "b" (regs));
+}
+
+/* We may have saved_regs from where the error came from
+ * or it is NULL if via a direct panic().
+ */
+static void crash_save_self(struct pt_regs *saved_regs)
+{
+	struct pt_regs regs;
+	int cpu;
+
+	cpu = smp_processor_id();
+	if (saved_regs)
+		memcpy(&regs, saved_regs, sizeof(regs));
+	else
+		crash_get_current_regs(&regs);
+	crash_save_this_cpu(&regs, cpu);
+}
+
+#ifdef CONFIG_SMP
+static atomic_t waiting_for_crash_ipi;
+
+void crash_ipi_callback(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpu == crashing_cpu)
+		return;
+
+	if (!cpu_online(cpu))
+		return;
+
+	if (ppc_md.kexec_cpu_down)
+		ppc_md.kexec_cpu_down(1, 1);
+
+	local_irq_disable();
+
+	crash_save_this_cpu(regs, cpu);
+	atomic_dec(&waiting_for_crash_ipi);
+	kexec_smp_wait();
+	/* NOTREACHED */
+}
+
+static void crash_kexec_prepare_cpus(void)
+{
+	unsigned int msecs;
+
+	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+
+	crash_send_ipi(crash_ipi_callback);
+	smp_wmb();
+
+	/*
+	 * FIXME: Until we will have the way to stop other CPUSs reliabally,
+	 * the crash CPU will send an IPI and wait for other CPUs to
+	 * respond. If not, proceed the kexec boot even though we failed to
+	 * capture other CPU states.
+	 */
+	msecs = 1000000;
+	while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) {
+		barrier();
+		mdelay(1);
+	}
+
+	/* Would it be better to replace the trap vector here? */
+
+	/*
+	 * FIXME: In case if we do not get all CPUs, one possibility: ask the
+	 * user to do soft reset such that we get all.
+	 * IPI handler is already set by the panic cpu initially. Therefore,
+	 * all cpus could invoke this handler from die() and the panic CPU
+	 * will call machine_kexec() directly from this handler to do
+	 * kexec boot.
+	 */
+	if (atomic_read(&waiting_for_crash_ipi))
+		printk(KERN_ALERT "done waiting: %d cpus not responding\n",
+			atomic_read(&waiting_for_crash_ipi));
+	/* Leave the IPI callback set */
+}
+#else
+static void crash_kexec_prepare_cpus(void)
+{
+	/*
+	 * move the secondarys to us so that we can copy
+	 * the new kernel 0-0x100 safely
+	 *
+	 * do this if kexec in setup.c ?
+	 */
+	smp_release_cpus();
+}
+
+#endif
+
+void default_machine_crash_shutdown(struct pt_regs *regs)
+{
+	/*
+	 * This function is only called after the system
+	 * has paniced or is otherwise in a critical state.
+	 * The minimum amount of code to allow a kexec'd kernel
+	 * to run successfully needs to happen here.
+	 *
+	 * In practice this means stopping other cpus in
+	 * an SMP system.
+	 * The kernel is broken so disable interrupts.
+	 */
+	local_irq_disable();
+
+	if (ppc_md.kexec_cpu_down)
+		ppc_md.kexec_cpu_down(1, 0);
+
+	/*
+	 * Make a note of crashing cpu. Will be used in machine_kexec
+	 * such that another IPI will not be sent.
+	 */
+	crashing_cpu = smp_processor_id();
+	crash_kexec_prepare_cpus();
+	crash_save_self(regs);
+}
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
new file mode 100644
index 0000000..87effa3
--- /dev/null
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -0,0 +1,109 @@
+/*
+ * Routines for doing kexec-based kdump.
+ *
+ * Copyright (C) 2005, IBM Corp.
+ *
+ * Created by: Michael Ellerman
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/crash_dump.h>
+#include <linux/bootmem.h>
+#include <asm/kdump.h>
+#include <asm/lmb.h>
+#include <asm/firmware.h>
+#include <asm/uaccess.h>
+
+#ifdef DEBUG
+#include <asm/udbg.h>
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static void __init create_trampoline(unsigned long addr)
+{
+	/* The maximum range of a single instruction branch, is the current
+	 * instruction's address + (32 MB - 4) bytes. For the trampoline we
+	 * need to branch to current address + 32 MB. So we insert a nop at
+	 * the trampoline address, then the next instruction (+ 4 bytes)
+	 * does a branch to (32 MB - 4). The net effect is that when we
+	 * branch to "addr" we jump to ("addr" + 32 MB). Although it requires
+	 * two instructions it doesn't require any registers.
+	 */
+	create_instruction(addr, 0x60000000); /* nop */
+	create_branch(addr + 4, addr + PHYSICAL_START, 0);
+}
+
+void __init kdump_setup(void)
+{
+	unsigned long i;
+
+	DBG(" -> kdump_setup()\n");
+
+	for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) {
+		create_trampoline(i);
+	}
+
+	create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START);
+	create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START);
+
+	DBG(" <- kdump_setup()\n");
+}
+
+static int __init parse_elfcorehdr(char *p)
+{
+	if (p)
+		elfcorehdr_addr = memparse(p, &p);
+
+	return 0;
+}
+__setup("elfcorehdr=", parse_elfcorehdr);
+
+static int __init parse_savemaxmem(char *p)
+{
+	if (p)
+		saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
+
+	return 0;
+}
+__setup("savemaxmem=", parse_savemaxmem);
+
+/*
+ * copy_oldmem_page - copy one page from "oldmem"
+ * @pfn: page frame number to be copied
+ * @buf: target memory address for the copy; this can be in kernel address
+ *      space or user address space (see @userbuf)
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page (based on pfn) to begin the copy
+ * @userbuf: if set, @buf is in user address space, use copy_to_user(),
+ *      otherwise @buf is in kernel address space, use memcpy().
+ *
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+			size_t csize, unsigned long offset, int userbuf)
+{
+	void  *vaddr;
+
+	if (!csize)
+		return 0;
+
+	vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0);
+
+	if (userbuf) {
+		if (copy_to_user((char __user *)buf, (vaddr + offset), csize)) {
+			iounmap(vaddr);
+			return -EFAULT;
+		}
+	} else
+		memcpy(buf, (vaddr + offset), csize);
+
+	iounmap(vaddr);
+	return csize;
+}
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c
index 7c34196..36aaa76 100644
--- a/arch/powerpc/kernel/dma_64.c
+++ b/arch/powerpc/kernel/dma_64.c
@@ -10,6 +10,7 @@
 /* Include the busses we support */
 #include <linux/pci.h>
 #include <asm/vio.h>
+#include <asm/ibmebus.h>
 #include <asm/scatterlist.h>
 #include <asm/bug.h>
 
@@ -23,6 +24,10 @@
 	if (dev->bus == &vio_bus_type)
 		return &vio_dma_ops;
 #endif
+#ifdef CONFIG_IBMEBUS
+	if (dev->bus == &ibmebus_bus_type)
+		return &ibmebus_dma_ops;
+#endif
 	return NULL;
 }
 
@@ -47,6 +52,10 @@
 	if (dev->bus == &vio_bus_type)
 		return -EIO;
 #endif /* CONFIG_IBMVIO */
+#ifdef CONFIG_IBMEBUS
+	if (dev->bus == &ibmebus_bus_type)
+		return -EIO;
+#endif
 	BUG();
 	return 0;
 }
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 2e99ae4..036b71d 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -200,8 +200,6 @@
 	bl	do_show_syscall
 #endif /* SHOW_SYSCALLS */
 	rlwinm	r10,r1,0,0,(31-THREAD_SHIFT)	/* current_thread_info() */
-	li	r11,0
-	stb	r11,TI_SC_NOERR(r10)
 	lwz	r11,TI_FLAGS(r10)
 	andi.	r11,r11,_TIF_SYSCALL_T_OR_A
 	bne-	syscall_dotrace
@@ -222,25 +220,21 @@
 	bl	do_show_syscall_exit
 #endif
 	mr	r6,r3
-	li	r11,-_LAST_ERRNO
-	cmplw	0,r3,r11
 	rlwinm	r12,r1,0,0,(31-THREAD_SHIFT)	/* current_thread_info() */
-	blt+	30f
-	lbz	r11,TI_SC_NOERR(r12)
-	cmpwi	r11,0
-	bne	30f
-	neg	r3,r3
-	lwz	r10,_CCR(r1)	/* Set SO bit in CR */
-	oris	r10,r10,0x1000
-	stw	r10,_CCR(r1)
-
 	/* disable interrupts so current_thread_info()->flags can't change */
-30:	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
+	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
 	SYNC
 	MTMSRD(r10)
 	lwz	r9,TI_FLAGS(r12)
-	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+	li	r8,-_LAST_ERRNO
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
 	bne-	syscall_exit_work
+	cmplw	0,r3,r8
+	blt+	syscall_exit_cont
+	lwz	r11,_CCR(r1)			/* Load CR */
+	neg	r3,r3
+	oris	r11,r11,0x1000	/* Set SO bit in CR */
+	stw	r11,_CCR(r1)
 syscall_exit_cont:
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 	/* If the process has its own DBCR0 value, load it up.  The single
@@ -292,46 +286,113 @@
 	b	syscall_dotrace_cont
 
 syscall_exit_work:
-	stw	r6,RESULT(r1)	/* Save result */
+	andi.	r0,r9,_TIF_RESTOREALL
+	bne-	2f
+	cmplw	0,r3,r8
+	blt+	1f
+	andi.	r0,r9,_TIF_NOERROR
+	bne-	1f
+	lwz	r11,_CCR(r1)			/* Load CR */
+	neg	r3,r3
+	oris	r11,r11,0x1000	/* Set SO bit in CR */
+	stw	r11,_CCR(r1)
+
+1:	stw	r6,RESULT(r1)	/* Save result */
 	stw	r3,GPR3(r1)	/* Update return value */
-	andi.	r0,r9,_TIF_SYSCALL_T_OR_A
-	beq	5f
-	ori	r10,r10,MSR_EE
-	SYNC
-	MTMSRD(r10)		/* re-enable interrupts */
+2:	andi.	r0,r9,(_TIF_PERSYSCALL_MASK)
+	beq	4f
+
+	/* Clear per-syscall TIF flags if any are set, but _leave_
+	_TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+	yet.  */
+
+	li	r11,_TIF_PERSYSCALL_MASK
+	addi	r12,r12,TI_FLAGS
+3:	lwarx	r8,0,r12
+	andc	r8,r8,r11
+#ifdef CONFIG_IBM405_ERR77
+	dcbt	0,r12
+#endif
+	stwcx.	r8,0,r12
+	bne-	3b
+	subi	r12,r12,TI_FLAGS
+	
+4:	/* Anything which requires enabling interrupts? */
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+	beq	7f
+
+	/* Save NVGPRS if they're not saved already */
 	lwz	r4,_TRAP(r1)
 	andi.	r4,r4,1
-	beq	4f
+	beq	5f
 	SAVE_NVGPRS(r1)
 	li	r4,0xc00
 	stw	r4,_TRAP(r1)
-4:
+
+	/* Re-enable interrupts */
+5:	ori	r10,r10,MSR_EE
+	SYNC
+	MTMSRD(r10)
+
+	andi.	r0,r9,_TIF_SAVE_NVGPRS
+	bne	save_user_nvgprs
+
+save_user_nvgprs_cont:
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+	beq	7f
+
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	do_syscall_trace_leave
 	REST_NVGPRS(r1)
-2:
-	lwz	r3,GPR3(r1)
+
+6:	lwz	r3,GPR3(r1)
 	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
 	SYNC
 	MTMSRD(r10)		/* disable interrupts again */
 	rlwinm	r12,r1,0,0,(31-THREAD_SHIFT)	/* current_thread_info() */
 	lwz	r9,TI_FLAGS(r12)
-5:
+7:
 	andi.	r0,r9,_TIF_NEED_RESCHED
-	bne	1f
+	bne	8f
 	lwz	r5,_MSR(r1)
 	andi.	r5,r5,MSR_PR
-	beq	syscall_exit_cont
+	beq	ret_from_except
 	andi.	r0,r9,_TIF_SIGPENDING
-	beq	syscall_exit_cont
+	beq	ret_from_except
 	b	do_user_signal
-1:
+8:
 	ori	r10,r10,MSR_EE
 	SYNC
 	MTMSRD(r10)		/* re-enable interrupts */
 	bl	schedule
-	b	2b
+	b	6b
 
+save_user_nvgprs:
+	lwz	r8,TI_SIGFRAME(r12)
+
+.macro savewords start, end
+  1:	stw \start,4*(\start)(r8)
+	.section __ex_table,"a"
+	.align	2
+	.long	1b,save_user_nvgprs_fault
+	.previous
+	.if \end - \start
+	savewords "(\start+1)",\end
+	.endif
+.endm	
+	savewords 14,31
+	b	save_user_nvgprs_cont
+
+	
+save_user_nvgprs_fault:
+	li	r3,11		/* SIGSEGV */
+	lwz	r4,TI_TASK(r12)
+	bl	force_sigsegv
+
+	rlwinm	r12,r1,0,0,(31-THREAD_SHIFT)	/* current_thread_info() */
+	lwz	r9,TI_FLAGS(r12)
+	b	save_user_nvgprs_cont
+	
 #ifdef SHOW_SYSCALLS
 do_show_syscall:
 #ifdef SHOW_SYSCALLS_TASK
@@ -401,28 +462,10 @@
 #endif /* SHOW_SYSCALLS */
 
 /*
- * The sigsuspend and rt_sigsuspend system calls can call do_signal
- * and thus put the process into the stopped state where we might
- * want to examine its user state with ptrace.  Therefore we need
- * to save all the nonvolatile registers (r13 - r31) before calling
- * the C code.
+ * The fork/clone functions need to copy the full register set into
+ * the child process. Therefore we need to save all the nonvolatile
+ * registers (r13 - r31) before calling the C code.
  */
-	.globl	ppc_sigsuspend
-ppc_sigsuspend:
-	SAVE_NVGPRS(r1)
-	lwz	r0,_TRAP(r1)
-	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
-	stw	r0,_TRAP(r1)		/* register set saved */
-	b	sys_sigsuspend
-
-	.globl	ppc_rt_sigsuspend
-ppc_rt_sigsuspend:
-	SAVE_NVGPRS(r1)
-	lwz	r0,_TRAP(r1)
-	rlwinm	r0,r0,0,0,30
-	stw	r0,_TRAP(r1)
-	b	sys_rt_sigsuspend
-
 	.globl	ppc_fork
 ppc_fork:
 	SAVE_NVGPRS(r1)
@@ -447,14 +490,6 @@
 	stw	r0,_TRAP(r1)		/* register set saved */
 	b	sys_clone
 
-	.globl	ppc_swapcontext
-ppc_swapcontext:
-	SAVE_NVGPRS(r1)
-	lwz	r0,_TRAP(r1)
-	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
-	stw	r0,_TRAP(r1)		/* register set saved */
-	b	sys_swapcontext
-
 /*
  * Top-level page fault handling.
  * This is in assembler because if do_page_fault tells us that
@@ -626,16 +661,6 @@
 	.long	ret_from_except
 #endif
 
-	.globl	sigreturn_exit
-sigreturn_exit:
-	subi	r1,r3,STACK_FRAME_OVERHEAD
-	rlwinm	r12,r1,0,0,(31-THREAD_SHIFT)	/* current_thread_info() */
-	lwz	r9,TI_FLAGS(r12)
-	andi.	r0,r9,_TIF_SYSCALL_T_OR_A
-	beq+	ret_from_except_full
-	bl	do_syscall_trace_leave
-	/* fall through */
-
 	.globl	ret_from_except_full
 ret_from_except_full:
 	REST_NVGPRS(r1)
@@ -658,7 +683,7 @@
 	/* Check current_thread_info()->flags */
 	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
 	lwz	r9,TI_FLAGS(r9)
-	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
 	bne	do_work
 
 restore_user:
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index bce33a3..aacebb3 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -113,9 +113,7 @@
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 #endif
 	clrrdi	r11,r1,THREAD_SHIFT
-	li	r12,0
 	ld	r10,TI_FLAGS(r11)
-	stb	r12,TI_SC_NOERR(r11)
 	andi.	r11,r10,_TIF_SYSCALL_T_OR_A
 	bne-	syscall_dotrace
 syscall_dotrace_cont:
@@ -144,24 +142,12 @@
 	bctrl			/* Call handler */
 
 syscall_exit:
-#ifdef SHOW_SYSCALLS
-	std	r3,GPR3(r1)
-	bl	.do_show_syscall_exit
-	ld	r3,GPR3(r1)
-#endif
 	std	r3,RESULT(r1)
-	ld	r5,_CCR(r1)
-	li	r10,-_LAST_ERRNO
-	cmpld	r3,r10
+#ifdef SHOW_SYSCALLS
+	bl	.do_show_syscall_exit
+	ld	r3,RESULT(r1)
+#endif
 	clrrdi	r12,r1,THREAD_SHIFT
-	bge-	syscall_error
-syscall_error_cont:
-
-	/* check for syscall tracing or audit */
-	ld	r9,TI_FLAGS(r12)
-	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
-	bne-	syscall_exit_trace
-syscall_exit_trace_cont:
 
 	/* disable interrupts so current_thread_info()->flags can't change,
 	   and so that we don't get interrupted after loading SRR0/1. */
@@ -173,8 +159,13 @@
 	rotldi	r10,r10,16
 	mtmsrd	r10,1
 	ld	r9,TI_FLAGS(r12)
-	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+	li	r11,-_LAST_ERRNO
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR)
 	bne-	syscall_exit_work
+	cmpld	r3,r11
+	ld	r5,_CCR(r1)
+	bge-	syscall_error
+syscall_error_cont:
 	ld	r7,_NIP(r1)
 	stdcx.	r0,0,r1			/* to clear the reservation */
 	andi.	r6,r8,MSR_PR
@@ -193,21 +184,12 @@
 	rfid
 	b	.	/* prevent speculative execution */
 
-syscall_enosys:
-	li	r3,-ENOSYS
-	std	r3,RESULT(r1)
-	clrrdi	r12,r1,THREAD_SHIFT
-	ld	r5,_CCR(r1)
-
-syscall_error:
-	lbz	r11,TI_SC_NOERR(r12)
-	cmpwi	0,r11,0
-	bne-	syscall_error_cont
-	neg	r3,r3
+syscall_error:	
 	oris	r5,r5,0x1000	/* Set SO bit in CR */
+	neg	r3,r3
 	std	r5,_CCR(r1)
 	b	syscall_error_cont
-        
+	
 /* Traced system call support */
 syscall_dotrace:
 	bl	.save_nvgprs
@@ -225,21 +207,69 @@
 	ld	r10,TI_FLAGS(r10)
 	b	syscall_dotrace_cont
 
-syscall_exit_trace:
-	std	r3,GPR3(r1)
-	bl	.save_nvgprs
+syscall_enosys:
+	li	r3,-ENOSYS
+	b	syscall_exit
+	
+syscall_exit_work:
+	/* If TIF_RESTOREALL is set, don't scribble on either r3 or ccr.
+	 If TIF_NOERROR is set, just save r3 as it is. */
+
+	andi.	r0,r9,_TIF_RESTOREALL
+	bne-	2f
+	cmpld	r3,r11		/* r10 is -LAST_ERRNO */
+	blt+	1f
+	andi.	r0,r9,_TIF_NOERROR
+	bne-	1f
+	ld	r5,_CCR(r1)
+	neg	r3,r3
+	oris	r5,r5,0x1000	/* Set SO bit in CR */
+	std	r5,_CCR(r1)
+1:	std	r3,GPR3(r1)
+2:	andi.	r0,r9,(_TIF_PERSYSCALL_MASK)
+	beq	4f
+
+	/* Clear per-syscall TIF flags if any are set, but _leave_
+	_TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+	yet.  */
+
+	li	r11,_TIF_PERSYSCALL_MASK
+	addi	r12,r12,TI_FLAGS
+3:	ldarx	r10,0,r12
+	andc	r10,r10,r11
+	stdcx.	r10,0,r12
+	bne-	3b
+	subi	r12,r12,TI_FLAGS
+	
+4:	bl	.save_nvgprs
+	/* Anything else left to do? */
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+	beq	.ret_from_except_lite
+
+	/* Re-enable interrupts */
+	mfmsr	r10
+	ori	r10,r10,MSR_EE
+	mtmsrd	r10,1
+
+	andi.	r0,r9,_TIF_SAVE_NVGPRS
+	bne	save_user_nvgprs
+
+	/* If tracing, re-enable interrupts and do it */
+save_user_nvgprs_cont:	
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+	beq	5f
+	
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	.do_syscall_trace_leave
 	REST_NVGPRS(r1)
-	ld	r3,GPR3(r1)
-	ld	r5,_CCR(r1)
 	clrrdi	r12,r1,THREAD_SHIFT
-	b	syscall_exit_trace_cont
 
-/* Stuff to do on exit from a system call. */
-syscall_exit_work:
-	std	r3,GPR3(r1)
-	std	r5,_CCR(r1)
+	/* Disable interrupts again and handle other work if any */
+5:	mfmsr	r10
+	rldicl	r10,r10,48,1
+	rotldi	r10,r10,16
+	mtmsrd	r10,1
+
 	b	.ret_from_except_lite
 
 /* Save non-volatile GPRs, if not already saved. */
@@ -252,6 +282,52 @@
 	std	r0,_TRAP(r1)
 	blr
 
+
+save_user_nvgprs:
+	ld	r10,TI_SIGFRAME(r12)
+	andi.	r0,r9,_TIF_32BIT
+	beq-	save_user_nvgprs_64
+
+	/* 32-bit save to userspace */
+
+.macro savewords start, end
+  1:	stw \start,4*(\start)(r10)
+	.section __ex_table,"a"
+	.align	3
+	.llong	1b,save_user_nvgprs_fault
+	.previous
+	.if \end - \start
+	savewords "(\start+1)",\end
+	.endif
+.endm	
+	savewords 14,31
+	b	save_user_nvgprs_cont
+
+save_user_nvgprs_64:
+	/* 64-bit save to userspace */
+
+.macro savelongs start, end
+  1:	std \start,8*(\start)(r10)
+	.section __ex_table,"a"
+	.align	3
+	.llong	1b,save_user_nvgprs_fault
+	.previous
+	.if \end - \start
+	savelongs "(\start+1)",\end
+	.endif
+.endm	
+	savelongs 14,31
+	b	save_user_nvgprs_cont
+
+save_user_nvgprs_fault:
+	li	r3,11		/* SIGSEGV */
+	ld	r4,TI_TASK(r12)
+	bl	.force_sigsegv
+
+	clrrdi	r12,r1,THREAD_SHIFT
+	ld	r9,TI_FLAGS(r12)
+	b	save_user_nvgprs_cont
+	
 /*
  * The sigsuspend and rt_sigsuspend system calls can call do_signal
  * and thus put the process into the stopped state where we might
@@ -260,35 +336,6 @@
  * the C code.  Similarly, fork, vfork and clone need the full
  * register state on the stack so that it can be copied to the child.
  */
-_GLOBAL(ppc32_sigsuspend)
-	bl	.save_nvgprs
-	bl	.compat_sys_sigsuspend
-	b	70f
-
-_GLOBAL(ppc64_rt_sigsuspend)
-	bl	.save_nvgprs
-	bl	.sys_rt_sigsuspend
-	b	70f
-
-_GLOBAL(ppc32_rt_sigsuspend)
-	bl	.save_nvgprs
-	bl	.compat_sys_rt_sigsuspend
-70:	cmpdi	0,r3,0
-	/* If it returned an error, we need to return via syscall_exit to set
-	   the SO bit in cr0 and potentially stop for ptrace. */
-	bne	syscall_exit
-	/* If sigsuspend() returns zero, we are going into a signal handler. We
-	   may need to call audit_syscall_exit() to mark the exit from sigsuspend() */
-#ifdef CONFIG_AUDITSYSCALL
-	ld	r3,PACACURRENT(r13)
-	ld	r4,AUDITCONTEXT(r3)
-	cmpdi	0,r4,0
-	beq	.ret_from_except	/* No audit_context: Leave immediately. */
-	li	r4, 2			/* AUDITSC_FAILURE */
-	li	r5,-4			/* It's always -EINTR */
-	bl	.audit_syscall_exit
-#endif
-	b	.ret_from_except
 
 _GLOBAL(ppc_fork)
 	bl	.save_nvgprs
@@ -305,37 +352,6 @@
 	bl	.sys_clone
 	b	syscall_exit
 
-_GLOBAL(ppc32_swapcontext)
-	bl	.save_nvgprs
-	bl	.compat_sys_swapcontext
-	b	80f
-	
-_GLOBAL(ppc64_swapcontext)
-	bl	.save_nvgprs
-	bl	.sys_swapcontext
-	b	80f
-
-_GLOBAL(ppc32_sigreturn)
-	bl	.compat_sys_sigreturn
-	b	80f
-
-_GLOBAL(ppc32_rt_sigreturn)
-	bl	.compat_sys_rt_sigreturn
-	b	80f
-
-_GLOBAL(ppc64_rt_sigreturn)
-	bl	.sys_rt_sigreturn
-
-80:	cmpdi	0,r3,0
-	blt	syscall_exit
-	clrrdi	r4,r1,THREAD_SHIFT
-	ld	r4,TI_FLAGS(r4)
-	andi.	r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
-	beq+	81f
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.do_syscall_trace_leave
-81:	b	.ret_from_except
-
 _GLOBAL(ret_from_fork)
 	bl	.schedule_tail
 	REST_NVGPRS(r1)
@@ -674,7 +690,7 @@
 
 	/* Setup our real return addr */	
 	SET_REG_TO_LABEL(r4,.rtas_return_loc)
-	SET_REG_TO_CONST(r9,KERNELBASE)
+	SET_REG_TO_CONST(r9,PAGE_OFFSET)
 	sub	r4,r4,r9
        	mtlr	r4
 
@@ -702,7 +718,7 @@
 _STATIC(rtas_return_loc)
 	/* relocation is off at this point */
 	mfspr	r4,SPRN_SPRG3	        /* Get PACA */
-	SET_REG_TO_CONST(r5, KERNELBASE)
+	SET_REG_TO_CONST(r5, PAGE_OFFSET)
         sub     r4,r4,r5                /* RELOC the PACA base pointer */
 
 	mfmsr   r6
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index ccdf947..03b25f9 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -120,10 +120,25 @@
  * because OF may have I/O devices mapped into that area
  * (particularly on CHRP).
  */
+#ifdef CONFIG_PPC_MULTIPLATFORM
 	cmpwi	0,r5,0
 	beq	1f
 	bl	prom_init
 	trap
+#endif
+
+/*
+ * Check for BootX signature when supporting PowerMac and branch to
+ * appropriate trampoline if it's present
+ */
+#ifdef CONFIG_PPC_PMAC
+1:	lis	r31,0x426f
+	ori	r31,r31,0x6f58
+	cmpw	0,r3,r31
+	bne	1f
+	bl	bootx_init
+	trap
+#endif /* CONFIG_PPC_PMAC */
 
 1:	mr	r31,r3			/* save parameters */
 	mr	r30,r4
@@ -153,6 +168,9 @@
 	bl	flush_tlbs
 
 	bl	initial_bats
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+	bl	setup_disp_bat
+#endif
 
 /*
  * Call setup_cpu for CPU 0 and initialize 6xx Idle
@@ -450,16 +468,11 @@
  * by executing an altivec instruction.
  */
 	. = 0xf00
-	b	Trap_0f
+	b	PerformanceMonitor
 
 	. = 0xf20
 	b	AltiVecUnavailable
 
-Trap_0f:
-	EXCEPTION_PROLOG
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	EXC_XFER_EE(0xf00, unknown_exception)
-
 /*
  * Handle TLB miss for instruction on 603/603e.
  * Note: we get an alternate set of r0 - r3 to use automatically.
@@ -703,6 +716,11 @@
 #endif /* CONFIG_ALTIVEC */
 	EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)
 
+PerformanceMonitor:
+	EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_STD(0xf00, performance_monitor_exception)
+
 #ifdef CONFIG_ALTIVEC
 /* Note that the AltiVec support is closely modeled after the FP
  * support.  Changes to one are likely to be applicable to the
@@ -1306,6 +1324,32 @@
 	blr
 
 
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+setup_disp_bat:
+	/*
+	 * setup the display bat prepared for us in prom.c
+	 */
+	mflr	r8
+	bl	reloc_offset
+	mtlr	r8
+	addis	r8,r3,disp_BAT@ha
+	addi	r8,r8,disp_BAT@l
+	cmpwi	cr0,r8,0
+	beqlr
+	lwz	r11,0(r8)
+	lwz	r8,4(r8)
+	mfspr	r9,SPRN_PVR
+	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
+	cmpwi	0,r9,1
+	beq	1f
+	mtspr	SPRN_DBAT3L,r8
+	mtspr	SPRN_DBAT3U,r11
+	blr
+1:	mtspr	SPRN_IBAT3L,r8
+	mtspr	SPRN_IBAT3U,r11
+	blr
+#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
+
 #ifdef CONFIG_8260
 /* Jump into the system reset for the rom.
  * We first disable the MMU, and then jump to the ROM reset address.
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 8a8bf79..1c066d1 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -154,11 +154,15 @@
 	bne	100b
 
 #ifdef CONFIG_HMT
-	b	.hmt_init
+	LOADADDR(r4, .hmt_init)
+	mtctr	r4
+	bctr
 #else
 #ifdef CONFIG_SMP
+	LOADADDR(r4, .pSeries_secondary_smp_init)
+	mtctr	r4
 	mr	r3,r24
-	b	.pSeries_secondary_smp_init
+	bctr
 #else
 	BUG_OPCODE
 #endif
@@ -200,6 +204,20 @@
 #define EX_R3		64
 #define EX_LR		72
 
+/*
+ * We're short on space and time in the exception prolog, so we can't use
+ * the normal LOADADDR macro. Normally we just need the low halfword of the
+ * address, but for Kdump we need the whole low word.
+ */
+#ifdef CONFIG_CRASH_DUMP
+#define LOAD_HANDLER(reg, label)					\
+	oris	reg,reg,(label)@h;	/* virt addr of handler ... */	\
+	ori	reg,reg,(label)@l;	/* .. and the rest */
+#else
+#define LOAD_HANDLER(reg, label)					\
+	ori	reg,reg,(label)@l;	/* virt addr of handler ... */
+#endif
+
 #define EXCEPTION_PROLOG_PSERIES(area, label)				\
 	mfspr	r13,SPRN_SPRG3;		/* get paca address into r13 */	\
 	std	r9,area+EX_R9(r13);	/* save r9 - r12 */		\
@@ -212,7 +230,7 @@
 	clrrdi	r12,r13,32;		/* get high part of &label */	\
 	mfmsr	r10;							\
 	mfspr	r11,SPRN_SRR0;		/* save SRR0 */			\
-	ori	r12,r12,(label)@l;	/* virt addr of handler */	\
+	LOAD_HANDLER(r12,label)						\
 	ori	r10,r10,MSR_IR|MSR_DR|MSR_RI;				\
 	mtspr	SPRN_SRR0,r12;						\
 	mfspr	r12,SPRN_SRR1;		/* and SRR1 */			\
@@ -553,6 +571,7 @@
  * Vectors for the FWNMI option.  Share common code.
  */
 	.globl system_reset_fwnmi
+      .align 7
 system_reset_fwnmi:
 	HMT_MEDIUM
 	mtspr	SPRN_SPRG1,r13		/* save r13 */
@@ -560,6 +579,7 @@
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
 
 	.globl machine_check_fwnmi
+      .align 7
 machine_check_fwnmi:
 	HMT_MEDIUM
 	mtspr	SPRN_SPRG1,r13		/* save r13 */
@@ -726,7 +746,8 @@
 decrementer_iSeries_masked:
 	li	r11,1
 	stb	r11,PACALPPACA+LPPACADECRINT(r13)
-	lwz	r12,PACADEFAULTDECR(r13)
+	LOADBASE(r12,tb_ticks_per_jiffy)
+	lwz	r12,OFF(tb_ticks_per_jiffy)(r12)
 	mtspr	SPRN_DEC,r12
 	/* fall through */
 
@@ -1345,7 +1366,7 @@
  * fixed address (the linker can't compute (u64)&initial_stab >>
  * PAGE_SHIFT).
  */
-	. = STAB0_PHYS_ADDR	/* 0x6000 */
+	. = STAB0_OFFSET	/* 0x6000 */
 	.globl initial_stab
 initial_stab:
 	.space	4096
@@ -1485,11 +1506,13 @@
  *
  */
 _GLOBAL(__start_initialization_multiplatform)
+#ifdef CONFIG_PPC_MULTIPLATFORM
 	/*
 	 * Are we booted from a PROM Of-type client-interface ?
 	 */
 	cmpldi	cr0,r5,0
 	bne	.__boot_from_prom		/* yes -> prom */
+#endif
 
 	/* Save parameters */
 	mr	r31,r3
@@ -1510,6 +1533,7 @@
 	bl	.__mmu_off
 	b	.__after_prom_start
 
+#ifdef CONFIG_PPC_MULTIPLATFORM
 _STATIC(__boot_from_prom)
 	/* Save parameters */
 	mr	r31,r3
@@ -1542,6 +1566,7 @@
 	bl	.prom_init
 	/* We never return */
 	trap
+#endif
 
 /*
  * At this point, r3 contains the physical address we are running at,
@@ -1550,7 +1575,7 @@
 _STATIC(__after_prom_start)
 
 /*
- * We need to run with __start at physical address 0.
+ * We need to run with __start at physical address PHYSICAL_START.
  * This will leave some code in the first 256B of
  * real memory, which are reserved for software use.
  * The remainder of the first page is loaded with the fixed
@@ -1565,7 +1590,7 @@
 	mr	r26,r3
 	SET_REG_TO_CONST(r27,KERNELBASE)
 
-	li	r3,0			/* target addr */
+	LOADADDR(r3, PHYSICAL_START)	/* target addr */
 
 	// XXX FIXME: Use phys returned by OF (r30)
 	add	r4,r27,r26 		/* source addr			 */
@@ -1846,7 +1871,7 @@
 	mulli	r13,r27,PACA_SIZE	/* Calculate vaddr of right paca */
 	add	r13,r13,r24		/* for this processor.		 */
 	add	r13,r13,r26		/* convert to physical addr	 */
-	mtspr	SPRN_SPRG3,r13		/* PPPBBB: Temp... -Peter */
+	mtspr	SPRN_SPRG3,r13
 	
 	/* Do very early kernel initializations, including initial hash table,
 	 * stab and slb setup before we turn on relocation.	*/
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
new file mode 100644
index 0000000..e47d40a
--- /dev/null
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -0,0 +1,396 @@
+/*
+ * IBM PowerPC IBM eBus Infrastructure Support.
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *  Heiko J Schick <schickhj@de.ibm.com>
+ *    
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB 
+ * BSD. 
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met: 
+ *
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer. 
+ *
+ * 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. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <linux/init.h>
+#include <linux/console.h>
+#include <linux/kobject.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <asm/ibmebus.h>
+#include <asm/abs_addr.h>
+
+static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */
+	.name = ibmebus_bus_device.ofdev.dev.bus_id,
+	.ofdev.dev.bus_id = "ibmebus",
+	.ofdev.dev.bus    = &ibmebus_bus_type,
+};
+
+static void *ibmebus_alloc_coherent(struct device *dev,
+				    size_t size,
+				    dma_addr_t *dma_handle,
+				    gfp_t flag)
+{
+	void *mem;
+	
+	mem = kmalloc(size, flag);
+	*dma_handle = (dma_addr_t)mem;
+
+	return mem;
+}
+
+static void ibmebus_free_coherent(struct device *dev,
+				  size_t size, void *vaddr, 
+				  dma_addr_t dma_handle)
+{
+	kfree(vaddr);
+}
+
+static dma_addr_t ibmebus_map_single(struct device *dev,
+				     void *ptr,
+				     size_t size,
+				     enum dma_data_direction direction)
+{
+	return (dma_addr_t)(ptr);
+}
+
+static void ibmebus_unmap_single(struct device *dev,
+				 dma_addr_t dma_addr,
+				 size_t size, 
+				 enum dma_data_direction direction)
+{
+	return;
+}
+
+static int ibmebus_map_sg(struct device *dev,
+			  struct scatterlist *sg,
+			  int nents, enum dma_data_direction direction)
+{
+	int i;
+	
+	for (i = 0; i < nents; i++) {
+		sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) 
+			+ sg[i].offset;
+		sg[i].dma_length = sg[i].length;
+	}
+	
+	return nents;
+}
+
+static void ibmebus_unmap_sg(struct device *dev,
+			     struct scatterlist *sg,
+			     int nents, enum dma_data_direction direction)
+{
+	return;
+}
+
+static int ibmebus_dma_supported(struct device *dev, u64 mask)
+{
+	return 1;
+}
+
+struct dma_mapping_ops ibmebus_dma_ops = {
+	.alloc_coherent = ibmebus_alloc_coherent,
+	.free_coherent  = ibmebus_free_coherent,
+	.map_single     = ibmebus_map_single,
+	.unmap_single   = ibmebus_unmap_single,
+	.map_sg         = ibmebus_map_sg,
+	.unmap_sg       = ibmebus_unmap_sg,
+	.dma_supported  = ibmebus_dma_supported,
+};
+
+static int ibmebus_bus_probe(struct device *dev)
+{
+	struct ibmebus_dev *ibmebusdev    = to_ibmebus_dev(dev);
+	struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
+	const struct of_device_id *id;
+	int error = -ENODEV;
+	
+	if (!ibmebusdrv->probe)
+		return error;
+	
+	id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev);
+	if (id) {
+		error = ibmebusdrv->probe(ibmebusdev, id);
+	}
+	
+	return error;
+}
+
+static int ibmebus_bus_remove(struct device *dev)
+{
+	struct ibmebus_dev *ibmebusdev    = to_ibmebus_dev(dev);
+	struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
+	
+	if (ibmebusdrv->remove) {
+		return ibmebusdrv->remove(ibmebusdev);
+	}
+	
+	return 0;
+}
+
+static void __devinit ibmebus_dev_release(struct device *dev)
+{
+	of_node_put(to_ibmebus_dev(dev)->ofdev.node);
+	kfree(to_ibmebus_dev(dev));
+}
+
+static ssize_t ibmebusdev_show_name(struct device *dev, 
+				    struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
+}
+static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name, 
+		   NULL);
+
+static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+	struct ibmebus_dev *dev, char *name)
+{
+	int err = 0;
+
+	dev->name = name;
+	dev->ofdev.dev.parent  = &ibmebus_bus_device.ofdev.dev;
+	dev->ofdev.dev.bus     = &ibmebus_bus_type;
+	dev->ofdev.dev.release = ibmebus_dev_release;
+
+	/* An ibmebusdev is based on a of_device. We have to change the
+	 * bus type to use our own DMA mapping operations. 
+	 */       
+	if ((err = of_device_register(&dev->ofdev)) != 0) {
+		printk(KERN_ERR "%s: failed to register device (%d).\n",
+		       __FUNCTION__, err);
+		return NULL;
+	}
+	
+	device_create_file(&dev->ofdev.dev, &dev_attr_name);
+	
+	return dev;
+}
+
+static struct ibmebus_dev* __devinit ibmebus_register_device_node(
+	struct device_node *dn)
+{
+	struct ibmebus_dev *dev;
+	char *loc_code;
+	int length;
+
+	loc_code = (char *)get_property(dn, "ibm,loc-code", NULL);
+	if (!loc_code) {
+                printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
+		       __FUNCTION__, dn->name ? dn->name : "<unknown>");
+		return NULL;
+        }
+	
+	if (strlen(loc_code) == 0) {
+	        printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
+		       __FUNCTION__);
+		return NULL;
+	}
+
+	dev = kmalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
+	if (!dev) {
+		return NULL;
+	}
+	memset(dev, 0, sizeof(struct ibmebus_dev));
+
+	dev->ofdev.node = of_node_get(dn);
+       
+	length = strlen(loc_code);
+	memcpy(dev->ofdev.dev.bus_id, loc_code 
+		+ (length - min(length, BUS_ID_SIZE - 1)), 
+		min(length, BUS_ID_SIZE - 1));
+
+	/* Register with generic device framework. */
+	if (ibmebus_register_device_common(dev, dn->name) == NULL) {
+		kfree(dev);
+		return NULL;
+	}
+
+	return dev;
+}
+
+static void ibmebus_probe_of_nodes(char* name)
+{
+	struct device_node *dn = NULL;
+	
+	while ((dn = of_find_node_by_name(dn, name))) {
+		if (ibmebus_register_device_node(dn) == NULL) {
+			of_node_put(dn);
+			
+			return;
+		}
+	}
+	
+	of_node_put(dn);
+	
+	return;
+}
+
+static void ibmebus_add_devices_by_id(struct of_device_id *idt)
+{
+	while (strlen(idt->name) > 0) {
+		ibmebus_probe_of_nodes(idt->name);
+		idt++;
+	}
+
+	return;
+}
+
+static int ibmebus_match_helper(struct device *dev, void *data)
+{
+	if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0)
+		return 1;
+	
+	return 0;
+}
+
+static int ibmebus_unregister_device(struct device *dev)
+{
+	device_remove_file(dev, &dev_attr_name);
+	of_device_unregister(to_of_device(dev));
+
+	return 0;
+}
+
+static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
+{
+	struct device *dev;
+	
+	while (strlen(idt->name) > 0) {
+		while ((dev = bus_find_device(&ibmebus_bus_type, NULL, 
+					      (void*)idt->name,
+					      ibmebus_match_helper))) {
+			ibmebus_unregister_device(dev);
+		}
+		idt++;
+		
+	}
+	
+	return;
+}
+
+int ibmebus_register_driver(struct ibmebus_driver *drv)
+{
+	int err = 0;
+
+	drv->driver.name   = drv->name;
+	drv->driver.bus    = &ibmebus_bus_type;
+	drv->driver.probe  = ibmebus_bus_probe;
+	drv->driver.remove = ibmebus_bus_remove;
+
+	if ((err = driver_register(&drv->driver) != 0))
+		return err;
+
+	ibmebus_add_devices_by_id(drv->id_table);
+	
+	return 0;
+}
+EXPORT_SYMBOL(ibmebus_register_driver);
+
+void ibmebus_unregister_driver(struct ibmebus_driver *drv)
+{	
+	driver_unregister(&drv->driver);
+	ibmebus_remove_devices_by_id(drv->id_table);
+}
+EXPORT_SYMBOL(ibmebus_unregister_driver);
+
+int ibmebus_request_irq(struct ibmebus_dev *dev,
+			u32 ist, 
+			irqreturn_t (*handler)(int, void*, struct pt_regs *),
+			unsigned long irq_flags, const char * devname,
+			void *dev_id)
+{
+	unsigned int irq = virt_irq_create_mapping(ist);
+	
+	if (irq == NO_IRQ)
+		return -EINVAL;
+	
+	irq = irq_offset_up(irq);
+	
+	return request_irq(irq, handler,
+			   irq_flags, devname, dev_id);
+}
+EXPORT_SYMBOL(ibmebus_request_irq);
+
+void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
+{
+	unsigned int irq = virt_irq_create_mapping(ist);
+	
+	irq = irq_offset_up(irq);
+	free_irq(irq, dev_id);
+	
+	return;
+}
+EXPORT_SYMBOL(ibmebus_free_irq);
+
+static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
+{	
+	const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+	struct ibmebus_driver *ebus_drv    = to_ibmebus_driver(drv);
+	const struct of_device_id *ids     = ebus_drv->id_table;
+	const struct of_device_id *found_id;
+	
+	if (!ids)
+		return 0;
+	
+	found_id = of_match_device(ids, &ebus_dev->ofdev);
+	if (found_id)
+		return 1;
+	
+	return 0;
+}
+
+struct bus_type ibmebus_bus_type = {
+	.name = "ibmebus",
+	.match = ibmebus_bus_match,
+};
+EXPORT_SYMBOL(ibmebus_bus_type);
+
+static int __init ibmebus_bus_init(void)
+{
+	int err;
+	
+	printk(KERN_INFO "IBM eBus Device Driver\n");
+	
+	err = bus_register(&ibmebus_bus_type);
+	if (err) {
+		printk(KERN_ERR ":%s: failed to register IBM eBus.\n",
+		       __FUNCTION__);
+		return err;
+	}
+	
+	err = device_register(&ibmebus_bus_device.ofdev.dev);
+	if (err) {
+		printk(KERN_WARNING "%s: device_register returned %i\n", 
+		       __FUNCTION__, err);
+		bus_unregister(&ibmebus_bus_type);
+
+		return err;
+	}
+	
+	return 0;
+}
+__initcall(ibmebus_bus_init);
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 5a71ed9..5651032 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -31,7 +31,6 @@
  * to reduce code space and undefined function references.
  */
 
-#include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/threads.h>
 #include <linux/kernel_stat.h>
@@ -44,18 +43,12 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/proc_fs.h>
-#include <linux/random.h>
 #include <linux/seq_file.h>
 #include <linux/cpumask.h>
 #include <linux/profile.h>
 #include <linux/bitops.h>
-#ifdef CONFIG_PPC64
-#include <linux/kallsyms.h>
-#endif
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -66,8 +59,7 @@
 #include <asm/prom.h>
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
-#ifdef CONFIG_PPC64
-#include <asm/iseries/it_lp_queue.h>
+#ifdef CONFIG_PPC_ISERIES
 #include <asm/paca.h>
 #endif
 
@@ -78,10 +70,6 @@
 
 static int ppc_spurious_interrupts;
 
-#if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP)
-extern void iSeries_smp_message_recv(struct pt_regs *);
-#endif
-
 #ifdef CONFIG_PPC32
 #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
 
@@ -195,49 +183,6 @@
 }
 #endif
 
-#ifdef CONFIG_PPC_ISERIES
-void do_IRQ(struct pt_regs *regs)
-{
-	struct paca_struct *lpaca;
-
-	irq_enter();
-
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
-	/* Debugging check for stack overflow: is there less than 2KB free? */
-	{
-		long sp;
-
-		sp = __get_SP() & (THREAD_SIZE-1);
-
-		if (unlikely(sp < (sizeof(struct thread_info) + 2048))) {
-			printk("do_IRQ: stack overflow: %ld\n",
-				sp - sizeof(struct thread_info));
-			dump_stack();
-		}
-	}
-#endif
-
-	lpaca = get_paca();
-#ifdef CONFIG_SMP
-	if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
-		lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
-		iSeries_smp_message_recv(regs);
-	}
-#endif /* CONFIG_SMP */
-	if (hvlpevent_is_pending())
-		process_hvlpevents(regs);
-
-	irq_exit();
-
-	if (lpaca->lppaca.int_dword.fields.decr_int) {
-		lpaca->lppaca.int_dword.fields.decr_int = 0;
-		/* Signal a fake decrementer interrupt */
-		timer_interrupt(regs);
-	}
-}
-
-#else	/* CONFIG_PPC_ISERIES */
-
 void do_IRQ(struct pt_regs *regs)
 {
 	int irq;
@@ -286,16 +231,24 @@
 		} else
 #endif
 			__do_IRQ(irq, regs);
-	} else
-#ifdef CONFIG_PPC32
-		if (irq != -2)
-#endif
-			/* That's not SMP safe ... but who cares ? */
-			ppc_spurious_interrupts++;
-        irq_exit();
-}
+	} else if (irq != -2)
+		/* That's not SMP safe ... but who cares ? */
+		ppc_spurious_interrupts++;
 
-#endif	/* CONFIG_PPC_ISERIES */
+        irq_exit();
+
+#ifdef CONFIG_PPC_ISERIES
+	{
+		struct paca_struct *lpaca = get_paca();
+
+		if (lpaca->lppaca.int_dword.fields.decr_int) {
+			lpaca->lppaca.int_dword.fields.decr_int = 0;
+			/* Signal a fake decrementer interrupt */
+			timer_interrupt(regs);
+		}
+	}
+#endif
+}
 
 void __init init_IRQ(void)
 {
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
new file mode 100644
index 0000000..f970ace
--- /dev/null
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -0,0 +1,557 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/prom.h>
+#include <asm/serial.h>
+#include <asm/udbg.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+#define MAX_LEGACY_SERIAL_PORTS	8
+
+static struct plat_serial8250_port
+legacy_serial_ports[MAX_LEGACY_SERIAL_PORTS+1];
+static struct legacy_serial_info {
+	struct device_node		*np;
+	unsigned int			speed;
+	unsigned int			clock;
+	phys_addr_t			taddr;
+} legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];
+static unsigned int legacy_serial_count;
+static int legacy_serial_console = -1;
+
+static int __init add_legacy_port(struct device_node *np, int want_index,
+				  int iotype, phys_addr_t base,
+				  phys_addr_t taddr, unsigned long irq,
+				  unsigned int flags)
+{
+	u32 *clk, *spd, clock = BASE_BAUD * 16;
+	int index;
+
+	/* get clock freq. if present */
+	clk = (u32 *)get_property(np, "clock-frequency", NULL);
+	if (clk && *clk)
+		clock = *clk;
+
+	/* get default speed if present */
+	spd = (u32 *)get_property(np, "current-speed", NULL);
+
+	/* If we have a location index, then try to use it */
+	if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
+		index = want_index;
+	else
+		index = legacy_serial_count;
+
+	/* if our index is still out of range, that mean that
+	 * array is full, we could scan for a free slot but that
+	 * make little sense to bother, just skip the port
+	 */
+	if (index >= MAX_LEGACY_SERIAL_PORTS)
+		return -1;
+	if (index >= legacy_serial_count)
+		legacy_serial_count = index + 1;
+
+	/* Check if there is a port who already claimed our slot */
+	if (legacy_serial_infos[index].np != 0) {
+		/* if we still have some room, move it, else override */
+		if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) {
+			printk(KERN_INFO "Moved legacy port %d -> %d\n",
+			       index, legacy_serial_count);
+			legacy_serial_ports[legacy_serial_count] =
+				legacy_serial_ports[index];
+			legacy_serial_infos[legacy_serial_count] =
+				legacy_serial_infos[index];
+			legacy_serial_count++;
+		} else {
+			printk(KERN_INFO "Replacing legacy port %d\n", index);
+		}
+	}
+
+	/* Now fill the entry */
+	memset(&legacy_serial_ports[index], 0,
+	       sizeof(struct plat_serial8250_port));
+	if (iotype == UPIO_PORT)
+		legacy_serial_ports[index].iobase = base;
+	else
+		legacy_serial_ports[index].mapbase = base;
+	legacy_serial_ports[index].iotype = iotype;
+	legacy_serial_ports[index].uartclk = clock;
+	legacy_serial_ports[index].irq = irq;
+	legacy_serial_ports[index].flags = flags;
+	legacy_serial_infos[index].taddr = taddr;
+	legacy_serial_infos[index].np = of_node_get(np);
+	legacy_serial_infos[index].clock = clock;
+	legacy_serial_infos[index].speed = spd ? *spd : 0;
+
+	printk(KERN_INFO "Found legacy serial port %d for %s\n",
+	       index, np->full_name);
+	printk(KERN_INFO "  %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",
+	       (iotype == UPIO_PORT) ? "port" : "mem",
+	       (unsigned long long)base, (unsigned long long)taddr, irq,
+	       legacy_serial_ports[index].uartclk,
+	       legacy_serial_infos[index].speed);
+
+	return index;
+}
+
+static int __init add_legacy_soc_port(struct device_node *np,
+				      struct device_node *soc_dev)
+{
+	phys_addr_t addr;
+	u32 *addrp;
+	unsigned int 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 (get_property(np, "clock-frequency", NULL) == NULL)
+		return -1;
+
+	/* Get the address */
+	addrp = of_get_address(soc_dev, 0, NULL, NULL);
+	if (addrp == NULL)
+		return -1;
+
+	addr = of_translate_address(soc_dev, addrp);
+
+	/* 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);
+}
+
+#ifdef CONFIG_ISA
+static int __init add_legacy_isa_port(struct device_node *np,
+				      struct device_node *isa_brg)
+{
+	u32 *reg;
+	char *typep;
+	int index = -1;
+	phys_addr_t taddr;
+
+	/* Get the ISA port number */
+	reg = (u32 *)get_property(np, "reg", NULL);
+	if (reg == NULL)
+		return -1;
+
+	/* Verify it's an IO port, we don't support anything else */
+	if (!(reg[0] & 0x00000001))
+		return -1;
+
+	/* Now look for an "ibm,aix-loc" property that gives us ordering
+	 * if any...
+	 */
+	typep = (char *)get_property(np, "ibm,aix-loc", NULL);
+
+	/* If we have a location index, then use it */
+	if (typep && *typep == 'S')
+		index = simple_strtol(typep+1, NULL, 0) - 1;
+
+	/* Translate ISA address */
+	taddr = of_translate_address(np, reg);
+
+	/* Add port, irq will be dealt with later */
+	return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ, UPF_BOOT_AUTOCONF);
+
+}
+#endif
+
+#ifdef CONFIG_PCI
+static int __init add_legacy_pci_port(struct device_node *np,
+				      struct device_node *pci_dev)
+{
+	phys_addr_t addr, base;
+	u32 *addrp;
+	unsigned int flags;
+	int iotype, index = -1, lindex = 0;
+
+	/* We only support ports that have a clock frequency properly
+	 * encoded in the device-tree (that is have an fcode). Anything
+	 * else can't be used that early and will be normally probed by
+	 * the generic 8250_pci driver later on. The reason is that 8250
+	 * compatible UARTs on PCI need all sort of quirks (port offsets
+	 * etc...) that this code doesn't know about
+	 */
+	if (get_property(np, "clock-frequency", NULL) == NULL)
+		return -1;
+
+	/* Get the PCI address. Assume BAR 0 */
+	addrp = of_get_pci_address(pci_dev, 0, NULL, &flags);
+	if (addrp == NULL)
+		return -1;
+
+	/* We only support BAR 0 for now */
+	iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT;
+	addr = of_translate_address(pci_dev, addrp);
+
+	/* Set the IO base to the same as the translated address for MMIO,
+	 * or to the domain local IO base for PIO (it will be fixed up later)
+	 */
+	if (iotype == UPIO_MEM)
+		base = addr;
+	else
+		base = addrp[2];
+
+	/* Try to guess an index... If we have subdevices of the pci dev,
+	 * we get to their "reg" property
+	 */
+	if (np != pci_dev) {
+		u32 *reg = (u32 *)get_property(np, "reg", NULL);
+		if (reg && (*reg < 4))
+			index = lindex = *reg;
+	}
+
+	/* Local index means it's the Nth port in the PCI chip. Unfortunately
+	 * the offset to add here is device specific. We know about those
+	 * EXAR ports and we default to the most common case. If your UART
+	 * doesn't work for these settings, you'll have to add your own special
+	 * cases here
+	 */
+	if (device_is_compatible(pci_dev, "pci13a8,152") ||
+	    device_is_compatible(pci_dev, "pci13a8,154") ||
+	    device_is_compatible(pci_dev, "pci13a8,158")) {
+		addr += 0x200 * lindex;
+		base += 0x200 * lindex;
+	} else {
+		addr += 8 * lindex;
+		base += 8 * lindex;
+	}
+
+	/* 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, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF);
+}
+#endif
+
+/*
+ * This is called very early, as part of setup_system() or eventually
+ * setup_arch(), basically before anything else in this file. This function
+ * will try to build a list of all the available 8250-compatible serial ports
+ * in the machine using the Open Firmware device-tree. It currently only deals
+ * with ISA and PCI busses but could be extended. It allows a very early boot
+ * console to be initialized, that list is also used later to provide 8250 with
+ * the machine non-PCI ports and to properly pick the default console port
+ */
+void __init find_legacy_serial_ports(void)
+{
+	struct device_node *np, *stdout = NULL;
+	char *path;
+	int index;
+
+	DBG(" -> find_legacy_serial_port()\n");
+
+	/* Now find out if one of these is out firmware console */
+	path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+	if (path != NULL) {
+		stdout = of_find_node_by_path(path);
+		if (stdout)
+			DBG("stdout is %s\n", stdout->full_name);
+	} else {
+		DBG(" no linux,stdout-path !\n");
+	}
+
+	/* First fill our array with SOC ports */
+	for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) {
+		struct device_node *soc = of_get_parent(np);
+		if (soc && !strcmp(soc->type, "soc")) {
+			index = add_legacy_soc_port(np, np);
+			if (index >= 0 && np == stdout)
+				legacy_serial_console = index;
+		}
+		of_node_put(soc);
+	}
+
+#ifdef CONFIG_ISA
+	/* First fill our array with ISA ports */
+	for (np = NULL; (np = of_find_node_by_type(np, "serial"));) {
+		struct device_node *isa = of_get_parent(np);
+		if (isa && !strcmp(isa->name, "isa")) {
+			index = add_legacy_isa_port(np, isa);
+			if (index >= 0 && np == stdout)
+				legacy_serial_console = index;
+		}
+		of_node_put(isa);
+	}
+#endif
+
+#ifdef CONFIG_PCI
+	/* Next, try to locate PCI ports */
+	for (np = NULL; (np = of_find_all_nodes(np));) {
+		struct device_node *pci, *parent = of_get_parent(np);
+		if (parent && !strcmp(parent->name, "isa")) {
+			of_node_put(parent);
+			continue;
+		}
+		if (strcmp(np->name, "serial") && strcmp(np->type, "serial")) {
+			of_node_put(parent);
+			continue;
+		}
+		/* Check for known pciclass, and also check wether we have
+		 * a device with child nodes for ports or not
+		 */
+		if (device_is_compatible(np, "pciclass,0700") ||
+		    device_is_compatible(np, "pciclass,070002"))
+			pci = np;
+		else if (device_is_compatible(parent, "pciclass,0700") ||
+			 device_is_compatible(parent, "pciclass,070002"))
+			pci = parent;
+		else {
+			of_node_put(parent);
+			continue;
+		}
+		index = add_legacy_pci_port(np, pci);
+		if (index >= 0 && np == stdout)
+			legacy_serial_console = index;
+		of_node_put(parent);
+	}
+#endif
+
+	DBG("legacy_serial_console = %d\n", legacy_serial_console);
+
+	/* udbg is 64 bits only for now, that will change soon though ... */
+	while (legacy_serial_console >= 0) {
+		struct legacy_serial_info *info =
+			&legacy_serial_infos[legacy_serial_console];
+		void __iomem *addr;
+
+		if (info->taddr == 0)
+			break;
+		addr = ioremap(info->taddr, 0x1000);
+		if (addr == NULL)
+			break;
+		if (info->speed == 0)
+			info->speed = udbg_probe_uart_speed(addr, info->clock);
+		DBG("default console speed = %d\n", info->speed);
+		udbg_init_uart(addr, info->speed, info->clock);
+		break;
+	}
+
+	DBG(" <- find_legacy_serial_port()\n");
+}
+
+static struct platform_device serial_device = {
+	.name	= "serial8250",
+	.id	= PLAT8250_DEV_PLATFORM,
+	.dev	= {
+		.platform_data = legacy_serial_ports,
+	},
+};
+
+static void __init fixup_port_irq(int index,
+				  struct device_node *np,
+				  struct plat_serial8250_port *port)
+{
+	DBG("fixup_port_irq(%d)\n", index);
+
+	/* Check for interrupts in that node */
+	if (np->n_intrs > 0) {
+		port->irq = np->intrs[0].line;
+		DBG(" port %d (%s), irq=%d\n",
+		    index, np->full_name, port->irq);
+		return;
+	}
+
+	/* Check for interrupts in the parent */
+	np = of_get_parent(np);
+	if (np == NULL)
+		return;
+
+	if (np->n_intrs > 0) {
+		port->irq = np->intrs[0].line;
+		DBG(" port %d (%s), irq=%d\n",
+		    index, np->full_name, port->irq);
+	}
+	of_node_put(np);
+}
+
+static void __init fixup_port_pio(int index,
+				  struct device_node *np,
+				  struct plat_serial8250_port *port)
+{
+#ifdef CONFIG_PCI
+	struct pci_controller *hose;
+
+	DBG("fixup_port_pio(%d)\n", index);
+
+	hose = pci_find_hose_for_OF_device(np);
+	if (hose) {
+		unsigned long offset = (unsigned long)hose->io_base_virt -
+#ifdef CONFIG_PPC64
+			pci_io_base;
+#else
+			isa_io_base;
+#endif
+		DBG("port %d, IO %lx -> %lx\n",
+		    index, port->iobase, port->iobase + offset);
+		port->iobase += offset;
+	}
+#endif
+}
+
+static void __init fixup_port_mmio(int index,
+				   struct device_node *np,
+				   struct plat_serial8250_port *port)
+{
+	DBG("fixup_port_mmio(%d)\n", index);
+
+	port->membase = ioremap(port->mapbase, 0x100);
+}
+
+/*
+ * This is called as an arch initcall, hopefully before the PCI bus is
+ * probed and/or the 8250 driver loaded since we need to register our
+ * platform devices before 8250 PCI ones are detected as some of them
+ * must properly "override" the platform ones.
+ *
+ * This function fixes up the interrupt value for platform ports as it
+ * couldn't be done earlier before interrupt maps have been parsed. It
+ * also "corrects" the IO address for PIO ports for the same reason,
+ * since earlier, the PHBs virtual IO space wasn't assigned yet. It then
+ * registers all those platform ports for use by the 8250 driver when it
+ * finally loads.
+ */
+static int __init serial_dev_init(void)
+{
+	int i;
+
+	if (legacy_serial_count == 0)
+		return -ENODEV;
+
+	/*
+	 * Before we register the platfrom serial devices, we need
+	 * to fixup their interrutps and their IO ports.
+	 */
+	DBG("Fixing serial ports interrupts and IO ports ...\n");
+
+	for (i = 0; i < legacy_serial_count; i++) {
+		struct plat_serial8250_port *port = &legacy_serial_ports[i];
+		struct device_node *np = legacy_serial_infos[i].np;
+
+		if (port->irq == NO_IRQ)
+			fixup_port_irq(i, np, port);
+		if (port->iotype == UPIO_PORT)
+			fixup_port_pio(i, np, port);
+		if (port->iotype == UPIO_MEM)
+			fixup_port_mmio(i, np, port);
+	}
+
+	DBG("Registering platform serial ports\n");
+
+	return platform_device_register(&serial_device);
+}
+arch_initcall(serial_dev_init);
+
+
+/*
+ * This is called very early, as part of console_init() (typically just after
+ * time_init()). This function is respondible for trying to find a good
+ * default console on serial ports. It tries to match the open firmware
+ * default output with one of the available serial console drivers, either
+ * one of the platform serial ports that have been probed earlier by
+ * find_legacy_serial_ports() or some more platform specific ones.
+ */
+static int __init check_legacy_serial_console(void)
+{
+	struct device_node *prom_stdout = NULL;
+	int speed = 0, offset = 0;
+	char *name;
+	u32 *spd;
+
+	DBG(" -> check_legacy_serial_console()\n");
+
+	/* The user has requested a console so this is already set up. */
+	if (strstr(saved_command_line, "console=")) {
+		DBG(" console was specified !\n");
+		return -EBUSY;
+	}
+
+	if (!of_chosen) {
+		DBG(" of_chosen is NULL !\n");
+		return -ENODEV;
+	}
+
+	if (legacy_serial_console < 0) {
+		DBG(" legacy_serial_console not found !\n");
+		return -ENODEV;
+	}
+	/* We are getting a weird phandle from OF ... */
+	/* ... So use the full path instead */
+	name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+	if (name == NULL) {
+		DBG(" no linux,stdout-path !\n");
+		return -ENODEV;
+	}
+	prom_stdout = of_find_node_by_path(name);
+	if (!prom_stdout) {
+		DBG(" can't find stdout package %s !\n", name);
+		return -ENODEV;
+	}
+	DBG("stdout is %s\n", prom_stdout->full_name);
+
+	name = (char *)get_property(prom_stdout, "name", NULL);
+	if (!name) {
+		DBG(" stdout package has no name !\n");
+		goto not_found;
+	}
+	spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
+	if (spd)
+		speed = *spd;
+
+	if (0)
+		;
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+	else if (strcmp(name, "serial") == 0) {
+		int i;
+		/* Look for it in probed array */
+		for (i = 0; i < legacy_serial_count; i++) {
+			if (prom_stdout != legacy_serial_infos[i].np)
+				continue;
+			offset = i;
+			speed = legacy_serial_infos[i].speed;
+			break;
+		}
+		if (i >= legacy_serial_count)
+			goto not_found;
+	}
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+	else if (strcmp(name, "ch-a") == 0)
+		offset = 0;
+	else if (strcmp(name, "ch-b") == 0)
+		offset = 1;
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+	else
+		goto not_found;
+	of_node_put(prom_stdout);
+
+	DBG("Found serial console at ttyS%d\n", offset);
+
+	if (speed) {
+		static char __initdata opt[16];
+		sprintf(opt, "%d", speed);
+		return add_preferred_console("ttyS", offset, opt);
+	} else
+		return add_preferred_console("ttyS", offset, NULL);
+
+ not_found:
+	DBG("No preferred console found !\n");
+	of_node_put(prom_stdout);
+	return -ENODEV;
+}
+console_initcall(check_legacy_serial_console);
+
diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c
index 5a05a79..584d1e3 100644
--- a/arch/powerpc/kernel/lparmap.c
+++ b/arch/powerpc/kernel/lparmap.c
@@ -7,7 +7,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <asm/mmu.h>
-#include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/iseries/lpar_map.h>
 
 const struct LparMap __attribute__((__section__(".text"))) xLparMap = {
@@ -16,16 +16,16 @@
 	.xSegmentTableOffs = STAB0_PAGE,
 
 	.xEsids = {
-		{ .xKernelEsid = GET_ESID(KERNELBASE),
-		  .xKernelVsid = KERNEL_VSID(KERNELBASE), },
-		{ .xKernelEsid = GET_ESID(VMALLOCBASE),
-		  .xKernelVsid = KERNEL_VSID(VMALLOCBASE), },
+		{ .xKernelEsid = GET_ESID(PAGE_OFFSET),
+		  .xKernelVsid = KERNEL_VSID(PAGE_OFFSET), },
+		{ .xKernelEsid = GET_ESID(VMALLOC_START),
+		  .xKernelVsid = KERNEL_VSID(VMALLOC_START), },
 	},
 
 	.xRanges = {
 		{ .xPages = HvPagesToMap,
 		  .xOffset = 0,
-		  .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - HW_PAGE_SHIFT),
+		  .xVPN = KERNEL_VSID(PAGE_OFFSET) << (SID_SHIFT - HW_PAGE_SHIFT),
 		},
 	},
 };
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
new file mode 100644
index 0000000..a91e40c
--- /dev/null
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -0,0 +1,67 @@
+/*
+ * Code to handle transition of Linux booting another kernel.
+ *
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ * Copyright (C) 2005 IBM Corporation.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/kexec.h>
+#include <linux/reboot.h>
+#include <linux/threads.h>
+#include <asm/machdep.h>
+
+/*
+ * Provide a dummy crash_notes definition until crash dump is implemented.
+ * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
+ */
+note_buf_t crash_notes[NR_CPUS];
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+	if (ppc_md.machine_crash_shutdown)
+		ppc_md.machine_crash_shutdown(regs);
+}
+
+/*
+ * Do what every setup is needed on image and the
+ * reboot code buffer to allow us to avoid allocations
+ * later.
+ */
+int machine_kexec_prepare(struct kimage *image)
+{
+	if (ppc_md.machine_kexec_prepare)
+		return ppc_md.machine_kexec_prepare(image);
+	/*
+	 * Fail if platform doesn't provide its own machine_kexec_prepare
+	 * implementation.
+	 */
+	return -ENOSYS;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+	if (ppc_md.machine_kexec_cleanup)
+		ppc_md.machine_kexec_cleanup(image);
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+	if (ppc_md.machine_kexec)
+		ppc_md.machine_kexec(image);
+	else {
+		/*
+		 * Fall back to normal restart if platform doesn't provide
+		 * its own kexec function, and user insist to kexec...
+		 */
+		machine_restart(NULL);
+	}
+	for(;;);
+}
diff --git a/arch/powerpc/kernel/machine_kexec_32.c b/arch/powerpc/kernel/machine_kexec_32.c
new file mode 100644
index 0000000..4436061
--- /dev/null
+++ b/arch/powerpc/kernel/machine_kexec_32.c
@@ -0,0 +1,65 @@
+/*
+ * PPC32 code to handle Linux booting another kernel.
+ *
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ * Copyright (C) 2005 IBM Corporation.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/kexec.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <asm/cacheflush.h>
+#include <asm/hw_irq.h>
+#include <asm/io.h>
+
+typedef NORET_TYPE void (*relocate_new_kernel_t)(
+				unsigned long indirection_page,
+				unsigned long reboot_code_buffer,
+				unsigned long start_address) ATTRIB_NORET;
+
+/*
+ * This is a generic machine_kexec function suitable at least for
+ * non-OpenFirmware embedded platforms.
+ * It merely copies the image relocation code to the control page and
+ * jumps to it.
+ * A platform specific function may just call this one.
+ */
+void default_machine_kexec(struct kimage *image)
+{
+	const extern unsigned char relocate_new_kernel[];
+	const extern unsigned int relocate_new_kernel_size;
+	unsigned long page_list;
+	unsigned long reboot_code_buffer, reboot_code_buffer_phys;
+	relocate_new_kernel_t rnk;
+
+	/* Interrupts aren't acceptable while we reboot */
+	local_irq_disable();
+
+	page_list = image->head;
+
+	/* we need both effective and real address here */
+	reboot_code_buffer =
+			(unsigned long)page_address(image->control_code_page);
+	reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer);
+
+	/* copy our kernel relocation code to the control code page */
+	memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+						relocate_new_kernel_size);
+
+	flush_icache_range(reboot_code_buffer,
+				reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
+	printk(KERN_INFO "Bye!\n");
+
+	/* now call it */
+	rnk = (relocate_new_kernel_t) reboot_code_buffer;
+	(*rnk)(page_list, reboot_code_buffer_phys, image->start);
+}
+
+int default_machine_kexec_prepare(struct kimage *image)
+{
+	return 0;
+}
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 97c51e4..d643144 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -1,5 +1,5 @@
 /*
- * machine_kexec.c - handle transition of Linux booting another kernel
+ * PPC64 code to handle Linux booting another kernel.
  *
  * Copyright (C) 2004-2005, IBM Corp.
  *
@@ -28,21 +28,7 @@
 
 #define HASH_GROUP_SIZE 0x80	/* size of each hash group, asm/mmu.h */
 
-/* Have this around till we move it into crash specific file */
-note_buf_t crash_notes[NR_CPUS];
-
-/* Dummy for now. Not sure if we need to have a crash shutdown in here
- * and if what it will achieve. Letting it be now to compile the code
- * in generic kexec environment
- */
-void machine_crash_shutdown(struct pt_regs *regs)
-{
-	/* do nothing right now */
-	/* smp_relase_cpus() if we want smp on panic kernel */
-	/* cpu_irq_down to isolate us until we are ready */
-}
-
-int machine_kexec_prepare(struct kimage *image)
+int default_machine_kexec_prepare(struct kimage *image)
 {
 	int i;
 	unsigned long begin, end;	/* limits of segment */
@@ -111,11 +97,6 @@
 	return 0;
 }
 
-void machine_kexec_cleanup(struct kimage *image)
-{
-	/* we do nothing in prepare that needs to be undone */
-}
-
 #define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE)
 
 static void copy_segments(unsigned long ind)
@@ -172,9 +153,8 @@
 	 * including ones that were in place on the original copy
 	 */
 	for (i = 0; i < nr_segments; i++)
-		flush_icache_range(ranges[i].mem + KERNELBASE,
-				ranges[i].mem + KERNELBASE +
-				ranges[i].memsz);
+		flush_icache_range((unsigned long)__va(ranges[i].mem),
+			(unsigned long)__va(ranges[i].mem + ranges[i].memsz));
 }
 
 #ifdef CONFIG_SMP
@@ -283,13 +263,20 @@
 					void (*clear_all)(void)) ATTRIB_NORET;
 
 /* too late to fail here */
-void machine_kexec(struct kimage *image)
+void default_machine_kexec(struct kimage *image)
 {
-
 	/* prepare control code if any */
 
-	/* shutdown other cpus into our wait loop and quiesce interrupts */
-	kexec_prepare_cpus();
+	/*
+        * If the kexec boot is the normal one, need to shutdown other cpus
+        * into our wait loop and quiesce interrupts.
+        * Otherwise, in the case of crashed mode (crashing_cpu >= 0),
+        * stopping other CPUs and collecting their pt_regs is done before
+        * using debugger IPI.
+        */
+
+       if (crashing_cpu == -1)
+               kexec_prepare_cpus();
 
 	/* switch to a staticly allocated stack.  Based on irq stack code.
 	 * XXX: the task struct will likely be invalid once we do the copy!
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 624a983..01d0d97 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -5,6 +5,10 @@
  * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
  * and Paul Mackerras.
  *
+ * kexec bits:
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
  * 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
@@ -24,6 +28,8 @@
 #include <asm/ppc_asm.h>
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
+#include <asm/processor.h>
+#include <asm/kexec.h>
 
 	.text
 
@@ -1006,3 +1012,110 @@
  */
 _GLOBAL(__main)
 	blr
+
+#ifdef CONFIG_KEXEC
+	/*
+	 * Must be relocatable PIC code callable as a C function.
+	 */
+	.globl relocate_new_kernel
+relocate_new_kernel:
+	/* r3 = page_list   */
+	/* r4 = reboot_code_buffer */
+	/* r5 = start_address      */
+
+	li	r0, 0
+
+	/*
+	 * Set Machine Status Register to a known status,
+	 * switch the MMU off and jump to 1: in a single step.
+	 */
+
+	mr	r8, r0
+	ori     r8, r8, MSR_RI|MSR_ME
+	mtspr	SPRN_SRR1, r8
+	addi	r8, r4, 1f - relocate_new_kernel
+	mtspr	SPRN_SRR0, r8
+	sync
+	rfi
+
+1:
+	/* from this point address translation is turned off */
+	/* and interrupts are disabled */
+
+	/* set a new stack at the bottom of our page... */
+	/* (not really needed now) */
+	addi	r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
+	stw	r0, 0(r1)
+
+	/* Do the copies */
+	li	r6, 0 /* checksum */
+	mr	r0, r3
+	b	1f
+
+0:	/* top, read another word for the indirection page */
+	lwzu	r0, 4(r3)
+
+1:
+	/* is it a destination page? (r8) */
+	rlwinm.	r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
+	beq	2f
+
+	rlwinm	r8, r0, 0, 0, 19 /* clear kexec flags, page align */
+	b	0b
+
+2:	/* is it an indirection page? (r3) */
+	rlwinm.	r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
+	beq	2f
+
+	rlwinm	r3, r0, 0, 0, 19 /* clear kexec flags, page align */
+	subi	r3, r3, 4
+	b	0b
+
+2:	/* are we done? */
+	rlwinm.	r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
+	beq	2f
+	b	3f
+
+2:	/* is it a source page? (r9) */
+	rlwinm.	r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
+	beq	0b
+
+	rlwinm	r9, r0, 0, 0, 19 /* clear kexec flags, page align */
+
+	li	r7, PAGE_SIZE / 4
+	mtctr   r7
+	subi    r9, r9, 4
+	subi    r8, r8, 4
+9:
+	lwzu    r0, 4(r9)  /* do the copy */
+	xor	r6, r6, r0
+	stwu    r0, 4(r8)
+	dcbst	0, r8
+	sync
+	icbi	0, r8
+	bdnz    9b
+
+	addi    r9, r9, 4
+	addi    r8, r8, 4
+	b	0b
+
+3:
+
+	/* To be certain of avoiding problems with self-modifying code
+	 * execute a serializing instruction here.
+	 */
+	isync
+	sync
+
+	/* jump to the entry point, usually the setup routine */
+	mtlr	r5
+	blrl
+
+1:	b	1b
+
+relocate_new_kernel_end:
+
+	.globl relocate_new_kernel_size
+relocate_new_kernel_size:
+	.long relocate_new_kernel_end - relocate_new_kernel
+#endif
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index c0fcd29..fd7db8d 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -80,80 +80,74 @@
 static ssize_t dev_nvram_read(struct file *file, char __user *buf,
 			  size_t count, loff_t *ppos)
 {
-	ssize_t len;
-	char *tmp_buffer;
-	int size;
+	ssize_t ret;
+	char *tmp = NULL;
+	ssize_t size;
 
-	if (ppc_md.nvram_size == NULL)
-		return -ENODEV;
+	ret = -ENODEV;
+	if (!ppc_md.nvram_size)
+		goto out;
+
+	ret = 0;
 	size = ppc_md.nvram_size();
+	if (*ppos >= size || size < 0)
+		goto out;
 
-	if (!access_ok(VERIFY_WRITE, buf, count))
-		return -EFAULT;
-	if (*ppos >= size)
-		return 0;
-	if (count > size) 
-		count = size;
+	count = min_t(size_t, count, size - *ppos);
+	count = min(count, PAGE_SIZE);
 
-	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
-	if (!tmp_buffer) {
-		printk(KERN_ERR "dev_read_nvram: kmalloc failed\n");
-		return -ENOMEM;
-	}
+	ret = -ENOMEM;
+	tmp = kmalloc(count, GFP_KERNEL);
+	if (!tmp)
+		goto out;
 
-	len = ppc_md.nvram_read(tmp_buffer, count, ppos);
-	if ((long)len <= 0) {
-		kfree(tmp_buffer);
-		return len;
-	}
+	ret = ppc_md.nvram_read(tmp, count, ppos);
+	if (ret <= 0)
+		goto out;
 
-	if (copy_to_user(buf, tmp_buffer, len)) {
-		kfree(tmp_buffer);
-		return -EFAULT;
-	}
+	if (copy_to_user(buf, tmp, ret))
+		ret = -EFAULT;
 
-	kfree(tmp_buffer);
-	return len;
+out:
+	kfree(tmp);
+	return ret;
 
 }
 
 static ssize_t dev_nvram_write(struct file *file, const char __user *buf,
-			   size_t count, loff_t *ppos)
+			  size_t count, loff_t *ppos)
 {
-	ssize_t len;
-	char * tmp_buffer;
-	int size;
+	ssize_t ret;
+	char *tmp = NULL;
+	ssize_t size;
 
-	if (ppc_md.nvram_size == NULL)
-		return -ENODEV;
+	ret = -ENODEV;
+	if (!ppc_md.nvram_size)
+		goto out;
+
+	ret = 0;
 	size = ppc_md.nvram_size();
+	if (*ppos >= size || size < 0)
+		goto out;
 
-	if (!access_ok(VERIFY_READ, buf, count))
-		return -EFAULT;
-	if (*ppos >= size)
-		return 0;
-	if (count > size)
-		count = size;
+	count = min_t(size_t, count, size - *ppos);
+	count = min(count, PAGE_SIZE);
 
-	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
-	if (!tmp_buffer) {
-		printk(KERN_ERR "dev_nvram_write: kmalloc failed\n");
-		return -ENOMEM;
-	}
-	
-	if (copy_from_user(tmp_buffer, buf, count)) {
-		kfree(tmp_buffer);
-		return -EFAULT;
-	}
+	ret = -ENOMEM;
+	tmp = kmalloc(count, GFP_KERNEL);
+	if (!tmp)
+		goto out;
 
-	len = ppc_md.nvram_write(tmp_buffer, count, ppos);
-	if ((long)len <= 0) {
-		kfree(tmp_buffer);
-		return len;
-	}
+	ret = -EFAULT;
+	if (copy_from_user(tmp, buf, count))
+		goto out;
 
-	kfree(tmp_buffer);
-	return len;
+	ret = ppc_md.nvram_write(tmp, count, ppos);
+
+out:
+	kfree(tmp);
+	return ret;
+
 }
 
 static int dev_nvram_ioctl(struct inode *inode, struct file *file,
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index a7b68f9..999bdd8 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -17,6 +17,7 @@
 #include <asm/page.h>
 #include <asm/lppaca.h>
 #include <asm/iseries/it_lp_queue.h>
+#include <asm/iseries/it_lp_reg_save.h>
 #include <asm/paca.h>
 
 
@@ -26,8 +27,7 @@
 
 /* The Paca is an array with one entry per processor.  Each contains an
  * lppaca, which contains the information shared between the
- * hypervisor and Linux.  Each also contains an ItLpRegSave area which
- * is used by the hypervisor to save registers.
+ * hypervisor and Linux.
  * On systems with hardware multi-threading, there are two threads
  * per processor.  The Paca array must contain an entry for each thread.
  * The VPD Areas will give a max logical processors = 2 * max physical
@@ -37,7 +37,6 @@
 #define PACA_INIT_COMMON(number, start, asrr, asrv)			    \
 	.lock_token = 0x8000,						    \
 	.paca_index = (number),		/* Paca Index */		    \
-	.default_decr = 0x00ff0000,	/* Initial Decr */		    \
 	.kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL,		    \
 	.stab_real = (asrr), 		/* Real pointer to segment table */ \
 	.stab_addr = (asrv),		/* Virt pointer to segment table */ \
@@ -57,11 +56,7 @@
 #ifdef CONFIG_PPC_ISERIES
 #define PACA_INIT_ISERIES(number)					    \
 	.lppaca_ptr = &paca[number].lppaca,				    \
-	.reg_save_ptr = &paca[number].reg_save,				    \
-	.reg_save = {							    \
-		.xDesc = 0xd397d9e2,	/* "LpRS" */			    \
-		.xSize = sizeof(struct ItLpRegSave)			    \
-	}
+	.reg_save_ptr = &iseries_reg_save[number],
 
 #define PACA_INIT(number)						    \
 {									    \
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 8b6008a..fc60a77 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -34,7 +34,7 @@
 
 #ifdef DEBUG
 #include <asm/udbg.h>
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG(fmt...) printk(fmt)
 #else
 #define DBG(fmt...)
 #endif
@@ -251,7 +251,7 @@
 		kfree(phb);
 }
 
-static void __init pcibios_claim_one_bus(struct pci_bus *b)
+void __devinit pcibios_claim_one_bus(struct pci_bus *b)
 {
 	struct pci_dev *dev;
 	struct pci_bus *child_bus;
@@ -323,6 +323,7 @@
 	addrs = (u32 *) get_property(node, "assigned-addresses", &proplen);
 	if (!addrs)
 		return;
+	DBG("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
 	for (; proplen >= 20; proplen -= 20, addrs += 5) {
 		flags = pci_parse_of_flags(addrs[0]);
 		if (!flags)
@@ -332,6 +333,9 @@
 		if (!size)
 			continue;
 		i = addrs[0] & 0xff;
+		DBG("  base: %llx, size: %llx, i: %x\n",
+		    (unsigned long long)base, (unsigned long long)size, i);
+
 		if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
 			res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
 		} else if (i == dev->rom_base_reg) {
@@ -362,6 +366,8 @@
 	if (type == NULL)
 		type = "";
 
+	DBG("    create device, devfn: %x, type: %s\n", devfn, type);
+
 	memset(dev, 0, sizeof(struct pci_dev));
 	dev->bus = bus;
 	dev->sysdata = node;
@@ -381,6 +387,8 @@
 		dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
 	dev->class = get_int_prop(node, "class-code", 0);
 
+	DBG("    class: 0x%x\n", dev->class);
+
 	dev->current_state = 4;		/* unknown power state */
 
 	if (!strcmp(type, "pci")) {
@@ -402,6 +410,8 @@
 
 	pci_parse_of_addrs(node, dev);
 
+	DBG("    adding to system ...\n");
+
 	pci_device_add(dev, bus);
 
 	/* XXX pci_scan_msi_device(dev); */
@@ -418,15 +428,21 @@
 	int reglen, devfn;
 	struct pci_dev *dev;
 
+	DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number);
+
 	while ((child = of_get_next_child(node, child)) != NULL) {
+		DBG("  * %s\n", child->full_name);
 		reg = (u32 *) get_property(child, "reg", &reglen);
 		if (reg == NULL || reglen < 20)
 			continue;
 		devfn = (reg[0] >> 8) & 0xff;
+
 		/* create a new pci_dev for this device */
 		dev = of_create_pci_dev(child, bus, devfn);
 		if (!dev)
 			continue;
+		DBG("dev header type: %x\n", dev->hdr_type);
+
 		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
 		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 			of_scan_pci_bridge(child, dev);
@@ -446,16 +462,18 @@
 	unsigned int flags;
 	u64 size;
 
+	DBG("of_scan_pci_bridge(%s)\n", node->full_name);
+
 	/* parse bus-range property */
 	busrange = (u32 *) get_property(node, "bus-range", &len);
 	if (busrange == NULL || len != 8) {
-		printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n",
+		printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
 		       node->full_name);
 		return;
 	}
 	ranges = (u32 *) get_property(node, "ranges", &len);
 	if (ranges == NULL) {
-		printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n",
+		printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
 		       node->full_name);
 		return;
 	}
@@ -509,10 +527,13 @@
 	}
 	sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
 		bus->number);
+	DBG("    bus name: %s\n", bus->name);
 
 	mode = PCI_PROBE_NORMAL;
 	if (ppc_md.pci_probe_mode)
 		mode = ppc_md.pci_probe_mode(bus);
+	DBG("    probe mode: %d\n", mode);
+
 	if (mode == PCI_PROBE_DEVTREE)
 		of_scan_bus(node, bus);
 	else if (mode == PCI_PROBE_NORMAL)
@@ -528,6 +549,8 @@
 	int i, mode;
 	struct resource *res;
 
+	DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
+
 	bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node);
 	if (bus == NULL) {
 		printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
@@ -552,8 +575,9 @@
 
 	mode = PCI_PROBE_NORMAL;
 #ifdef CONFIG_PPC_MULTIPLATFORM
-	if (ppc_md.pci_probe_mode)
+	if (node && ppc_md.pci_probe_mode)
 		mode = ppc_md.pci_probe_mode(bus);
+	DBG("    probe mode: %d\n", mode);
 	if (mode == PCI_PROBE_DEVTREE) {
 		bus->subordinate = hose->last_busno;
 		of_scan_bus(node, bus);
@@ -842,8 +866,7 @@
  * Returns a negative error code on failure, zero on success.
  */
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
-			enum pci_mmap_state mmap_state,
-			int write_combine)
+			enum pci_mmap_state mmap_state, int write_combine)
 {
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	struct resource *rp;
@@ -896,6 +919,25 @@
 				      unsigned long phb_io_base_phys,
 				      void __iomem * phb_io_base_virt)
 {
+	/* Remove these asap */
+
+	struct pci_address {
+		u32 a_hi;
+		u32 a_mid;
+		u32 a_lo;
+	};
+
+	struct isa_address {
+		u32 a_hi;
+		u32 a_lo;
+	};
+
+	struct isa_range {
+		struct isa_address isa_addr;
+		struct pci_address pci_addr;
+		unsigned int size;
+	};
+
 	struct isa_range *range;
 	unsigned long pci_addr;
 	unsigned int isa_addr;
@@ -1223,6 +1265,7 @@
 }
 EXPORT_SYMBOL(pcibios_fixup_device_resources);
 
+
 static void __devinit do_bus_setup(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
@@ -1306,8 +1349,38 @@
 	*end = rsrc->end + offset;
 }
 
+struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
+{
+	if (!have_of)
+		return NULL;
+	while(node) {
+		struct pci_controller *hose, *tmp;
+		list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+			if (hose->arch_data == node)
+				return hose;
+		node = node->parent;
+	}
+	return NULL;
+}
+
 #endif /* CONFIG_PPC_MULTIPLATFORM */
 
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+	struct pci_controller *hose, *tmp;
+
+	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+		if (address >= hose->io_base_phys &&
+		    address < (hose->io_base_phys + hose->pci_io_size)) {
+			unsigned long base =
+				(unsigned long)hose->io_base_virt - pci_io_base;
+			return base + (address - hose->io_base_phys);
+		}
+	}
+	return (unsigned int)-1;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
 
 #define IOBASE_BRIDGE_NUMBER	0
 #define IOBASE_MEMORY		1
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
index 2d333cc..e6fb194 100644
--- a/arch/powerpc/kernel/pmc.c
+++ b/arch/powerpc/kernel/pmc.c
@@ -43,8 +43,13 @@
 	mtspr(SPRN_MMCR0, mmcr0);
 }
 #else
+/* Ensure exceptions are disabled */
 static void dummy_perf(struct pt_regs *regs)
 {
+	unsigned int mmcr0 = mfspr(SPRN_MMCR0);
+
+	mmcr0 &= ~(MMCR0_PMXE);
+	mtspr(SPRN_MMCR0, mmcr0);
 }
 #endif
 
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 94db257..b275814 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -76,11 +76,6 @@
 EXPORT_SYMBOL(sys_sigreturn);
 #endif
 
-#if defined(CONFIG_PPC_PREP)
-EXPORT_SYMBOL(_prep_type);
-EXPORT_SYMBOL(ucSystemType);
-#endif
-
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 3bf968e..977ee3a 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -29,6 +29,7 @@
 #include <linux/initrd.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
+#include <linux/kexec.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -37,6 +38,7 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/kdump.h>
 #include <asm/smp.h>
 #include <asm/system.h>
 #include <asm/mmu.h>
@@ -55,21 +57,6 @@
 #define DBG(fmt...)
 #endif
 
-struct pci_reg_property {
-	struct pci_address addr;
-	u32 size_hi;
-	u32 size_lo;
-};
-
-struct isa_reg_property {
-	u32 space;
-	u32 address;
-	u32 size;
-};
-
-
-typedef int interpret_func(struct device_node *, unsigned long *,
-			   int, int, int);
 
 static int __initdata dt_root_addr_cells;
 static int __initdata dt_root_size_cells;
@@ -311,6 +298,16 @@
 	int i, j, n, sense;
 	unsigned int *irq, virq;
 	struct device_node *ic;
+	int trace = 0;
+
+	//#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0)
+#define TRACE(fmt...)
+
+	if (!strcmp(np->name, "smu-doorbell"))
+		trace = 1;
+
+	TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n",
+	      num_interrupt_controllers);
 
 	if (num_interrupt_controllers == 0) {
 		/*
@@ -345,11 +342,12 @@
 	}
 
 	ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+	TRACE("ints=%p, intlen=%d\n", ints, intlen);
 	if (ints == NULL)
 		return 0;
 	intrcells = prom_n_intr_cells(np);
 	intlen /= intrcells * sizeof(unsigned int);
-
+	TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen);
 	np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
 	if (!np->intrs)
 		return -ENOMEM;
@@ -360,6 +358,7 @@
 	intrcount = 0;
 	for (i = 0; i < intlen; ++i, ints += intrcells) {
 		n = map_interrupt(&irq, &ic, np, ints, intrcells);
+		TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n);
 		if (n <= 0)
 			continue;
 
@@ -370,6 +369,7 @@
 			np->intrs[intrcount].sense = map_isa_senses[sense];
 		} else {
 			virq = virt_irq_create_mapping(irq[0]);
+			TRACE("virq=%d\n", virq);
 #ifdef CONFIG_PPC64
 			if (virq == NO_IRQ) {
 				printk(KERN_CRIT "Could not allocate interrupt"
@@ -379,6 +379,12 @@
 #endif
 			np->intrs[intrcount].line = irq_offset_up(virq);
 			sense = (n > 1)? (irq[1] & 3): 1;
+
+			/* Apple uses bits in there in a different way, let's
+			 * only keep the real sense bit on macs
+			 */
+			if (_machine == PLATFORM_POWERMAC)
+				sense &= 0x1;
 			np->intrs[intrcount].sense = map_mpic_senses[sense];
 		}
 
@@ -388,12 +394,13 @@
 			char *name = get_property(ic->parent, "name", NULL);
 			if (name && !strcmp(name, "u3"))
 				np->intrs[intrcount].line += 128;
-			else if (!(name && !strcmp(name, "mac-io")))
+			else if (!(name && (!strcmp(name, "mac-io") ||
+					    !strcmp(name, "u4"))))
 				/* ignore other cascaded controllers, such as
 				   the k2-sata-root */
 				break;
 		}
-#endif
+#endif /* CONFIG_PPC64 */
 		if (n > 2) {
 			printk("hmmm, got %d intr cells for %s:", n,
 			       np->full_name);
@@ -408,234 +415,19 @@
 	return 0;
 }
 
-static int __devinit interpret_pci_props(struct device_node *np,
-					 unsigned long *mem_start,
-					 int naddrc, int nsizec,
-					 int measure_only)
-{
-	struct address_range *adr;
-	struct pci_reg_property *pci_addrs;
-	int i, l, n_addrs;
-
-	pci_addrs = (struct pci_reg_property *)
-		get_property(np, "assigned-addresses", &l);
-	if (!pci_addrs)
-		return 0;
-
-	n_addrs = l / sizeof(*pci_addrs);
-
-	adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
-	if (!adr)
-		return -ENOMEM;
-
- 	if (measure_only)
- 		return 0;
-
- 	np->addrs = adr;
- 	np->n_addrs = n_addrs;
-
- 	for (i = 0; i < n_addrs; i++) {
- 		adr[i].space = pci_addrs[i].addr.a_hi;
- 		adr[i].address = pci_addrs[i].addr.a_lo |
-			((u64)pci_addrs[i].addr.a_mid << 32);
- 		adr[i].size = pci_addrs[i].size_lo;
-	}
-
-	return 0;
-}
-
-static int __init interpret_dbdma_props(struct device_node *np,
-					unsigned long *mem_start,
-					int naddrc, int nsizec,
-					int measure_only)
-{
-	struct reg_property32 *rp;
-	struct address_range *adr;
-	unsigned long base_address;
-	int i, l;
-	struct device_node *db;
-
-	base_address = 0;
-	if (!measure_only) {
-		for (db = np->parent; db != NULL; db = db->parent) {
-			if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
-				base_address = db->addrs[0].address;
-				break;
-			}
-		}
-	}
-
-	rp = (struct reg_property32 *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct reg_property32)) {
-		i = 0;
-		adr = (struct address_range *) (*mem_start);
-		while ((l -= sizeof(struct reg_property32)) >= 0) {
-			if (!measure_only) {
-				adr[i].space = 2;
-				adr[i].address = rp[i].address + base_address;
-				adr[i].size = rp[i].size;
-			}
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		(*mem_start) += i * sizeof(struct address_range);
-	}
-
-	return 0;
-}
-
-static int __init interpret_macio_props(struct device_node *np,
-					unsigned long *mem_start,
-					int naddrc, int nsizec,
-					int measure_only)
-{
-	struct reg_property32 *rp;
-	struct address_range *adr;
-	unsigned long base_address;
-	int i, l;
-	struct device_node *db;
-
-	base_address = 0;
-	if (!measure_only) {
-		for (db = np->parent; db != NULL; db = db->parent) {
-			if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
-				base_address = db->addrs[0].address;
-				break;
-			}
-		}
-	}
-
-	rp = (struct reg_property32 *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct reg_property32)) {
-		i = 0;
-		adr = (struct address_range *) (*mem_start);
-		while ((l -= sizeof(struct reg_property32)) >= 0) {
-			if (!measure_only) {
-				adr[i].space = 2;
-				adr[i].address = rp[i].address + base_address;
-				adr[i].size = rp[i].size;
-			}
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		(*mem_start) += i * sizeof(struct address_range);
-	}
-
-	return 0;
-}
-
-static int __init interpret_isa_props(struct device_node *np,
-				      unsigned long *mem_start,
-				      int naddrc, int nsizec,
-				      int measure_only)
-{
-	struct isa_reg_property *rp;
-	struct address_range *adr;
-	int i, l;
-
-	rp = (struct isa_reg_property *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
-		i = 0;
-		adr = (struct address_range *) (*mem_start);
-		while ((l -= sizeof(struct isa_reg_property)) >= 0) {
-			if (!measure_only) {
-				adr[i].space = rp[i].space;
-				adr[i].address = rp[i].address;
-				adr[i].size = rp[i].size;
-			}
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		(*mem_start) += i * sizeof(struct address_range);
-	}
-
-	return 0;
-}
-
-static int __init interpret_root_props(struct device_node *np,
-				       unsigned long *mem_start,
-				       int naddrc, int nsizec,
-				       int measure_only)
-{
-	struct address_range *adr;
-	int i, l;
-	unsigned int *rp;
-	int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
-
-	rp = (unsigned int *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= rpsize) {
-		i = 0;
-		adr = (struct address_range *) (*mem_start);
-		while ((l -= rpsize) >= 0) {
-			if (!measure_only) {
-				adr[i].space = 0;
-				adr[i].address = rp[naddrc - 1];
-				adr[i].size = rp[naddrc + nsizec - 1];
-			}
-			++i;
-			rp += naddrc + nsizec;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		(*mem_start) += i * sizeof(struct address_range);
-	}
-
-	return 0;
-}
-
 static int __devinit finish_node(struct device_node *np,
 				 unsigned long *mem_start,
-				 interpret_func *ifunc,
-				 int naddrc, int nsizec,
 				 int measure_only)
 {
 	struct device_node *child;
-	int *ip, rc = 0;
-
-	/* get the device addresses and interrupts */
-	if (ifunc != NULL)
-		rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
-	if (rc)
-		goto out;
+	int rc = 0;
 
 	rc = finish_node_interrupts(np, mem_start, measure_only);
 	if (rc)
 		goto out;
 
-	/* Look for #address-cells and #size-cells properties. */
-	ip = (int *) get_property(np, "#address-cells", NULL);
-	if (ip != NULL)
-		naddrc = *ip;
-	ip = (int *) get_property(np, "#size-cells", NULL);
-	if (ip != NULL)
-		nsizec = *ip;
-
-	if (!strcmp(np->name, "device-tree") || np->parent == NULL)
-		ifunc = interpret_root_props;
-	else if (np->type == 0)
-		ifunc = NULL;
-	else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
-		ifunc = interpret_pci_props;
-	else if (!strcmp(np->type, "dbdma"))
-		ifunc = interpret_dbdma_props;
-	else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
-		ifunc = interpret_macio_props;
-	else if (!strcmp(np->type, "isa"))
-		ifunc = interpret_isa_props;
-	else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
-		ifunc = interpret_root_props;
-	else if (!((ifunc == interpret_dbdma_props
-		    || ifunc == interpret_macio_props)
-		   && (!strcmp(np->type, "escc")
-		       || !strcmp(np->type, "media-bay"))))
-		ifunc = NULL;
-
 	for (child = np->child; child != NULL; child = child->sibling) {
-		rc = finish_node(child, mem_start, ifunc,
-				 naddrc, nsizec, measure_only);
+		rc = finish_node(child, mem_start, measure_only);
 		if (rc)
 			goto out;
 	}
@@ -697,10 +489,10 @@
 	 * reason and then remove those additional 16 bytes
 	 */
 	size = 16;
-	finish_node(allnodes, &size, NULL, 0, 0, 1);
+	finish_node(allnodes, &size, 1);
 	size -= 16;
 	end = start = (unsigned long) __va(lmb_alloc(size, 128));
-	finish_node(allnodes, &end, NULL, 0, 0, 0);
+	finish_node(allnodes, &end, 0);
 	BUG_ON(end != start + size);
 
 	DBG(" <- finish_device_tree\n");
@@ -1197,6 +989,16 @@
 	}
 #endif /* CONFIG_PPC_RTAS */
 
+#ifdef CONFIG_KEXEC
+       lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL);
+       if (lprop)
+               crashk_res.start = *lprop;
+
+       lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL);
+       if (lprop)
+               crashk_res.end = crashk_res.start + *lprop - 1;
+#endif
+
 	/* break now */
 	return 1;
 }
@@ -1263,7 +1065,9 @@
 	} else if (strcmp(type, "memory") != 0)
 		return 0;
 
-	reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
+	reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l);
+	if (reg == NULL)
+		reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
 	if (reg == NULL)
 		return 0;
 
@@ -1335,11 +1139,14 @@
 	of_scan_flat_dt(early_init_dt_scan_memory, NULL);
 	lmb_enforce_memory_limit(memory_limit);
 	lmb_analyze();
-	lmb_reserve(0, __pa(klimit));
 
 	DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
 
 	/* Reserve LMB regions used by kernel, initrd, dt, etc... */
+	lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
+#ifdef CONFIG_CRASH_DUMP
+	lmb_reserve(0, KDUMP_RESERVE_LIMIT);
+#endif
 	early_reserve_mem();
 
 	DBG("Scanning CPUs ...\n");
@@ -1802,7 +1609,6 @@
 		prop = next;
 	}
 	kfree(node->intrs);
-	kfree(node->addrs);
 	kfree(node->full_name);
 	kfree(node->data);
 	kfree(node);
@@ -1884,9 +1690,7 @@
  * This should probably be split up into smaller chunks.
  */
 
-static int of_finish_dynamic_node(struct device_node *node,
-				  unsigned long *unused1, int unused2,
-				  int unused3, int unused4)
+static int of_finish_dynamic_node(struct device_node *node)
 {
 	struct device_node *parent = of_get_parent(node);
 	int err = 0;
@@ -1907,7 +1711,8 @@
 		return -ENODEV;
 
 	/* fix up new node's linux_phandle field */
-	if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
+	if ((ibm_phandle = (unsigned int *)get_property(node,
+							"ibm,phandle", NULL)))
 		node->linux_phandle = *ibm_phandle;
 
 out:
@@ -1922,7 +1727,9 @@
 
 	switch (action) {
 	case PSERIES_RECONFIG_ADD:
-		err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0);
+		err = of_finish_dynamic_node(node);
+		if (!err)
+			finish_node(node, NULL, 0);
 		if (err < 0) {
 			printk(KERN_ERR "finish_node returned %d\n", err);
 			err = NOTIFY_BAD;
@@ -1996,175 +1803,4 @@
 	return 0;
 }
 
-/* I quickly hacked that one, check against spec ! */
-static inline unsigned long
-bus_space_to_resource_flags(unsigned int bus_space)
-{
-	u8 space = (bus_space >> 24) & 0xf;
-	if (space == 0)
-		space = 0x02;
-	if (space == 0x02)
-		return IORESOURCE_MEM;
-	else if (space == 0x01)
-		return IORESOURCE_IO;
-	else {
-		printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
-		    	bus_space);
-		return 0;
-	}
-}
 
-#ifdef CONFIG_PCI
-static struct resource *find_parent_pci_resource(struct pci_dev* pdev,
-						 struct address_range *range)
-{
-	unsigned long mask;
-	int i;
-
-	/* Check this one */
-	mask = bus_space_to_resource_flags(range->space);
-	for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
-		if ((pdev->resource[i].flags & mask) == mask &&
-			pdev->resource[i].start <= range->address &&
-			pdev->resource[i].end > range->address) {
-				if ((range->address + range->size - 1) > pdev->resource[i].end) {
-					/* Add better message */
-					printk(KERN_WARNING "PCI/OF resource overlap !\n");
-					return NULL;
-				}
-				break;
-			}
-	}
-	if (i == DEVICE_COUNT_RESOURCE)
-		return NULL;
-	return &pdev->resource[i];
-}
-
-/*
- * Request an OF device resource. Currently handles child of PCI devices,
- * or other nodes attached to the root node. Ultimately, put some
- * link to resources in the OF node.
- */
-struct resource *request_OF_resource(struct device_node* node, int index,
-				     const char* name_postfix)
-{
-	struct pci_dev* pcidev;
-	u8 pci_bus, pci_devfn;
-	unsigned long iomask;
-	struct device_node* nd;
-	struct resource* parent;
-	struct resource *res = NULL;
-	int nlen, plen;
-
-	if (index >= node->n_addrs)
-		goto fail;
-
-	/* Sanity check on bus space */
-	iomask = bus_space_to_resource_flags(node->addrs[index].space);
-	if (iomask & IORESOURCE_MEM)
-		parent = &iomem_resource;
-	else if (iomask & IORESOURCE_IO)
-		parent = &ioport_resource;
-	else
-		goto fail;
-
-	/* Find a PCI parent if any */
-	nd = node;
-	pcidev = NULL;
-	while (nd) {
-		if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
-			pcidev = pci_find_slot(pci_bus, pci_devfn);
-		if (pcidev) break;
-		nd = nd->parent;
-	}
-	if (pcidev)
-		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
-	if (!parent) {
-		printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
-			node->name);
-		goto fail;
-	}
-
-	res = __request_region(parent, node->addrs[index].address,
-			       node->addrs[index].size, NULL);
-	if (!res)
-		goto fail;
-	nlen = strlen(node->name);
-	plen = name_postfix ? strlen(name_postfix) : 0;
-	res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
-	if (res->name) {
-		strcpy((char *)res->name, node->name);
-		if (plen)
-			strcpy((char *)res->name+nlen, name_postfix);
-	}
-	return res;
-fail:
-	return NULL;
-}
-EXPORT_SYMBOL(request_OF_resource);
-
-int release_OF_resource(struct device_node *node, int index)
-{
-	struct pci_dev* pcidev;
-	u8 pci_bus, pci_devfn;
-	unsigned long iomask, start, end;
-	struct device_node* nd;
-	struct resource* parent;
-	struct resource *res = NULL;
-
-	if (index >= node->n_addrs)
-		return -EINVAL;
-
-	/* Sanity check on bus space */
-	iomask = bus_space_to_resource_flags(node->addrs[index].space);
-	if (iomask & IORESOURCE_MEM)
-		parent = &iomem_resource;
-	else if (iomask & IORESOURCE_IO)
-		parent = &ioport_resource;
-	else
-		return -EINVAL;
-
-	/* Find a PCI parent if any */
-	nd = node;
-	pcidev = NULL;
-	while(nd) {
-		if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
-			pcidev = pci_find_slot(pci_bus, pci_devfn);
-		if (pcidev) break;
-		nd = nd->parent;
-	}
-	if (pcidev)
-		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
-	if (!parent) {
-		printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
-			node->name);
-		return -ENODEV;
-	}
-
-	/* Find us in the parent and its childs */
-	res = parent->child;
-	start = node->addrs[index].address;
-	end = start + node->addrs[index].size - 1;
-	while (res) {
-		if (res->start == start && res->end == end &&
-		    (res->flags & IORESOURCE_BUSY))
-		    	break;
-		if (res->start <= start && res->end >= end)
-			res = res->child;
-		else
-			res = res->sibling;
-	}
-	if (!res)
-		return -ENODEV;
-
-	if (res->name) {
-		kfree(res->name);
-		res->name = NULL;
-	}
-	release_resource(res);
-	kfree(res);
-
-	return 0;
-}
-EXPORT_SYMBOL(release_OF_resource);
-#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index bcdc209..e381f2f 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -192,6 +192,11 @@
 static unsigned long __initdata rmo_top;
 static unsigned long __initdata ram_top;
 
+#ifdef CONFIG_KEXEC
+static unsigned long __initdata prom_crashk_base;
+static unsigned long __initdata prom_crashk_size;
+#endif
+
 static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
 static int __initdata mem_reserve_cnt;
 
@@ -553,7 +558,8 @@
 static void __init early_cmdline_parse(void)
 {
 	struct prom_t *_prom = &RELOC(prom);
-	char *opt, *p;
+	const char *opt;
+	char *p;
 	int l = 0;
 
 	RELOC(prom_cmd_line[0]) = 0;
@@ -590,6 +596,34 @@
 		RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
 #endif
 	}
+
+#ifdef CONFIG_KEXEC
+	/*
+	 * crashkernel=size@addr specifies the location to reserve for
+	 * crash kernel.
+	 */
+	opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel="));
+	if (opt) {
+		opt += 12;
+		RELOC(prom_crashk_size) = prom_memparse(opt, &opt);
+
+		if (ALIGN(RELOC(prom_crashk_size), 0x1000000) !=
+			RELOC(prom_crashk_size)) {
+			prom_printf("Warning: crashkernel size is not "
+					"aligned to 16MB\n");
+		}
+
+		/*
+		 * At present, the crash kernel always run at 32MB.
+		 * Just ignore whatever user passed.
+		 */
+		RELOC(prom_crashk_base) = 0x2000000;
+		if (*opt == '@') {
+			prom_printf("Warning: PPC64 kdump kernel always runs "
+					"at 32 MB\n");
+		}
+	}
+#endif
 }
 
 #ifdef CONFIG_PPC_PSERIES
@@ -1011,6 +1045,12 @@
 	prom_printf("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
 	prom_printf("  rmo_top      : %x\n", RELOC(rmo_top));
 	prom_printf("  ram_top      : %x\n", RELOC(ram_top));
+#ifdef CONFIG_KEXEC
+	if (RELOC(prom_crashk_base)) {
+		prom_printf("  crashk_base  : %x\n",  RELOC(prom_crashk_base));
+		prom_printf("  crashk_size  : %x\n", RELOC(prom_crashk_size));
+	}
+#endif
 }
 
 
@@ -1500,6 +1540,8 @@
 #ifdef CONFIG_PPC64
 			if (strstr(p, RELOC("Momentum,Maple")))
 				return PLATFORM_MAPLE;
+			if (strstr(p, RELOC("IBM,CPB")))
+				return PLATFORM_CELL;
 #endif
 			i += sl + 1;
 		}
@@ -1994,7 +2036,7 @@
 	if (r3 && r4 && r4 != 0xdeadbeef) {
 		unsigned long val;
 
-		RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3;
+		RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3;
 		RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
 
 		val = RELOC(prom_initrd_start);
@@ -2094,6 +2136,10 @@
 	 */
 	prom_init_mem();
 
+#ifdef CONFIG_KEXEC
+	if (RELOC(prom_crashk_base))
+		reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size));
+#endif
 	/*
 	 * Determine which cpu is actually running right _now_
 	 */
@@ -2150,6 +2196,16 @@
 	}
 #endif
 
+#ifdef CONFIG_KEXEC
+	if (RELOC(prom_crashk_base)) {
+		prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base",
+			PTRRELOC(&prom_crashk_base),
+			sizeof(RELOC(prom_crashk_base)));
+		prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size",
+			PTRRELOC(&prom_crashk_size),
+			sizeof(RELOC(prom_crashk_size)));
+	}
+#endif
 	/*
 	 * Fixup any known bugs in the device-tree
 	 */
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
new file mode 100644
index 0000000..309ae1d
--- /dev/null
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -0,0 +1,547 @@
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/pci_regs.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+#ifdef CONFIG_PPC64
+#define PRu64	"%lx"
+#else
+#define PRu64	"%llx"
+#endif
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS	4
+#define OF_CHECK_COUNTS(na, ns)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
+			(ns) > 0)
+
+/* Debug utility */
+#ifdef DEBUG
+static void of_dump_addr(const char *s, u32 *addr, int na)
+{
+	printk("%s", s);
+	while(na--)
+		printk(" %08x", *(addr++));
+	printk("\n");
+}
+#else
+static void of_dump_addr(const char *s, u32 *addr, int na) { }
+#endif
+
+/* Read a big address */
+static inline u64 of_read_addr(u32 *cell, int size)
+{
+	u64 r = 0;
+	while (size--)
+		r = (r << 32) | *(cell++);
+	return r;
+}
+
+/* Callbacks for bus specific translators */
+struct of_bus {
+	const char	*name;
+	const char	*addresses;
+	int		(*match)(struct device_node *parent);
+	void		(*count_cells)(struct device_node *child,
+				       int *addrc, int *sizec);
+	u64		(*map)(u32 *addr, u32 *range, int na, int ns, int pna);
+	int		(*translate)(u32 *addr, u64 offset, int na);
+	unsigned int	(*get_flags)(u32 *addr);
+};
+
+
+/*
+ * Default translator (generic bus)
+ */
+
+static void of_bus_default_count_cells(struct device_node *dev,
+				       int *addrc, int *sizec)
+{
+	if (addrc)
+		*addrc = prom_n_addr_cells(dev);
+	if (sizec)
+		*sizec = prom_n_size_cells(dev);
+}
+
+static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+	u64 cp, s, da;
+
+	cp = of_read_addr(range, na);
+	s  = of_read_addr(range + na + pna, ns);
+	da = of_read_addr(addr, na);
+
+	DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
+	    cp, s, da);
+
+	if (da < cp || da >= (cp + s))
+		return OF_BAD_ADDR;
+	return da - cp;
+}
+
+static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+	u64 a = of_read_addr(addr, na);
+	memset(addr, 0, na * 4);
+	a += offset;
+	if (na > 1)
+		addr[na - 2] = a >> 32;
+	addr[na - 1] = a & 0xffffffffu;
+
+	return 0;
+}
+
+static unsigned int of_bus_default_get_flags(u32 *addr)
+{
+	return IORESOURCE_MEM;
+}
+
+
+/*
+ * PCI bus specific translator
+ */
+
+static int of_bus_pci_match(struct device_node *np)
+{
+	return !strcmp(np->type, "pci");
+}
+
+static void of_bus_pci_count_cells(struct device_node *np,
+				   int *addrc, int *sizec)
+{
+	if (addrc)
+		*addrc = 3;
+	if (sizec)
+		*sizec = 2;
+}
+
+static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+	u64 cp, s, da;
+
+	/* Check address type match */
+	if ((addr[0] ^ range[0]) & 0x03000000)
+		return OF_BAD_ADDR;
+
+	/* Read address values, skipping high cell */
+	cp = of_read_addr(range + 1, na - 1);
+	s  = of_read_addr(range + na + pna, ns);
+	da = of_read_addr(addr + 1, na - 1);
+
+	DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
+
+	if (da < cp || da >= (cp + s))
+		return OF_BAD_ADDR;
+	return da - cp;
+}
+
+static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+	return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_pci_get_flags(u32 *addr)
+{
+	unsigned int flags = 0;
+	u32 w = addr[0];
+
+	switch((w >> 24) & 0x03) {
+	case 0x01:
+		flags |= IORESOURCE_IO;
+	case 0x02: /* 32 bits */
+	case 0x03: /* 64 bits */
+		flags |= IORESOURCE_MEM;
+	}
+	if (w & 0x40000000)
+		flags |= IORESOURCE_PREFETCH;
+	return flags;
+}
+
+/*
+ * ISA bus specific translator
+ */
+
+static int of_bus_isa_match(struct device_node *np)
+{
+	return !strcmp(np->name, "isa");
+}
+
+static void of_bus_isa_count_cells(struct device_node *child,
+				   int *addrc, int *sizec)
+{
+	if (addrc)
+		*addrc = 2;
+	if (sizec)
+		*sizec = 1;
+}
+
+static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+	u64 cp, s, da;
+
+	/* Check address type match */
+	if ((addr[0] ^ range[0]) & 0x00000001)
+		return OF_BAD_ADDR;
+
+	/* Read address values, skipping high cell */
+	cp = of_read_addr(range + 1, na - 1);
+	s  = of_read_addr(range + na + pna, ns);
+	da = of_read_addr(addr + 1, na - 1);
+
+	DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
+
+	if (da < cp || da >= (cp + s))
+		return OF_BAD_ADDR;
+	return da - cp;
+}
+
+static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
+{
+	return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_isa_get_flags(u32 *addr)
+{
+	unsigned int flags = 0;
+	u32 w = addr[0];
+
+	if (w & 1)
+		flags |= IORESOURCE_IO;
+	else
+		flags |= IORESOURCE_MEM;
+	return flags;
+}
+
+
+/*
+ * Array of bus specific translators
+ */
+
+static struct of_bus of_busses[] = {
+	/* PCI */
+	{
+		.name = "pci",
+		.addresses = "assigned-addresses",
+		.match = of_bus_pci_match,
+		.count_cells = of_bus_pci_count_cells,
+		.map = of_bus_pci_map,
+		.translate = of_bus_pci_translate,
+		.get_flags = of_bus_pci_get_flags,
+	},
+	/* ISA */
+	{
+		.name = "isa",
+		.addresses = "reg",
+		.match = of_bus_isa_match,
+		.count_cells = of_bus_isa_count_cells,
+		.map = of_bus_isa_map,
+		.translate = of_bus_isa_translate,
+		.get_flags = of_bus_isa_get_flags,
+	},
+	/* Default */
+	{
+		.name = "default",
+		.addresses = "reg",
+		.match = NULL,
+		.count_cells = of_bus_default_count_cells,
+		.map = of_bus_default_map,
+		.translate = of_bus_default_translate,
+		.get_flags = of_bus_default_get_flags,
+	},
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
+		if (!of_busses[i].match || of_busses[i].match(np))
+			return &of_busses[i];
+	BUG();
+	return NULL;
+}
+
+static int of_translate_one(struct device_node *parent, struct of_bus *bus,
+			    struct of_bus *pbus, u32 *addr,
+			    int na, int ns, int pna)
+{
+	u32 *ranges;
+	unsigned int rlen;
+	int rone;
+	u64 offset = OF_BAD_ADDR;
+
+	/* Normally, an absence of a "ranges" property means we are
+	 * crossing a non-translatable boundary, and thus the addresses
+	 * below the current not cannot be converted to CPU physical ones.
+	 * Unfortunately, while this is very clear in the spec, it's not
+	 * what Apple understood, and they do have things like /uni-n or
+	 * /ht nodes with no "ranges" property and a lot of perfectly
+	 * useable mapped devices below them. Thus we treat the absence of
+	 * "ranges" as equivalent to an empty "ranges" property which means
+	 * a 1:1 translation at that level. It's up to the caller not to try
+	 * to translate addresses that aren't supposed to be translated in
+	 * the first place. --BenH.
+	 */
+	ranges = (u32 *)get_property(parent, "ranges", &rlen);
+	if (ranges == NULL || rlen == 0) {
+		offset = of_read_addr(addr, na);
+		memset(addr, 0, pna * 4);
+		DBG("OF: no ranges, 1:1 translation\n");
+		goto finish;
+	}
+
+	DBG("OF: walking ranges...\n");
+
+	/* Now walk through the ranges */
+	rlen /= 4;
+	rone = na + pna + ns;
+	for (; rlen >= rone; rlen -= rone, ranges += rone) {
+		offset = bus->map(addr, ranges, na, ns, pna);
+		if (offset != OF_BAD_ADDR)
+			break;
+	}
+	if (offset == OF_BAD_ADDR) {
+		DBG("OF: not found !\n");
+		return 1;
+	}
+	memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+	of_dump_addr("OF: parent translation for:", addr, pna);
+	DBG("OF: with offset: "PRu64"\n", offset);
+
+	/* Translate it into parent bus space */
+	return pbus->translate(addr, offset, pna);
+}
+
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+u64 of_translate_address(struct device_node *dev, u32 *in_addr)
+{
+	struct device_node *parent = NULL;
+	struct of_bus *bus, *pbus;
+	u32 addr[OF_MAX_ADDR_CELLS];
+	int na, ns, pna, pns;
+	u64 result = OF_BAD_ADDR;
+
+	DBG("OF: ** translation for device %s **\n", dev->full_name);
+
+	/* Increase refcount at current level */
+	of_node_get(dev);
+
+	/* Get parent & match bus type */
+	parent = of_get_parent(dev);
+	if (parent == NULL)
+		goto bail;
+	bus = of_match_bus(parent);
+
+	/* Cound address cells & copy address locally */
+	bus->count_cells(dev, &na, &ns);
+	if (!OF_CHECK_COUNTS(na, ns)) {
+		printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+		       dev->full_name);
+		goto bail;
+	}
+	memcpy(addr, in_addr, na * 4);
+
+	DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
+	    bus->name, na, ns, parent->full_name);
+	of_dump_addr("OF: translating address:", addr, na);
+
+	/* Translate */
+	for (;;) {
+		/* Switch to parent bus */
+		of_node_put(dev);
+		dev = parent;
+		parent = of_get_parent(dev);
+
+		/* If root, we have finished */
+		if (parent == NULL) {
+			DBG("OF: reached root node\n");
+			result = of_read_addr(addr, na);
+			break;
+		}
+
+		/* Get new parent bus and counts */
+		pbus = of_match_bus(parent);
+		pbus->count_cells(dev, &pna, &pns);
+		if (!OF_CHECK_COUNTS(pna, pns)) {
+			printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+			       dev->full_name);
+			break;
+		}
+
+		DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
+		    pbus->name, pna, pns, parent->full_name);
+
+		/* Apply bus translation */
+		if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
+			break;
+
+		/* Complete the move up one level */
+		na = pna;
+		ns = pns;
+		bus = pbus;
+
+		of_dump_addr("OF: one level translation:", addr, na);
+	}
+ bail:
+	of_node_put(parent);
+	of_node_put(dev);
+
+	return result;
+}
+EXPORT_SYMBOL(of_translate_address);
+
+u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+		    unsigned int *flags)
+{
+	u32 *prop;
+	unsigned int psize;
+	struct device_node *parent;
+	struct of_bus *bus;
+	int onesize, i, na, ns;
+
+	/* Get parent & match bus type */
+	parent = of_get_parent(dev);
+	if (parent == NULL)
+		return NULL;
+	bus = of_match_bus(parent);
+	bus->count_cells(dev, &na, &ns);
+	of_node_put(parent);
+	if (!OF_CHECK_COUNTS(na, ns))
+		return NULL;
+
+	/* Get "reg" or "assigned-addresses" property */
+	prop = (u32 *)get_property(dev, bus->addresses, &psize);
+	if (prop == NULL)
+		return NULL;
+	psize /= 4;
+
+	onesize = na + ns;
+	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+		if (i == index) {
+			if (size)
+				*size = of_read_addr(prop + na, ns);
+			if (flags)
+				*flags = bus->get_flags(prop);
+			return prop;
+		}
+	return NULL;
+}
+EXPORT_SYMBOL(of_get_address);
+
+u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+			unsigned int *flags)
+{
+	u32 *prop;
+	unsigned int psize;
+	struct device_node *parent;
+	struct of_bus *bus;
+	int onesize, i, na, ns;
+
+	/* Get parent & match bus type */
+	parent = of_get_parent(dev);
+	if (parent == NULL)
+		return NULL;
+	bus = of_match_bus(parent);
+	if (strcmp(bus->name, "pci"))
+		return NULL;
+	bus->count_cells(dev, &na, &ns);
+	of_node_put(parent);
+	if (!OF_CHECK_COUNTS(na, ns))
+		return NULL;
+
+	/* Get "reg" or "assigned-addresses" property */
+	prop = (u32 *)get_property(dev, bus->addresses, &psize);
+	if (prop == NULL)
+		return NULL;
+	psize /= 4;
+
+	onesize = na + ns;
+	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+		if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
+			if (size)
+				*size = of_read_addr(prop + na, ns);
+			if (flags)
+				*flags = bus->get_flags(prop);
+			return prop;
+		}
+	return NULL;
+}
+EXPORT_SYMBOL(of_get_pci_address);
+
+static int __of_address_to_resource(struct device_node *dev, u32 *addrp,
+				    u64 size, unsigned int flags,
+				    struct resource *r)
+{
+	u64 taddr;
+
+	if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
+		return -EINVAL;
+	taddr = of_translate_address(dev, addrp);
+	if (taddr == OF_BAD_ADDR)
+		return -EINVAL;
+	memset(r, 0, sizeof(struct resource));
+	if (flags & IORESOURCE_IO) {
+		unsigned long port;
+		port = pci_address_to_pio(taddr);
+		if (port == (unsigned long)-1)
+			return -EINVAL;
+		r->start = port;
+		r->end = port + size - 1;
+	} else {
+		r->start = taddr;
+		r->end = taddr + size - 1;
+	}
+	r->flags = flags;
+	r->name = dev->name;
+	return 0;
+}
+
+int of_address_to_resource(struct device_node *dev, int index,
+			   struct resource *r)
+{
+	u32		*addrp;
+	u64		size;
+	unsigned int	flags;
+
+	addrp = of_get_address(dev, index, &size, &flags);
+	if (addrp == NULL)
+		return -EINVAL;
+	return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_address_to_resource);
+
+int of_pci_address_to_resource(struct device_node *dev, int bar,
+			       struct resource *r)
+{
+	u32		*addrp;
+	u64		size;
+	unsigned int	flags;
+
+	addrp = of_get_pci_address(dev, bar, &size, &flags);
+	if (addrp == NULL)
+		return -EINVAL;
+	return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 60dec24..45b8109 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -188,39 +188,19 @@
 	return 0;
 }
 
-static int get_phb_reg_prop(struct device_node *dev,
-			    unsigned int addr_size_words,
-			    struct reg_property64 *reg)
+static void python_countermeasures(struct device_node *dev)
 {
-	unsigned int *ui_ptr = NULL, len;
-
-	/* Found a PHB, now figure out where his registers are mapped. */
-	ui_ptr = (unsigned int *)get_property(dev, "reg", &len);
-	if (ui_ptr == NULL)
-		return 1;
-
-	if (addr_size_words == 1) {
-		reg->address = ((struct reg_property32 *)ui_ptr)->address;
-		reg->size    = ((struct reg_property32 *)ui_ptr)->size;
-	} else {
-		*reg = *((struct reg_property64 *)ui_ptr);
-	}
-
-	return 0;
-}
-
-static void python_countermeasures(struct device_node *dev,
-				   unsigned int addr_size_words)
-{
-	struct reg_property64 reg_struct;
+	struct resource registers;
 	void __iomem *chip_regs;
 	volatile u32 val;
 
-	if (get_phb_reg_prop(dev, addr_size_words, &reg_struct))
+	if (of_address_to_resource(dev, 0, &registers)) {
+		printk(KERN_ERR "Can't get address for Python workarounds !\n");
 		return;
+	}
 
 	/* Python's register file is 1 MB in size. */
-	chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000);
+	chip_regs = ioremap(registers.start & ~(0xfffffUL), 0x100000);
 
 	/*
 	 * Firmware doesn't always clear this bit which is critical
@@ -301,11 +281,10 @@
 }
 
 static int __devinit setup_phb(struct device_node *dev,
-			       struct pci_controller *phb,
-			       unsigned int addr_size_words)
+			       struct pci_controller *phb)
 {
 	if (is_python(dev))
-		python_countermeasures(dev, addr_size_words);
+		python_countermeasures(dev);
 
 	if (phb_set_bus_ranges(dev, phb))
 		return 1;
@@ -320,8 +299,8 @@
 {
 	struct device_node *node;
 	struct pci_controller *phb;
-	unsigned int root_size_cells = 0;
 	unsigned int index;
+	unsigned int root_size_cells = 0;
 	unsigned int *opprop = NULL;
 	struct device_node *root = of_find_node_by_path("/");
 
@@ -343,10 +322,11 @@
 		phb = pcibios_alloc_controller(node);
 		if (!phb)
 			continue;
-		setup_phb(node, phb, root_size_cells);
+		setup_phb(node, phb);
 		pci_process_bridge_OF_ranges(phb, node, 0);
 		pci_setup_phb_io(phb, index == 0);
 #ifdef CONFIG_PPC_PSERIES
+		/* XXX This code need serious fixing ... --BenH */
 		if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) {
 			int addr = root_size_cells * (index + 2) - 1;
 			mpic_assign_isu(pSeries_mpic, index, opprop[addr]);
@@ -381,22 +361,17 @@
 
 struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
 {
-	struct device_node *root = of_find_node_by_path("/");
-	unsigned int root_size_cells = 0;
 	struct pci_controller *phb;
 	int primary;
 
-	root_size_cells = prom_n_size_cells(root);
-
 	primary = list_empty(&hose_list);
 	phb = pcibios_alloc_controller(dn);
 	if (!phb)
 		return NULL;
-	setup_phb(dn, phb, root_size_cells);
+	setup_phb(dn, phb);
 	pci_process_bridge_OF_ranges(phb, dn, primary);
 
 	pci_setup_phb_io_dynamic(phb, primary);
-	of_node_put(root);
 
 	pci_devs_phb_init_dynamic(phb);
 	scan_phb(phb);
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index bd3eb42..d5c52fa 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -93,8 +93,8 @@
 /* also used by kexec */
 void machine_shutdown(void)
 {
-	if (ppc_md.nvram_sync)
-		ppc_md.nvram_sync();
+	if (ppc_md.machine_shutdown)
+		ppc_md.machine_shutdown();
 }
 
 void machine_restart(char *cmd)
@@ -294,129 +294,6 @@
 	.show =	show_cpuinfo,
 };
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
-static int __init set_preferred_console(void)
-{
-	struct device_node *prom_stdout = NULL;
-	char *name;
-	u32 *spd;
-	int offset = 0;
-
-	DBG(" -> set_preferred_console()\n");
-
-	/* The user has requested a console so this is already set up. */
-	if (strstr(saved_command_line, "console=")) {
-		DBG(" console was specified !\n");
-		return -EBUSY;
-	}
-
-	if (!of_chosen) {
-		DBG(" of_chosen is NULL !\n");
-		return -ENODEV;
-	}
-	/* We are getting a weird phandle from OF ... */
-	/* ... So use the full path instead */
-	name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
-	if (name == NULL) {
-		DBG(" no linux,stdout-path !\n");
-		return -ENODEV;
-	}
-	prom_stdout = of_find_node_by_path(name);
-	if (!prom_stdout) {
-		DBG(" can't find stdout package %s !\n", name);
-		return -ENODEV;
-	}	
-	DBG("stdout is %s\n", prom_stdout->full_name);
-
-	name = (char *)get_property(prom_stdout, "name", NULL);
-	if (!name) {
-		DBG(" stdout package has no name !\n");
-		goto not_found;
-	}
-	spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
-
-	if (0)
-		;
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-	else if (strcmp(name, "serial") == 0) {
-		int i;
-		u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
-		if (i > 8) {
-			switch (reg[1]) {
-				case 0x3f8:
-					offset = 0;
-					break;
-				case 0x2f8:
-					offset = 1;
-					break;
-				case 0x898:
-					offset = 2;
-					break;
-				case 0x890:
-					offset = 3;
-					break;
-				default:
-					/* We dont recognise the serial port */
-					goto not_found;
-			}
-		}
-	}
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-#ifdef CONFIG_PPC_PSERIES
-	else if (strcmp(name, "vty") == 0) {
- 		u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL);
- 		char *compat = (char *)get_property(prom_stdout, "compatible", NULL);
-
- 		if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) {
- 			/* Host Virtual Serial Interface */
- 			switch (reg[0]) {
- 				case 0x30000000:
- 					offset = 0;
- 					break;
- 				case 0x30000001:
- 					offset = 1;
- 					break;
- 				default:
-					goto not_found;
- 			}
-			of_node_put(prom_stdout);
-			DBG("Found hvsi console at offset %d\n", offset);
- 			return add_preferred_console("hvsi", offset, NULL);
- 		} else {
- 			/* pSeries LPAR virtual console */
-			of_node_put(prom_stdout);
-			DBG("Found hvc console\n");
- 			return add_preferred_console("hvc", 0, NULL);
- 		}
-	}
-#endif /* CONFIG_PPC_PSERIES */
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
-	else if (strcmp(name, "ch-a") == 0)
-		offset = 0;
-	else if (strcmp(name, "ch-b") == 0)
-		offset = 1;
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-	else
-		goto not_found;
-	of_node_put(prom_stdout);
-
-	DBG("Found serial console at ttyS%d\n", offset);
-
-	if (spd) {
-		static char __initdata opt[16];
-		sprintf(opt, "%d", *spd);
-		return add_preferred_console("ttyS", offset, opt);
-	} else
-		return add_preferred_console("ttyS", offset, NULL);
-
- not_found:
-	DBG("No preferred console found !\n");
-	of_node_put(prom_stdout);
-	return -ENODEV;
-}
-console_initcall(set_preferred_console);
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
 void __init check_for_initrd(void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -442,7 +319,7 @@
 	/* If we were passed an initrd, set the ROOT_DEV properly if the values
 	 * look sensible. If not, clear initrd reference.
 	 */
-	if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
+	if (is_kernel_addr(initrd_start) && is_kernel_addr(initrd_end) &&
 	    initrd_end > initrd_start)
 		ROOT_DEV = Root_RAM0;
 	else
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index e569433..e5d285a 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -39,6 +39,8 @@
 #include <asm/nvram.h>
 #include <asm/xmon.h>
 #include <asm/time.h>
+#include <asm/serial.h>
+#include <asm/udbg.h>
 
 #include "setup.h"
 
@@ -172,12 +174,23 @@
  */
 void __init machine_init(unsigned long dt_ptr, unsigned long phys)
 {
+	/* If btext is enabled, we might have a BAT setup for early display,
+	 * thus we do enable some very basic udbg output
+	 */
+#ifdef CONFIG_BOOTX_TEXT
+	udbg_putc = btext_drawchar;
+#endif
+
+	/* Do some early initialization based on the flat device tree */
 	early_init_devtree(__va(dt_ptr));
 
+	/* Check default command line */
 #ifdef CONFIG_CMDLINE
-	strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
+	if (cmd_line[0] == 0)
+		strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
 #endif /* CONFIG_CMDLINE */
 
+	/* Base init based on machine type */
 	platform_init();
 
 #ifdef CONFIG_6xx
@@ -282,25 +295,22 @@
 
 	unflatten_device_tree();
 	check_for_initrd();
+
+	if (ppc_md.init_early)
+		ppc_md.init_early();
+
+#ifdef CONFIG_SERIAL_8250
+	find_legacy_serial_ports();
+#endif
 	finish_device_tree();
 
 	smp_setup_cpu_maps();
 
-#ifdef CONFIG_BOOTX_TEXT
-	init_boot_display();
-#endif
-
-#ifdef CONFIG_PPC_PMAC
-	/* This could be called "early setup arch", it must be done
-	 * now because xmon need it
-	 */
-	if (_machine == _MACH_Pmac)
-		pmac_feature_init();	/* New cool way */
-#endif
-
 #ifdef CONFIG_XMON_DEFAULT
 	xmon_init(1);
 #endif
+	/* Register early console */
+	register_early_udbg_console();
 
 #if defined(CONFIG_KGDB)
 	if (ppc_md.kgdb_map_scc)
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index e3fb783..98e9f05 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -34,6 +34,7 @@
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <asm/io.h>
+#include <asm/kdump.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
@@ -268,6 +269,10 @@
 	}
 	ppc_md = **mach;
 
+#ifdef CONFIG_CRASH_DUMP
+	kdump_setup();
+#endif
+
 	DBG("Found, Initializing memory management...\n");
 
 	/*
@@ -317,6 +322,7 @@
 void smp_release_cpus(void)
 {
 	extern unsigned long __secondary_hold_spinloop;
+	unsigned long *ptr;
 
 	DBG(" -> smp_release_cpus()\n");
 
@@ -327,7 +333,9 @@
 	 * This is useless but harmless on iSeries, secondaries are already
 	 * waiting on their paca spinloops. */
 
-	__secondary_hold_spinloop = 1;
+	ptr  = (unsigned long *)((unsigned long)&__secondary_hold_spinloop
+			- PHYSICAL_START);
+	*ptr = 1;
 	mb();
 
 	DBG(" <- smp_release_cpus()\n");
@@ -459,16 +467,21 @@
 	 */
 	ppc_md.init_early();
 
+ 	/*
+	 * We can discover serial ports now since the above did setup the
+	 * hash table management for us, thus ioremap works. We do that early
+	 * so that further code can be debugged
+	 */
+#ifdef CONFIG_SERIAL_8250
+	find_legacy_serial_ports();
+#endif
+
 	/*
 	 * "Finish" the device-tree, that is do the actual parsing of
 	 * some of the properties like the interrupt map
 	 */
 	finish_device_tree();
 
-#ifdef CONFIG_BOOTX_TEXT
-	init_boot_display();
-#endif
-
 	/*
 	 * Initialize xmon
 	 */
@@ -507,6 +520,9 @@
 	       ppc64_caches.iline_size);
 	printk("htab_address                  = 0x%p\n", htab_address);
 	printk("htab_hash_mask                = 0x%lx\n", htab_hash_mask);
+#if PHYSICAL_START > 0
+	printk("physical_start                = 0x%x\n", PHYSICAL_START);
+#endif
 	printk("-----------------------------------------------------\n");
 
 	mm_init_ppc64();
@@ -657,187 +673,6 @@
 	printk("[terminate]%04x %s\n", src, msg);
 }
 
-#ifndef CONFIG_PPC_ISERIES
-/*
- * This function can be used by platforms to "find" legacy serial ports.
- * It works for "serial" nodes under an "isa" node, and will try to
- * respect the "ibm,aix-loc" property if any. It works with up to 8
- * ports.
- */
-
-#define MAX_LEGACY_SERIAL_PORTS	8
-static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1];
-static unsigned int old_serial_count;
-
-void __init generic_find_legacy_serial_ports(u64 *physport,
-		unsigned int *default_speed)
-{
-	struct device_node *np;
-	u32 *sizeprop;
-
-	struct isa_reg_property {
-		u32 space;
-		u32 address;
-		u32 size;
-	};
-	struct pci_reg_property {
-		struct pci_address addr;
-		u32 size_hi;
-		u32 size_lo;
-	};                                                                        
-
-	DBG(" -> generic_find_legacy_serial_port()\n");
-
-	*physport = 0;
-	if (default_speed)
-		*default_speed = 0;
-
-	np = of_find_node_by_path("/");
-	if (!np)
-		return;
-
-	/* First fill our array */
-	for (np = NULL; (np = of_find_node_by_type(np, "serial"));) {
-		struct device_node *isa, *pci;
-		struct isa_reg_property *reg;
-		unsigned long phys_size, addr_size, io_base;
-		u32 *rangesp;
-		u32 *interrupts, *clk, *spd;
-		char *typep;
-		int index, rlen, rentsize;
-
-		/* Ok, first check if it's under an "isa" parent */
-		isa = of_get_parent(np);
-		if (!isa || strcmp(isa->name, "isa")) {
-			DBG("%s: no isa parent found\n", np->full_name);
-			continue;
-		}
-		
-		/* Now look for an "ibm,aix-loc" property that gives us ordering
-		 * if any...
-		 */
-	 	typep = (char *)get_property(np, "ibm,aix-loc", NULL);
-
-		/* Get the ISA port number */
-		reg = (struct isa_reg_property *)get_property(np, "reg", NULL);	
-		if (reg == NULL)
-			goto next_port;
-		/* We assume the interrupt number isn't translated ... */
-		interrupts = (u32 *)get_property(np, "interrupts", NULL);
-		/* get clock freq. if present */
-		clk = (u32 *)get_property(np, "clock-frequency", NULL);
-		/* get default speed if present */
-		spd = (u32 *)get_property(np, "current-speed", NULL);
-		/* Default to locate at end of array */
-		index = old_serial_count; /* end of the array by default */
-
-		/* If we have a location index, then use it */
-		if (typep && *typep == 'S') {
-			index = simple_strtol(typep+1, NULL, 0) - 1;
-			/* if index is out of range, use end of array instead */
-			if (index >= MAX_LEGACY_SERIAL_PORTS)
-				index = old_serial_count;
-			/* if our index is still out of range, that mean that
-			 * array is full, we could scan for a free slot but that
-			 * make little sense to bother, just skip the port
-			 */
-			if (index >= MAX_LEGACY_SERIAL_PORTS)
-				goto next_port;
-			if (index >= old_serial_count)
-				old_serial_count = index + 1;
-			/* Check if there is a port who already claimed our slot */
-			if (serial_ports[index].iobase != 0) {
-				/* if we still have some room, move it, else override */
-				if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) {
-					DBG("Moved legacy port %d -> %d\n", index,
-					    old_serial_count);
-					serial_ports[old_serial_count++] =
-						serial_ports[index];
-				} else {
-					DBG("Replacing legacy port %d\n", index);
-				}
-			}
-		}
-		if (index >= MAX_LEGACY_SERIAL_PORTS)
-			goto next_port;
-		if (index >= old_serial_count)
-			old_serial_count = index + 1;
-
-		/* Now fill the entry */
-		memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port));
-		serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16;
-		serial_ports[index].iobase = reg->address;
-		serial_ports[index].irq = interrupts ? interrupts[0] : 0;
-		serial_ports[index].flags = ASYNC_BOOT_AUTOCONF;
-
-		DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n",
-		    index,
-		    serial_ports[index].iobase,
-		    serial_ports[index].irq,
-		    serial_ports[index].uartclk);
-
-		/* Get phys address of IO reg for port 1 */
-		if (index != 0)
-			goto next_port;
-
-		pci = of_get_parent(isa);
-		if (!pci) {
-			DBG("%s: no pci parent found\n", np->full_name);
-			goto next_port;
-		}
-
-		rangesp = (u32 *)get_property(pci, "ranges", &rlen);
-		if (rangesp == NULL) {
-			of_node_put(pci);
-			goto next_port;
-		}
-		rlen /= 4;
-
-		/* we need the #size-cells of the PCI bridge node itself */
-		phys_size = 1;
-		sizeprop = (u32 *)get_property(pci, "#size-cells", NULL);
-		if (sizeprop != NULL)
-			phys_size = *sizeprop;
-		/* we need the parent #addr-cells */
-		addr_size = prom_n_addr_cells(pci);
-		rentsize = 3 + addr_size + phys_size;
-		io_base = 0;
-		for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) {
-			if (((rangesp[0] >> 24) & 0x3) != 1)
-				continue; /* not IO space */
-			io_base = rangesp[3];
-			if (addr_size == 2)
-				io_base = (io_base << 32) | rangesp[4];
-		}
-		if (io_base != 0) {
-			*physport = io_base + reg->address;
-			if (default_speed && spd)
-				*default_speed = *spd;
-		}
-		of_node_put(pci);
-	next_port:
-		of_node_put(isa);
-	}
-
-	DBG(" <- generic_find_legacy_serial_port()\n");
-}
-
-static struct platform_device serial_device = {
-	.name	= "serial8250",
-	.id	= PLAT8250_DEV_PLATFORM,
-	.dev	= {
-		.platform_data = serial_ports,
-	},
-};
-
-static int __init serial_dev_init(void)
-{
-	return platform_device_register(&serial_device);
-}
-arch_initcall(serial_dev_init);
-
-#endif /* CONFIG_PPC_ISERIES */
-
 int check_legacy_ioport(unsigned long base_port)
 {
 	if (ppc_md.check_legacy_ioport == NULL)
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 5a2eba6..d3f0b6d 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -76,7 +76,6 @@
  * registers from *regs.  This is what we need
  * to do when a signal has been delivered.
  */
-#define sigreturn_exit(regs)	return 0
 
 #define GP_REGS_SIZE	min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32))
 #undef __SIGNAL_FRAMESIZE
@@ -156,9 +155,17 @@
 	elf_greg_t64 *gregs = (elf_greg_t64 *)regs;
 	int i;
 
-	for (i = 0; i <= PT_RESULT; i ++)
+	if (!FULL_REGS(regs)) {
+		set_thread_flag(TIF_SAVE_NVGPRS);
+		current_thread_info()->nvgprs_frame = frame->mc_gregs;
+	}
+
+	for (i = 0; i <= PT_RESULT; i ++) {
+		if (i == 14 && !FULL_REGS(regs))
+			i = 32;
 		if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i]))
 			return -EFAULT;
+	}
 	return 0;
 }
 
@@ -179,8 +186,6 @@
 
 #else /* CONFIG_PPC64 */
 
-extern void sigreturn_exit(struct pt_regs *);
-
 #define GP_REGS_SIZE	min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
 
 static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set)
@@ -214,6 +219,15 @@
 static inline int save_general_regs(struct pt_regs *regs,
 		struct mcontext __user *frame)
 {
+	if (!FULL_REGS(regs)) {
+		/* Zero out the unsaved GPRs to avoid information
+		   leak, and set TIF_SAVE_NVGPRS to ensure that the
+		   registers do actually get saved later. */
+		memset(&regs->gpr[14], 0, 18 * sizeof(unsigned long));
+		current_thread_info()->nvgprs_frame = &frame->mc_gregs;
+		set_thread_flag(TIF_SAVE_NVGPRS);
+	}
+
 	return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE);
 }
 
@@ -256,8 +270,10 @@
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&saveset, regs))
-			sigreturn_exit(regs);
+		if (do_signal(&saveset, regs)) {
+			set_thread_flag(TIF_RESTOREALL);
+			return 0;
+		}
 	}
 }
 
@@ -292,8 +308,10 @@
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&saveset, regs))
-			sigreturn_exit(regs);
+		if (do_signal(&saveset, regs)) {
+			set_thread_flag(TIF_RESTOREALL);
+			return 0;
+		}
 	}
 }
 
@@ -391,9 +409,6 @@
 static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
 		int sigret)
 {
-#ifdef CONFIG_PPC32
-	CHECK_FULL_REGS(regs);
-#endif
 	/* Make sure floating point registers are stored in regs */
 	flush_fp_to_thread(current);
 
@@ -828,12 +843,6 @@
 	regs->gpr[6] = (unsigned long) rt_sf;
 	regs->nip = (unsigned long) ka->sa.sa_handler;
 	regs->trap = 0;
-#ifdef CONFIG_PPC64
-	regs->result = 0;
-
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-#endif
 	return 1;
 
 badframe:
@@ -911,8 +920,8 @@
 	 */
 	if (do_setcontext(new_ctx, regs, 0))
 		do_exit(SIGSEGV);
-	sigreturn_exit(regs);
-	/* doesn't actually return back to here */
+
+	set_thread_flag(TIF_RESTOREALL);
 	return 0;
 }
 
@@ -945,12 +954,11 @@
 	 * nobody does any...
 	 */
 	compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs);
-	return (int)regs->result;
 #else
 	do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]);
-	sigreturn_exit(regs);		/* doesn't return here */
-	return 0;
 #endif
+	set_thread_flag(TIF_RESTOREALL);
+	return 0;
 
  bad:
 	force_sig(SIGSEGV, current);
@@ -1041,9 +1049,7 @@
 	 */
 	do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]);
 
-	sigreturn_exit(regs);
-	/* doesn't actually return back to here */
-
+	set_thread_flag(TIF_RESTOREALL);
  out:
 	return 0;
 }
@@ -1107,12 +1113,6 @@
 	regs->gpr[4] = (unsigned long) sc;
 	regs->nip = (unsigned long) ka->sa.sa_handler;
 	regs->trap = 0;
-#ifdef CONFIG_PPC64
-	regs->result = 0;
-
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-#endif
 
 	return 1;
 
@@ -1160,12 +1160,8 @@
 	    || restore_user_regs(regs, sr, 1))
 		goto badframe;
 
-#ifdef CONFIG_PPC64
-	return (int)regs->result;
-#else
-	sigreturn_exit(regs);		/* doesn't return */
+	set_thread_flag(TIF_RESTOREALL);
 	return 0;
-#endif
 
 badframe:
 	force_sig(SIGSEGV, current);
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 1decf27..5462bef 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -96,8 +96,10 @@
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&saveset, regs))
+		if (do_signal(&saveset, regs)) {
+			set_thread_flag(TIF_RESTOREALL);
 			return 0;
+		}
 	}
 }
 
@@ -152,6 +154,14 @@
 	err |= __put_user(0, &sc->v_regs);
 #endif /* CONFIG_ALTIVEC */
 	err |= __put_user(&sc->gp_regs, &sc->regs);
+	if (!FULL_REGS(regs)) {
+		/* Zero out the unsaved GPRs to avoid information
+		   leak, and set TIF_SAVE_NVGPRS to ensure that the
+		   registers do actually get saved later. */
+		memset(&regs->gpr[14], 0, 18 * sizeof(unsigned long));
+		set_thread_flag(TIF_SAVE_NVGPRS);
+		current_thread_info()->nvgprs_frame = &sc->gp_regs;
+	}
 	err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
 	err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
 	err |= __put_user(signr, &sc->signal);
@@ -340,6 +350,7 @@
 		do_exit(SIGSEGV);
 
 	/* This returns like rt_sigreturn */
+	set_thread_flag(TIF_RESTOREALL);
 	return 0;
 }
 
@@ -372,7 +383,8 @@
 	 */
 	do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]);
 
-	return regs->result;
+	set_thread_flag(TIF_RESTOREALL);
+	return 0;
 
 badframe:
 #if DEBUG_SIG
@@ -454,9 +466,6 @@
 	if (err)
 		goto badframe;
 
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 	return 1;
 
 badframe:
@@ -502,6 +511,8 @@
 		 * we only get here if there is a handler, we dont restart.
 		 */
 		regs->result = -EINTR;
+		regs->gpr[3] = EINTR;
+		regs->ccr |= 0x10000000;
 		break;
 	case -ERESTARTSYS:
 		/* ERESTARTSYS means to restart the syscall if there is no
@@ -509,6 +520,8 @@
 		 */
 		if (!(ka->sa.sa_flags & SA_RESTART)) {
 			regs->result = -EINTR;
+			regs->gpr[3] = EINTR;
+			regs->ccr |= 0x10000000;
 			break;
 		}
 		/* fallthrough */
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 30374d2..d381ec9 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -31,6 +31,7 @@
 #include <linux/sysdev.h>
 #include <linux/cpu.h>
 #include <linux/notifier.h>
+#include <linux/topology.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -75,6 +76,8 @@
 
 int smt_enabled_at_boot = 1;
 
+static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
+
 #ifdef CONFIG_MPIC
 int __init smp_mpic_probe(void)
 {
@@ -123,11 +126,16 @@
 		/* XXX Do we have to do this? */
 		set_need_resched();
 		break;
-#ifdef CONFIG_DEBUGGER
 	case PPC_MSG_DEBUGGER_BREAK:
+		if (crash_ipi_function_ptr) {
+			crash_ipi_function_ptr(regs);
+			break;
+		}
+#ifdef CONFIG_DEBUGGER
 		debugger_ipi(regs);
 		break;
-#endif
+#endif /* CONFIG_DEBUGGER */
+		/* FALLTHROUGH */
 	default:
 		printk("SMP %d: smp_message_recv(): unknown msg %d\n",
 		       smp_processor_id(), msg);
@@ -147,6 +155,17 @@
 }
 #endif
 
+#ifdef CONFIG_KEXEC
+void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
+{
+	crash_ipi_function_ptr = crash_ipi_callback;
+	if (crash_ipi_callback) {
+		mb();
+		smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
+	}
+}
+#endif
+
 static void stop_this_cpu(void *dummy)
 {
 	local_irq_disable();
@@ -452,10 +471,6 @@
 	if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))
 		return -EINVAL;
 
-#ifdef CONFIG_PPC64
-	paca[cpu].default_decr = tb_ticks_per_jiffy;
-#endif
-
 	/* Make sure callin-map entry is 0 (can be leftover a CPU
 	 * hotplug
 	 */
@@ -554,6 +569,8 @@
 	smp_ops->setup_cpu(boot_cpuid);
 
 	set_cpus_allowed(current, old_mask);
+
+	dump_numa_cpu_topology();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index 91b93d9..ad895c9 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -43,9 +43,6 @@
 #include <asm/time.h>
 #include <asm/unistd.h>
 
-extern unsigned long wall_jiffies;
-
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -311,31 +308,6 @@
 	return error? -EFAULT: 0;
 }
 
-#ifdef CONFIG_PPC64
-time_t sys64_time(time_t __user * tloc)
-{
-	time_t secs;
-	time_t usecs;
-
-	long tb_delta = tb_ticks_since(tb_last_stamp);
-	tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
-
-	secs  = xtime.tv_sec;  
-	usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec;
-	while (usecs >= USEC_PER_SEC) {
-		++secs;
-		usecs -= USEC_PER_SEC;
-	}
-
-	if (tloc) {
-		if (put_user(secs,tloc))
-			secs = -EFAULT;
-	}
-
-	return secs;
-}
-#endif
-
 long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low,
 		      u32 len_high, u32 len_low)
 {
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S
index 65eaea9..65463a1 100644
--- a/arch/powerpc/kernel/systbl.S
+++ b/arch/powerpc/kernel/systbl.S
@@ -54,7 +54,7 @@
 SYSCALL(unlink)
 COMPAT_SYS(execve)
 SYSCALL(chdir)
-SYSX(sys64_time,compat_sys_time,sys_time)
+COMPAT_SYS(time)
 SYSCALL(mknod)
 SYSCALL(chmod)
 SYSCALL(lchown)
@@ -113,7 +113,7 @@
 COMPAT_SYS(ssetmask)
 SYSCALL(setreuid)
 SYSCALL(setregid)
-SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend)
+SYS32ONLY(sigsuspend)
 COMPAT_SYS(sigpending)
 COMPAT_SYS(sethostname)
 COMPAT_SYS(setrlimit)
@@ -160,7 +160,7 @@
 COMPAT_SYS(sysinfo)
 COMPAT_SYS(ipc)
 SYSCALL(fsync)
-SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn)
+SYS32ONLY(sigreturn)
 PPC_SYS(clone)
 COMPAT_SYS(setdomainname)
 PPC_SYS(newuname)
@@ -213,13 +213,13 @@
 SYSCALL(setresgid)
 SYSCALL(getresgid)
 COMPAT_SYS(prctl)
-SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn)
+COMPAT_SYS(rt_sigreturn)
 COMPAT_SYS(rt_sigaction)
 COMPAT_SYS(rt_sigprocmask)
 COMPAT_SYS(rt_sigpending)
 COMPAT_SYS(rt_sigtimedwait)
 COMPAT_SYS(rt_sigqueueinfo)
-SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend)
+COMPAT_SYS(rt_sigsuspend)
 COMPAT_SYS(pread64)
 COMPAT_SYS(pwrite64)
 SYSCALL(chown)
@@ -290,7 +290,7 @@
 COMPAT_SYS(clock_gettime)
 COMPAT_SYS(clock_getres)
 COMPAT_SYS(clock_nanosleep)
-SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext)
+COMPAT_SYS(swapcontext)
 COMPAT_SYS(tgkill)
 COMPAT_SYS(utimes)
 COMPAT_SYS(statfs64)
@@ -319,3 +319,5 @@
 SYSCALL(inotify_init)
 SYSCALL(inotify_add_watch)
 SYSCALL(inotify_rm_watch)
+SYSCALL(spu_run)
+SYSCALL(spu_create)
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index de84797..56f50e9 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -699,10 +699,6 @@
 	div128_by_32(1024*1024, 0, tb_ticks_per_sec, &res);
 	tb_to_xs = res.result_low;
 
-#ifdef CONFIG_PPC64
-	get_paca()->default_decr = tb_ticks_per_jiffy;
-#endif
-
 	/*
 	 * Compute scale factor for sched_clock.
 	 * The calibrate_decr() function has set tb_ticks_per_sec,
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 1511454..7509aa6 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -31,6 +31,7 @@
 #include <linux/prctl.h>
 #include <linux/delay.h>
 #include <linux/kprobes.h>
+#include <linux/kexec.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -95,7 +96,7 @@
 
 int die(const char *str, struct pt_regs *regs, long err)
 {
-	static int die_counter;
+	static int die_counter, crash_dump_start = 0;
 	int nl = 0;
 
 	if (debugger(regs))
@@ -156,7 +157,21 @@
 	print_modules();
 	show_regs(regs);
 	bust_spinlocks(0);
+
+	if (!crash_dump_start && kexec_should_crash(current)) {
+		crash_dump_start = 1;
+		spin_unlock_irq(&die_lock);
+		crash_kexec(regs);
+		/* NOTREACHED */
+	}
 	spin_unlock_irq(&die_lock);
+	if (crash_dump_start)
+		/*
+		 * Only for soft-reset: Other CPUs will be responded to an IPI
+		 * sent by first kexec CPU.
+		 */
+		for(;;)
+			;
 
 	if (in_interrupt())
 		panic("Fatal exception in interrupt");
@@ -215,8 +230,10 @@
 void system_reset_exception(struct pt_regs *regs)
 {
 	/* See if any machine dependent calls */
-	if (ppc_md.system_reset_exception)
-		ppc_md.system_reset_exception(regs);
+	if (ppc_md.system_reset_exception) {
+		if (ppc_md.system_reset_exception(regs))
+			return;
+	}
 
 	die("System Reset", regs, SIGABRT);
 
@@ -886,12 +903,10 @@
 	die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
 }
 
-#if defined(CONFIG_PPC64) || defined(CONFIG_E500)
 void performance_monitor_exception(struct pt_regs *regs)
 {
 	perf_irq(regs);
 }
-#endif
 
 #ifdef CONFIG_8xx
 void SoftwareEmulation(struct pt_regs *regs)
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 0d878e7..558c1ce 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -16,8 +16,8 @@
 #include <linux/console.h>
 #include <asm/processor.h>
 
-void (*udbg_putc)(unsigned char c);
-unsigned char (*udbg_getc)(void);
+void (*udbg_putc)(char c);
+int (*udbg_getc)(void);
 int (*udbg_getc_poll)(void);
 
 /* udbg library, used by xmon et al */
@@ -57,8 +57,8 @@
 
 int udbg_read(char *buf, int buflen)
 {
-	char c, *p = buf;
-	int i;
+	char *p = buf;
+	int i, c;
 
 	if (!udbg_getc)
 		return 0;
@@ -66,8 +66,11 @@
 	for (i = 0; i < buflen; ++i) {
 		do {
 			c = udbg_getc();
+			if (c == -1 && i == 0)
+				return -1;
+
 		} while (c == 0x11 || c == 0x13);
-		if (c == 0)
+		if (c == 0 || c == -1)
 			break;
 		*p++ = c;
 	}
@@ -78,7 +81,7 @@
 #define UDBG_BUFSIZE 256
 void udbg_printf(const char *fmt, ...)
 {
-	unsigned char buf[UDBG_BUFSIZE];
+	char buf[UDBG_BUFSIZE];
 	va_list args;
 
 	va_start(args, fmt);
@@ -87,6 +90,12 @@
 	va_end(args);
 }
 
+void __init udbg_progress(char *s, unsigned short hex)
+{
+	udbg_puts(s);
+	udbg_puts("\n");
+}
+
 /*
  * Early boot console based on udbg
  */
@@ -99,7 +108,7 @@
 static struct console udbg_console = {
 	.name	= "udbg",
 	.write	= udbg_console_write,
-	.flags	= CON_PRINTBUFFER,
+	.flags	= CON_PRINTBUFFER | CON_ENABLED,
 	.index	= -1,
 };
 
@@ -107,15 +116,19 @@
 
 void __init disable_early_printk(void)
 {
+#if 1
 	if (!early_console_initialized)
 		return;
 	unregister_console(&udbg_console);
 	early_console_initialized = 0;
+#endif
 }
 
 /* called by setup_system */
 void register_early_udbg_console(void)
 {
+	if (early_console_initialized)
+		return;
 	early_console_initialized = 1;
 	register_console(&udbg_console);
 }
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index 9313574..7541bf4 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -43,9 +43,11 @@
 #define LSR_TEMT 0x40  /* Xmitter empty */
 #define LSR_ERR  0x80  /* Error */
 
+#define LCR_DLAB 0x80
+
 static volatile struct NS16550 __iomem *udbg_comport;
 
-static void udbg_550_putc(unsigned char c)
+static void udbg_550_putc(char c)
 {
 	if (udbg_comport) {
 		while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
@@ -67,39 +69,80 @@
 	return -1;
 }
 
-static unsigned char udbg_550_getc(void)
+static int udbg_550_getc(void)
 {
 	if (udbg_comport) {
 		while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
 			/* wait for char */;
 		return in_8(&udbg_comport->rbr);
 	}
-	return 0;
+	return -1;
 }
 
-void udbg_init_uart(void __iomem *comport, unsigned int speed)
+void udbg_init_uart(void __iomem *comport, unsigned int speed,
+		    unsigned int clock)
 {
-	u16 dll = speed ? (115200 / speed) : 12;
+	unsigned int dll, base_bauds = clock / 16;
+
+	if (speed == 0)
+		speed = 9600;
+	dll = base_bauds / speed;
 
 	if (comport) {
 		udbg_comport = (struct NS16550 __iomem *)comport;
 		out_8(&udbg_comport->lcr, 0x00);
 		out_8(&udbg_comport->ier, 0xff);
 		out_8(&udbg_comport->ier, 0x00);
-		out_8(&udbg_comport->lcr, 0x80);	/* Access baud rate */
-		out_8(&udbg_comport->dll, dll & 0xff);	/* 1 = 115200,  2 = 57600,
-							   3 = 38400, 12 = 9600 baud */
-		out_8(&udbg_comport->dlm, dll >> 8);	/* dll >> 8 which should be zero
-							   for fast rates; */
-		out_8(&udbg_comport->lcr, 0x03);	/* 8 data, 1 stop, no parity */
-		out_8(&udbg_comport->mcr, 0x03);	/* RTS/DTR */
-		out_8(&udbg_comport->fcr ,0x07);	/* Clear & enable FIFOs */
+		out_8(&udbg_comport->lcr, LCR_DLAB);
+		out_8(&udbg_comport->dll, dll & 0xff);
+		out_8(&udbg_comport->dlm, dll >> 8);
+		/* 8 data, 1 stop, no parity */
+		out_8(&udbg_comport->lcr, 0x03);
+		/* RTS/DTR */
+		out_8(&udbg_comport->mcr, 0x03);
+		/* Clear & enable FIFOs */
+		out_8(&udbg_comport->fcr ,0x07);
 		udbg_putc = udbg_550_putc;
 		udbg_getc = udbg_550_getc;
 		udbg_getc_poll = udbg_550_getc_poll;
 	}
 }
 
+unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
+{
+	unsigned int dll, dlm, divisor, prescaler, speed;
+	u8 old_lcr;
+	volatile struct NS16550 __iomem *port = comport;
+
+	old_lcr = in_8(&port->lcr);
+
+	/* select divisor latch registers.  */
+	out_8(&port->lcr, LCR_DLAB);
+
+	/* now, read the divisor */
+	dll = in_8(&port->dll);
+	dlm = in_8(&port->dlm);
+	divisor = dlm << 8 | dll;
+
+	/* check prescaling */
+	if (in_8(&port->mcr) & 0x80)
+		prescaler = 4;
+	else
+		prescaler = 1;
+
+	/* restore the LCR */
+	out_8(&port->lcr, old_lcr);
+
+	/* calculate speed */
+	speed = (clock / prescaler) / (divisor * 16);
+
+	/* sanity check */
+	if (speed < 0 || speed > (clock / 16))
+		speed = 9600;
+
+	return speed;
+}
+
 #ifdef CONFIG_PPC_MAPLE
 void udbg_maple_real_putc(unsigned char c)
 {
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 93d4fbf..a4815d3 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -81,7 +81,8 @@
 }
 
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
-static void do_dabr(struct pt_regs *regs, unsigned long error_code)
+static void do_dabr(struct pt_regs *regs, unsigned long address,
+		    unsigned long error_code)
 {
 	siginfo_t info;
 
@@ -99,7 +100,7 @@
 	info.si_signo = SIGTRAP;
 	info.si_errno = 0;
 	info.si_code = TRAP_HWBKPT;
-	info.si_addr = (void __user *)regs->nip;
+	info.si_addr = (void __user *)address;
 	force_sig_info(SIGTRAP, &info, current);
 }
 #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/
@@ -159,7 +160,7 @@
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
   	if (error_code & DSISR_DABRMATCH) {
 		/* DABR match */
-		do_dabr(regs, error_code);
+		do_dabr(regs, address, error_code);
 		return 0;
 	}
 #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index a606504..5bb433c 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -456,7 +456,7 @@
 
 	/* create bolted the linear mapping in the hash table */
 	for (i=0; i < lmb.memory.cnt; i++) {
-		base = lmb.memory.region[i].base + KERNELBASE;
+		base = (unsigned long)__va(lmb.memory.region[i].base);
 		size = lmb.memory.region[i].size;
 
 		DBG("creating mapping for region: %lx : %lx\n", base, size);
@@ -498,8 +498,8 @@
 	 * for either 4K or 16MB pages.
 	 */
 	if (tce_alloc_start) {
-		tce_alloc_start += KERNELBASE;
-		tce_alloc_end += KERNELBASE;
+		tce_alloc_start = (unsigned long)__va(tce_alloc_start);
+		tce_alloc_end = (unsigned long)__va(tce_alloc_end);
 
 		if (base + size >= tce_alloc_start)
 			tce_alloc_start = base + size + 1;
@@ -644,6 +644,7 @@
 	DBG_LOW(" -> rc=%d\n", rc);
 	return rc;
 }
+EXPORT_SYMBOL_GPL(hash_page);
 
 void hash_preload(struct mm_struct *mm, unsigned long ea,
 		  unsigned long access, unsigned long trap)
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 54131b8..b51bb28 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -549,6 +549,17 @@
 	return addr;
 }
 
+static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
+{
+	struct vm_area_struct *vma;
+
+	vma = find_vma(current->mm, addr);
+	if (!vma || ((addr + len) <= vma->vm_start))
+		return 0;
+
+	return -ENOMEM;
+}
+
 static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
 {
 	unsigned long addr = 0;
@@ -618,15 +629,28 @@
 	if (!cpu_has_feature(CPU_FTR_16M_PAGE))
 		return -EINVAL;
 
+	/* Paranoia, caller should have dealt with this */
+	BUG_ON((addr + len)  < addr);
+
 	if (test_thread_flag(TIF_32BIT)) {
+		/* Paranoia, caller should have dealt with this */
+		BUG_ON((addr + len) > 0x100000000UL);
+
 		curareas = current->mm->context.low_htlb_areas;
 
-		/* First see if we can do the mapping in the existing
-		 * low areas */
+		/* First see if we can use the hint address */
+		if (addr && (htlb_check_hinted_area(addr, len) == 0)) {
+			areamask = LOW_ESID_MASK(addr, len);
+			if (open_low_hpage_areas(current->mm, areamask) == 0)
+				return addr;
+		}
+
+		/* Next see if we can map in the existing low areas */
 		addr = htlb_get_low_area(len, curareas);
 		if (addr != -ENOMEM)
 			return addr;
 
+		/* Finally go looking for areas to open */
 		lastshift = 0;
 		for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
 		     ! lastshift; areamask >>=1) {
@@ -641,12 +665,22 @@
 	} else {
 		curareas = current->mm->context.high_htlb_areas;
 
-		/* First see if we can do the mapping in the existing
-		 * high areas */
+		/* First see if we can use the hint address */
+		/* We discourage 64-bit processes from doing hugepage
+		 * mappings below 4GB (must use MAP_FIXED) */
+		if ((addr >= 0x100000000UL)
+		    && (htlb_check_hinted_area(addr, len) == 0)) {
+			areamask = HTLB_AREA_MASK(addr, len);
+			if (open_high_hpage_areas(current->mm, areamask) == 0)
+				return addr;
+		}
+
+		/* Next see if we can map in the existing high areas */
 		addr = htlb_get_high_area(len, curareas);
 		if (addr != -ENOMEM)
 			return addr;
 
+		/* Finally go looking for areas to open */
 		lastshift = 0;
 		for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
 		     ! lastshift; areamask >>=1) {
diff --git a/arch/powerpc/mm/imalloc.c b/arch/powerpc/mm/imalloc.c
index f9587bc..8b0c132 100644
--- a/arch/powerpc/mm/imalloc.c
+++ b/arch/powerpc/mm/imalloc.c
@@ -107,6 +107,7 @@
 		if (v_addr < (unsigned long) tmp->addr + tmp->size)
 			break;
 
+	*vm = NULL;
 	if (tmp) {
 		if (im_region_overlaps(v_addr, size, tmp))
 			return IM_REGION_OVERLAP;
@@ -127,7 +128,6 @@
 		}
 	}
 
-	*vm = NULL;
 	return IM_REGION_UNUSED;
 }
 
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 7d4b8b5..7d0d75c 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -188,6 +188,11 @@
 
 	if (ppc_md.progress)
 		ppc_md.progress("MMU:exit", 0x211);
+
+	/* From now on, btext is no longer BAT mapped if it was at all */
+#ifdef CONFIG_BOOTX_TEXT
+	btext_unmap();
+#endif
 }
 
 /* This is only called until mem_init is done. */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index ed6ed2e..15aac0d 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -114,19 +114,18 @@
 	num_physpages++;
 }
 
-/*
- * This works only for the non-NUMA case.  Later, we'll need a lookup
- * to convert from real physical addresses to nid, that doesn't use
- * pfn_to_nid().
- */
 int __devinit add_memory(u64 start, u64 size)
 {
-	struct pglist_data *pgdata = NODE_DATA(0);
+	struct pglist_data *pgdata;
 	struct zone *zone;
+	int nid;
 	unsigned long start_pfn = start >> PAGE_SHIFT;
 	unsigned long nr_pages = size >> PAGE_SHIFT;
 
-	start += KERNELBASE;
+	nid = hot_add_scn_to_nid(start);
+	pgdata = NODE_DATA(nid);
+
+	start = __va(start);
 	create_section_mapping(start, start + size);
 
 	/* this should work for most non-highmem platforms */
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index ba7a305..2863a91 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -37,6 +37,7 @@
 
 static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
 static int min_common_depth;
+static int n_mem_addr_cells, n_mem_size_cells;
 
 /*
  * We need somewhere to store start/end/node for each region until we have
@@ -254,32 +255,20 @@
 	return depth;
 }
 
-static int __init get_mem_addr_cells(void)
+static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
 {
 	struct device_node *memory = NULL;
-	int rc;
 
 	memory = of_find_node_by_type(memory, "memory");
 	if (!memory)
-		return 0; /* it won't matter */
+		panic("numa.c: No memory nodes found!");
 
-	rc = prom_n_addr_cells(memory);
-	return rc;
+	*n_addr_cells = prom_n_addr_cells(memory);
+	*n_size_cells = prom_n_size_cells(memory);
+	of_node_put(memory);
 }
 
-static int __init get_mem_size_cells(void)
-{
-	struct device_node *memory = NULL;
-	int rc;
-
-	memory = of_find_node_by_type(memory, "memory");
-	if (!memory)
-		return 0; /* it won't matter */
-	rc = prom_n_size_cells(memory);
-	return rc;
-}
-
-static unsigned long __init read_n_cells(int n, unsigned int **buf)
+static unsigned long __devinit read_n_cells(int n, unsigned int **buf)
 {
 	unsigned long result = 0;
 
@@ -386,7 +375,6 @@
 {
 	struct device_node *cpu = NULL;
 	struct device_node *memory = NULL;
-	int addr_cells, size_cells;
 	int max_domain;
 	unsigned long i;
 
@@ -425,8 +413,7 @@
 		}
 	}
 
-	addr_cells = get_mem_addr_cells();
-	size_cells = get_mem_size_cells();
+	get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);
 	memory = NULL;
 	while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
 		unsigned long start;
@@ -436,15 +423,21 @@
 		unsigned int *memcell_buf;
 		unsigned int len;
 
-		memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+		memcell_buf = (unsigned int *)get_property(memory,
+			"linux,usable-memory", &len);
+		if (!memcell_buf || len <= 0)
+			memcell_buf =
+				(unsigned int *)get_property(memory, "reg",
+					&len);
 		if (!memcell_buf || len <= 0)
 			continue;
 
-		ranges = memory->n_addrs;
+		/* ranges in cell */
+		ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
 new_range:
 		/* these are order-sensitive, and modify the buffer pointer */
-		start = read_n_cells(addr_cells, &memcell_buf);
-		size = read_n_cells(size_cells, &memcell_buf);
+		start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+		size = read_n_cells(n_mem_size_cells, &memcell_buf);
 
 		numa_domain = of_node_numa_domain(memory);
 
@@ -497,7 +490,41 @@
 	node_set_online(0);
 }
 
-static void __init dump_numa_topology(void)
+void __init dump_numa_cpu_topology(void)
+{
+	unsigned int node;
+	unsigned int cpu, count;
+
+	if (min_common_depth == -1 || !numa_enabled)
+		return;
+
+	for_each_online_node(node) {
+		printk(KERN_INFO "Node %d CPUs:", node);
+
+		count = 0;
+		/*
+		 * If we used a CPU iterator here we would miss printing
+		 * the holes in the cpumap.
+		 */
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) {
+				if (count == 0)
+					printk(" %u", cpu);
+				++count;
+			} else {
+				if (count > 1)
+					printk("-%u", cpu - 1);
+				count = 0;
+			}
+		}
+
+		if (count > 1)
+			printk("-%u", NR_CPUS - 1);
+		printk("\n");
+	}
+}
+
+static void __init dump_numa_memory_topology(void)
 {
 	unsigned int node;
 	unsigned int count;
@@ -529,7 +556,6 @@
 			printk("-0x%lx", i);
 		printk("\n");
 	}
-	return;
 }
 
 /*
@@ -591,7 +617,7 @@
 	if (parse_numa_properties())
 		setup_nonnuma();
 	else
-		dump_numa_topology();
+		dump_numa_memory_topology();
 
 	register_cpu_notifier(&ppc64_numa_nb);
 
@@ -730,3 +756,60 @@
 	return 0;
 }
 early_param("numa", early_numa);
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * Find the node associated with a hot added memory section.  Section
+ * corresponds to a SPARSEMEM section, not an LMB.  It is assumed that
+ * sections are fully contained within a single LMB.
+ */
+int hot_add_scn_to_nid(unsigned long scn_addr)
+{
+	struct device_node *memory = NULL;
+	nodemask_t nodes;
+	int numa_domain = 0;
+
+	if (!numa_enabled || (min_common_depth < 0))
+		return numa_domain;
+
+	while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+		unsigned long start, size;
+		int ranges;
+		unsigned int *memcell_buf;
+		unsigned int len;
+
+		memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+		if (!memcell_buf || len <= 0)
+			continue;
+
+		/* ranges in cell */
+		ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
+ha_new_range:
+		start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+		size = read_n_cells(n_mem_size_cells, &memcell_buf);
+		numa_domain = of_node_numa_domain(memory);
+
+		/* Domains not present at boot default to 0 */
+		if (!node_online(numa_domain))
+			numa_domain = any_online_node(NODE_MASK_ALL);
+
+		if ((scn_addr >= start) && (scn_addr < (start + size))) {
+			of_node_put(memory);
+			goto got_numa_domain;
+		}
+
+		if (--ranges)		/* process all ranges in cell */
+			goto ha_new_range;
+	}
+	BUG();	/* section address should be found above */
+
+	/* Temporary code to ensure that returned node is not empty */
+got_numa_domain:
+	nodes_setall(nodes);
+	while (NODE_DATA(numa_domain)->node_spanned_pages == 0) {
+		node_clear(numa_domain, nodes);
+		numa_domain = any_online_node(nodes);
+	}
+	return numa_domain;
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 60e852f..ffc8ed4 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -75,7 +75,7 @@
 	vflags = SLB_VSID_KERNEL | virtual_llp;
 
 	ksp_esid_data = mk_esid_data(get_paca()->kstack, 2);
-	if ((ksp_esid_data & ESID_MASK) == KERNELBASE)
+	if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET)
 		ksp_esid_data &= ~SLB_ESID_V;
 
 	/* We need to do this all in asm, so we're sure we don't touch
@@ -87,8 +87,8 @@
 		     /* Slot 2 - kernel stack */
 		     "slbmte	%2,%3\n"
 		     "isync"
-		     :: "r"(mk_vsid_data(VMALLOCBASE, vflags)),
-		        "r"(mk_esid_data(VMALLOCBASE, 1)),
+		     :: "r"(mk_vsid_data(VMALLOC_START, vflags)),
+		        "r"(mk_esid_data(VMALLOC_START, 1)),
 		        "r"(mk_vsid_data(ksp_esid_data, lflags)),
 		        "r"(ksp_esid_data)
 		     : "memory");
@@ -134,14 +134,14 @@
 	else
 		unmapped_base = TASK_UNMAPPED_BASE_USER64;
 
-	if (pc >= KERNELBASE)
+	if (is_kernel_addr(pc))
 		return;
 	slb_allocate(pc);
 
 	if (GET_ESID(pc) == GET_ESID(stack))
 		return;
 
-	if (stack >= KERNELBASE)
+	if (is_kernel_addr(stack))
 		return;
 	slb_allocate(stack);
 
@@ -149,7 +149,7 @@
 	    || (GET_ESID(stack) == GET_ESID(unmapped_base)))
 		return;
 
-	if (unmapped_base >= KERNELBASE)
+	if (is_kernel_addr(unmapped_base))
 		return;
 	slb_allocate(unmapped_base);
 }
@@ -213,10 +213,10 @@
 	asm volatile("isync":::"memory");
 	asm volatile("slbmte  %0,%0"::"r" (0) : "memory");
 	asm volatile("isync; slbia; isync":::"memory");
-	create_slbe(KERNELBASE, lflags, 0);
+	create_slbe(PAGE_OFFSET, lflags, 0);
 
 	/* VMALLOC space has 4K pages always for now */
-	create_slbe(VMALLOCBASE, vflags, 1);
+	create_slbe(VMALLOC_START, vflags, 1);
 
 	/* We don't bolt the stack for the time being - we're in boot,
 	 * so the stack is in the bolted segment.  By the time it goes
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index 950ffc5..d1acee3 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -37,9 +37,9 @@
 
 	srdi	r9,r3,60		/* get region */
 	srdi	r10,r3,28		/* get esid */
-	cmpldi	cr7,r9,0xc		/* cmp KERNELBASE for later use */
+	cmpldi	cr7,r9,0xc		/* cmp PAGE_OFFSET for later use */
 
-	/* r3 = address, r10 = esid, cr7 = <>KERNELBASE */
+	/* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */
 	blt	cr7,0f			/* user or kernel? */
 
 	/* kernel address: proto-VSID = ESID */
@@ -166,7 +166,7 @@
 /*
  * Finish loading of an SLB entry and return
  *
- * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <>KERNELBASE
+ * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET
  */
 slb_finish_load:
 	ASM_VSID_SCRAMBLE(r10,r9)
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 51e7951..82e4951 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -40,7 +40,7 @@
 	unsigned long entry, group, old_esid, castout_entry, i;
 	unsigned int global_entry;
 	struct stab_entry *ste, *castout_ste;
-	unsigned long kernel_segment = (esid << SID_SHIFT) >= KERNELBASE;
+	unsigned long kernel_segment = (esid << SID_SHIFT) >= PAGE_OFFSET;
 
 	vsid_data = vsid << STE_VSID_SHIFT;
 	esid_data = esid << SID_SHIFT | STE_ESID_KP | STE_ESID_V;
@@ -83,7 +83,7 @@
 		}
 
 		/* Dont cast out the first kernel segment */
-		if ((castout_ste->esid_data & ESID_MASK) != KERNELBASE)
+		if ((castout_ste->esid_data & ESID_MASK) != PAGE_OFFSET)
 			break;
 
 		castout_entry = (castout_entry + 1) & 0xf;
@@ -122,7 +122,7 @@
 	unsigned long offset;
 
 	/* Kernel or user address? */
-	if (ea >= KERNELBASE) {
+	if (is_kernel_addr(ea)) {
 		vsid = get_kernel_vsid(ea);
 	} else {
 		if ((ea >= TASK_SIZE_USER64) || (! mm))
@@ -133,7 +133,7 @@
 
 	stab_entry = make_ste(get_paca()->stab_addr, GET_ESID(ea), vsid);
 
-	if (ea < KERNELBASE) {
+	if (!is_kernel_addr(ea)) {
 		offset = __get_cpu_var(stab_cache_ptr);
 		if (offset < NR_STAB_CACHE_ENTRIES)
 			__get_cpu_var(stab_cache[offset++]) = stab_entry;
@@ -190,7 +190,7 @@
 		     entry++, ste++) {
 			unsigned long ea;
 			ea = ste->esid_data & ESID_MASK;
-			if (ea < KERNELBASE) {
+			if (!is_kernel_addr(ea)) {
 				ste->esid_data = 0;
 			}
 		}
@@ -251,7 +251,7 @@
 			panic("Unable to allocate segment table for CPU %d.\n",
 			      cpu);
 
-		newstab += KERNELBASE;
+		newstab = (unsigned long)__va(newstab);
 
 		memset((void *)newstab, 0, HW_PAGE_SIZE);
 
@@ -270,11 +270,11 @@
  */
 void stab_initialize(unsigned long stab)
 {
-	unsigned long vsid = get_kernel_vsid(KERNELBASE);
+	unsigned long vsid = get_kernel_vsid(PAGE_OFFSET);
 	unsigned long stabreal;
 
 	asm volatile("isync; slbia; isync":::"memory");
-	make_ste(stab, GET_ESID(KERNELBASE), vsid);
+	make_ste(stab, GET_ESID(PAGE_OFFSET), vsid);
 
 	/* Order update */
 	asm volatile("sync":::"memory");
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
index 859d29a..bb3afb6 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_64.c
@@ -168,7 +168,7 @@
 		batch->mm = mm;
 		batch->psize = psize;
 	}
-	if (addr < KERNELBASE) {
+	if (!is_kernel_addr(addr)) {
 		vsid = get_vsid(mm->context.id, addr);
 		WARN_ON(vsid == 0);
 	} else
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 0782d0c..554cd7c 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -9,3 +9,4 @@
 oprofile-y := $(DRIVER_OBJS) common.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
+oprofile-$(CONFIG_PPC32) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index af2c05d..71615eb 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -14,9 +14,6 @@
  */
 
 #include <linux/oprofile.h>
-#ifndef __powerpc64__
-#include <linux/slab.h>
-#endif /* ! __powerpc64__ */
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/errno.h>
@@ -31,10 +28,6 @@
 static struct op_counter_config ctr[OP_MAX_COUNTER];
 static struct op_system_config sys;
 
-#ifndef __powerpc64__
-static char *cpu_type;
-#endif /* ! __powerpc64__ */
-
 static void op_handle_interrupt(struct pt_regs *regs)
 {
 	model->handle_interrupt(regs, ctr);
@@ -53,14 +46,7 @@
 	model->reg_setup(ctr, &sys, model->num_counters);
 
 	/* Configure the registers on all cpus.  */
-#ifdef __powerpc64__
 	on_each_cpu(model->cpu_setup, NULL, 0, 1);
-#else /* __powerpc64__ */
-#if 0
-	/* FIXME: Make multi-cpu work */
-	on_each_cpu(model->reg_setup, NULL, 0, 1);
-#endif
-#endif /* __powerpc64__ */
 
 	return 0;
 }
@@ -95,7 +81,7 @@
 {
 	int i;
 
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
 	/*
 	 * There is one mmcr0, mmcr1 and mmcra for setting the events for
 	 * all of the counters.
@@ -103,7 +89,7 @@
 	oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0);
 	oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1);
 	oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra);
-#endif /* __powerpc64__ */
+#endif
 
 	for (i = 0; i < model->num_counters; ++i) {
 		struct dentry *dir;
@@ -115,65 +101,68 @@
 		oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
 		oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
 		oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
-#ifdef __powerpc64__
+
 		/*
-		 * We dont support per counter user/kernel selection, but
-		 * we leave the entries because userspace expects them
+		 * Classic PowerPC doesn't support per-counter
+		 * control like this, but the options are
+		 * expected, so they remain.  For Freescale
+		 * Book-E style performance monitors, we do
+		 * support them.
 		 */
-#endif /* __powerpc64__ */
 		oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
 		oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
 
-#ifndef __powerpc64__
-		/* FIXME: Not sure if this is used */
-#endif /* ! __powerpc64__ */
 		oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
 	}
 
 	oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
 	oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
 	oprofilefs_create_ulong(sb, root, "backtrace_spinlocks",
 				&sys.backtrace_spinlocks);
-#endif /* __powerpc64__ */
+#endif
 
 	/* Default to tracing both kernel and user */
 	sys.enable_kernel = 1;
 	sys.enable_user = 1;
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
 	/* Turn on backtracing through spinlocks by default */
 	sys.backtrace_spinlocks = 1;
-#endif /* __powerpc64__ */
+#endif
 
 	return 0;
 }
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-#ifndef __powerpc64__
-#ifdef CONFIG_FSL_BOOKE
-	model = &op_model_fsl_booke;
-#else
-	return -ENODEV;
-#endif
-
-	cpu_type = kmalloc(32, GFP_KERNEL);
-	if (NULL == cpu_type)
-		return -ENOMEM;
-
-	sprintf(cpu_type, "ppc/%s", cur_cpu_spec->cpu_name);
-
-	model->num_counters = cur_cpu_spec->num_pmcs;
-
-	ops->cpu_type = cpu_type;
-#else /* __powerpc64__ */
-	if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type)
+	if (!cur_cpu_spec->oprofile_cpu_type)
 		return -ENODEV;
-	model = cur_cpu_spec->oprofile_model;
+
+	switch (cur_cpu_spec->oprofile_type) {
+#ifdef CONFIG_PPC64
+		case RS64:
+			model = &op_model_rs64;
+			break;
+		case POWER4:
+			model = &op_model_power4;
+			break;
+#else
+		case G4:
+			model = &op_model_7450;
+			break;
+#endif
+#ifdef CONFIG_FSL_BOOKE
+		case BOOKE:
+			model = &op_model_fsl_booke;
+			break;
+#endif
+		default:
+			return -ENODEV;
+	}
+
 	model->num_counters = cur_cpu_spec->num_pmcs;
 
 	ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
-#endif /* __powerpc64__ */
 	ops->create_files = op_powerpc_create_files;
 	ops->setup = op_powerpc_setup;
 	ops->shutdown = op_powerpc_shutdown;
@@ -188,8 +177,4 @@
 
 void oprofile_arch_exit(void)
 {
-#ifndef __powerpc64__
-	kfree(cpu_type);
-	cpu_type = NULL;
-#endif /* ! __powerpc64__ */
 }
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
new file mode 100644
index 0000000..32abfdb
--- /dev/null
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -0,0 +1,206 @@
+/*
+ * oprofile/op_model_7450.c
+ *
+ * Freescale 745x/744x oprofile support, based on fsl_booke support
+ * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * 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/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/page.h>
+#include <asm/pmc.h>
+#include <asm/oprofile_impl.h>
+
+static unsigned long reset_value[OP_MAX_COUNTER];
+
+static int oprofile_running;
+static u32 mmcr0_val, mmcr1_val, mmcr2_val;
+
+#define MMCR0_PMC1_SHIFT	6
+#define MMCR0_PMC2_SHIFT	0
+#define MMCR1_PMC3_SHIFT	27
+#define MMCR1_PMC4_SHIFT	22
+#define MMCR1_PMC5_SHIFT	17
+#define MMCR1_PMC6_SHIFT	11
+
+#define mmcr0_event1(event) \
+	((event << MMCR0_PMC1_SHIFT) & MMCR0_PMC1SEL)
+#define mmcr0_event2(event) \
+	((event << MMCR0_PMC2_SHIFT) & MMCR0_PMC2SEL)
+
+#define mmcr1_event3(event) \
+	((event << MMCR1_PMC3_SHIFT) & MMCR1_PMC3SEL)
+#define mmcr1_event4(event) \
+	((event << MMCR1_PMC4_SHIFT) & MMCR1_PMC4SEL)
+#define mmcr1_event5(event) \
+	((event << MMCR1_PMC5_SHIFT) & MMCR1_PMC5SEL)
+#define mmcr1_event6(event) \
+	((event << MMCR1_PMC6_SHIFT) & MMCR1_PMC6SEL)
+
+#define MMCR0_INIT (MMCR0_FC | MMCR0_FCS | MMCR0_FCP | MMCR0_FCM1 | MMCR0_FCM0)
+
+/* Unfreezes the counters on this CPU, enables the interrupt,
+ * enables the counters to trigger the interrupt, and sets the
+ * counters to only count when the mark bit is not set.
+ */
+static void pmc_start_ctrs(void)
+{
+	u32 mmcr0 = mfspr(SPRN_MMCR0);
+
+	mmcr0 &= ~(MMCR0_FC | MMCR0_FCM0);
+	mmcr0 |= (MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE);
+
+	mtspr(SPRN_MMCR0, mmcr0);
+}
+
+/* Disables the counters on this CPU, and freezes them */
+static void pmc_stop_ctrs(void)
+{
+	u32 mmcr0 = mfspr(SPRN_MMCR0);
+
+	mmcr0 |= MMCR0_FC;
+	mmcr0 &= ~(MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE);
+
+	mtspr(SPRN_MMCR0, mmcr0);
+}
+
+/* Configures the counters on this CPU based on the global
+ * settings */
+static void fsl7450_cpu_setup(void *unused)
+{
+	/* freeze all counters */
+	pmc_stop_ctrs();
+
+	mtspr(SPRN_MMCR0, mmcr0_val);
+	mtspr(SPRN_MMCR1, mmcr1_val);
+	mtspr(SPRN_MMCR2, mmcr2_val);
+}
+
+#define NUM_CTRS 6
+
+/* Configures the global settings for the countes on all CPUs. */
+static void fsl7450_reg_setup(struct op_counter_config *ctr,
+			     struct op_system_config *sys,
+			     int num_ctrs)
+{
+	int i;
+
+	/* Our counters count up, and "count" refers to
+	 * how much before the next interrupt, and we interrupt
+	 * on overflow.  So we calculate the starting value
+	 * which will give us "count" until overflow.
+	 * Then we set the events on the enabled counters */
+	for (i = 0; i < NUM_CTRS; ++i)
+		reset_value[i] = 0x80000000UL - ctr[i].count;
+
+	/* Set events for Counters 1 & 2 */
+	mmcr0_val = MMCR0_INIT | mmcr0_event1(ctr[0].event)
+		| mmcr0_event2(ctr[1].event);
+
+	/* Setup user/kernel bits */
+	if (sys->enable_kernel)
+		mmcr0_val &= ~(MMCR0_FCS);
+
+	if (sys->enable_user)
+		mmcr0_val &= ~(MMCR0_FCP);
+
+	/* Set events for Counters 3-6 */
+	mmcr1_val = mmcr1_event3(ctr[2].event)
+		| mmcr1_event4(ctr[3].event)
+		| mmcr1_event5(ctr[4].event)
+		| mmcr1_event6(ctr[5].event);
+
+	mmcr2_val = 0;
+}
+
+/* Sets the counters on this CPU to the chosen values, and starts them */
+static void fsl7450_start(struct op_counter_config *ctr)
+{
+	int i;
+
+	mtmsr(mfmsr() | MSR_PMM);
+
+	for (i = 0; i < NUM_CTRS; ++i) {
+		if (ctr[i].enabled)
+			ctr_write(i, reset_value[i]);
+		else
+			ctr_write(i, 0);
+	}
+
+	/* Clear the freeze bit, and enable the interrupt.
+	 * The counters won't actually start until the rfi clears
+	 * the PMM bit */
+	pmc_start_ctrs();
+
+	oprofile_running = 1;
+}
+
+/* Stop the counters on this CPU */
+static void fsl7450_stop(void)
+{
+	/* freeze counters */
+	pmc_stop_ctrs();
+
+	oprofile_running = 0;
+
+	mb();
+}
+
+
+/* Handle the interrupt on this CPU, and log a sample for each
+ * event that triggered the interrupt */
+static void fsl7450_handle_interrupt(struct pt_regs *regs,
+				    struct op_counter_config *ctr)
+{
+	unsigned long pc;
+	int is_kernel;
+	int val;
+	int i;
+
+	/* set the PMM bit (see comment below) */
+	mtmsr(mfmsr() | MSR_PMM);
+
+	pc = mfspr(SPRN_SIAR);
+	is_kernel = (pc >= KERNELBASE);
+
+	for (i = 0; i < NUM_CTRS; ++i) {
+		val = ctr_read(i);
+		if (val < 0) {
+			if (oprofile_running && ctr[i].enabled) {
+				oprofile_add_pc(pc, is_kernel, i);
+				ctr_write(i, reset_value[i]);
+			} else {
+				ctr_write(i, 0);
+			}
+		}
+	}
+
+	/* The freeze bit was set by the interrupt. */
+	/* Clear the freeze bit, and reenable the interrupt.
+	 * The counters won't actually start until the rfi clears
+	 * the PMM bit */
+	pmc_start_ctrs();
+}
+
+struct op_powerpc_model op_model_7450= {
+	.reg_setup		= fsl7450_reg_setup,
+	.cpu_setup		= fsl7450_cpu_setup,
+	.start			= fsl7450_start,
+	.stop			= fsl7450_stop,
+	.handle_interrupt	= fsl7450_handle_interrupt,
+};
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index a3401b4..659a021 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -252,7 +252,7 @@
 		return (unsigned long)__va(pc);
 
 	/* Not sure where we were */
-	if (pc < KERNELBASE)
+	if (!is_kernel_addr(pc))
 		/* function descriptor madness */
 		return *((unsigned long *)kernel_unknown_bucket);
 
@@ -264,7 +264,7 @@
 	int is_kernel;
 
 	if (!mmcra_has_sihv) {
-		is_kernel = (pc >= KERNELBASE);
+		is_kernel = is_kernel_addr(pc);
 	} else {
 		unsigned long mmcra = mfspr(SPRN_MMCRA);
 		is_kernel = ((mmcra & MMCRA_SIPR) == 0);
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index e010b85..5c909ee 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -178,7 +178,6 @@
 	int val;
 	int i;
 	unsigned long pc = mfspr(SPRN_SIAR);
-	int is_kernel = (pc >= KERNELBASE);
 
 	/* set the PMM bit (see comment below) */
 	mtmsrd(mfmsr() | MSR_PMM);
@@ -187,7 +186,7 @@
 		val = ctr_read(i);
 		if (val < 0) {
 			if (ctr[i].enabled) {
-				oprofile_add_pc(pc, is_kernel, i);
+				oprofile_add_pc(pc, is_kernel_addr(pc), i);
 				ctr_write(i, reset_value[i]);
 			} else {
 				ctr_write(i, 0);
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
new file mode 100644
index 0000000..3157071
--- /dev/null
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -0,0 +1,13 @@
+menu "Cell Broadband Engine options"
+	depends on PPC_CELL
+
+config SPU_FS
+	tristate "SPU file system"
+	default m
+	depends on PPC_CELL
+	help
+	  The SPU file system is used to access Synergistic Processing
+	  Units on machines implementing the Broadband Processor
+	  Architecture.
+
+endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 55e094b..16031b5 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,2 +1,10 @@
 obj-y			+= interrupt.o iommu.o setup.o spider-pic.o
+obj-y			+= pervasive.o
+
 obj-$(CONFIG_SMP)	+= smp.o
+obj-$(CONFIG_SPU_FS)	+= spufs/ spu-base.o
+
+spu-base-y		+= spu_base.o spu_priv1.o
+
+builtin-spufs-$(CONFIG_SPU_FS)	+= spu_syscalls.o
+obj-y			+= $(builtin-spufs-m)
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 7fbe78a..63aa52a 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/types.h>
 
@@ -55,6 +56,7 @@
 
 struct iic {
 	struct iic_regs __iomem *regs;
+	u8 target_id;
 };
 
 static DEFINE_PER_CPU(struct iic, iic);
@@ -172,12 +174,11 @@
 	return irq;
 }
 
-static struct iic_regs __iomem *find_iic(int cpu)
+static int setup_iic(int cpu, struct iic *iic)
 {
 	struct device_node *np;
 	int nodeid = cpu / 2;
 	unsigned long regs;
-	struct iic_regs __iomem *iic_regs;
 
 	for (np = of_find_node_by_type(NULL, "cpu");
 	     np;
@@ -188,20 +189,23 @@
 
 	if (!np) {
 		printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
-		iic_regs = NULL;
-	} else {
-		regs = *(long *)get_property(np, "iic", NULL);
-
-		/* hack until we have decided on the devtree info */
-		regs += 0x400;
-		if (cpu & 1)
-			regs += 0x20;
-
-		printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
-		iic_regs = __ioremap(regs, sizeof(struct iic_regs),
-						 _PAGE_NO_CACHE);
+		iic->regs = NULL;
+		iic->target_id = 0xff;
+		return -ENODEV;
 	}
-	return iic_regs;
+
+	regs = *(long *)get_property(np, "iic", NULL);
+
+	/* hack until we have decided on the devtree info */
+	regs += 0x400;
+	if (cpu & 1)
+		regs += 0x20;
+
+	printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
+	iic->regs = __ioremap(regs, sizeof(struct iic_regs),
+					 _PAGE_NO_CACHE);
+	iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
+	return 0;
 }
 
 #ifdef CONFIG_SMP
@@ -227,6 +231,12 @@
 	out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
 }
 
+u8 iic_get_target_id(int cpu)
+{
+	return per_cpu(iic, cpu).target_id;
+}
+EXPORT_SYMBOL_GPL(iic_get_target_id);
+
 static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
 {
 	smp_message_recv(iic_irq_to_ipi(irq), regs);
@@ -276,7 +286,7 @@
 	irq_offset = 0;
 	for_each_cpu(cpu) {
 		iic = &per_cpu(iic, cpu);
-		iic->regs = find_iic(cpu);
+		setup_iic(cpu, iic);
 		if (iic->regs)
 			out_be64(&iic->regs->prio, 0xff);
 	}
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index 37d58e6..a14bd38 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -54,6 +54,7 @@
 extern void iic_local_enable(void);
 extern void iic_local_disable(void);
 
+extern u8 iic_get_target_id(int cpu);
 
 extern void spider_init_IRQ(void);
 extern int spider_get_irq(unsigned long int_pending);
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 74f999b..46e7cb9 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -29,6 +29,8 @@
 #include <linux/bootmem.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
 
 #include <asm/sections.h>
 #include <asm/iommu.h>
@@ -40,6 +42,7 @@
 #include <asm/abs_addr.h>
 #include <asm/system.h>
 #include <asm/ppc-pci.h>
+#include <asm/udbg.h>
 
 #include "iommu.h"
 
@@ -220,8 +223,6 @@
 {
 	unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR;
 	unsigned long __iomem *p = base + IOC_PT_CACHE_REG;
-	pr_debug("iopt %02lx was v%016lx/t%016lx, store v%016lx/t%016lx\n",
-		index, get_iopt_cache(base, index, &oldtag), oldtag, val, tag);
 
 	out_be64(p, val);
 	out_be64(&tags[index], tag);
@@ -248,66 +249,175 @@
 	out_be64(p, conf | IOCMD_CONF_TE);
 }
 
-/* FIXME: get these from the device tree */
-#define ioc_base	0x20000511000ull
-#define ioc_mmio_base	0x20000510000ull
-#define ioid		0x48a
-#define iopt_phys_offset (- 0x20000000) /* We have a 512MB offset from the SB */
-#define io_page_size	0x1000000
-
-static unsigned long map_iopt_entry(unsigned long address)
+static void enable_mapping(void __iomem *base, void __iomem *mmio_base)
 {
-	switch (address >> 20) {
-	case 0x600:
-		address = 0x24020000000ull; /* spider i/o */
-		break;
-	default:
-		address += iopt_phys_offset;
-		break;
-	}
-
-	return get_iopt_entry(address, ioid, IOPT_PROT_RW);
+	set_iocmd_config(base);
+	set_iost_origin(mmio_base);
 }
 
-static void iommu_bus_setup_null(struct pci_bus *b) { }
 static void iommu_dev_setup_null(struct pci_dev *d) { }
+static void iommu_bus_setup_null(struct pci_bus *b) { }
+
+struct cell_iommu {
+	unsigned long base;
+	unsigned long mmio_base;
+	void __iomem *mapped_base;
+	void __iomem *mapped_mmio_base;
+};
+
+static struct cell_iommu cell_iommus[NR_CPUS];
 
 /* initialize the iommu to support a simple linear mapping
  * for each DMA window used by any device. For now, we
  * happen to know that there is only one DMA window in use,
  * starting at iopt_phys_offset. */
-static void cell_map_iommu(void)
+static void cell_do_map_iommu(struct cell_iommu *iommu,
+			      unsigned int ioid,
+			      unsigned long map_start,
+			      unsigned long map_size)
 {
-	unsigned long address;
-	void __iomem *base;
+	unsigned long io_address, real_address;
+	void __iomem *ioc_base, *ioc_mmio_base;
 	ioste ioste;
 	unsigned long index;
 
-	base = __ioremap(ioc_base, 0x1000, _PAGE_NO_CACHE);
-	pr_debug("%lx mapped to %p\n", ioc_base, base);
-	set_iocmd_config(base);
-	iounmap(base);
+	/* we pretend the io page table was at a very high address */
+	const unsigned long fake_iopt = 0x10000000000ul;
+	const unsigned long io_page_size = 0x1000000; /* use 16M pages */
+	const unsigned long io_segment_size = 0x10000000; /* 256M */
 
-	base = __ioremap(ioc_mmio_base, 0x1000, _PAGE_NO_CACHE);
-	pr_debug("%lx mapped to %p\n", ioc_mmio_base, base);
+	ioc_base = iommu->mapped_base;
+	ioc_mmio_base = iommu->mapped_mmio_base;
 
-	set_iost_origin(base);
-
-	for (address = 0; address < 0x100000000ul; address += io_page_size) {
-		ioste = get_iost_entry(0x10000000000ul, address, io_page_size);
-		if ((address & 0xfffffff) == 0) /* segment start */
-			set_iost_cache(base, address >> 28, ioste);
-		index = get_ioc_hash_1way(ioste, address);
+	for (real_address = 0, io_address = 0;
+	     io_address <= map_start + map_size;
+	     real_address += io_page_size, io_address += io_page_size) {
+		ioste = get_iost_entry(fake_iopt, io_address, io_page_size);
+		if ((real_address % io_segment_size) == 0) /* segment start */
+			set_iost_cache(ioc_mmio_base,
+				       io_address >> 28, ioste);
+		index = get_ioc_hash_1way(ioste, io_address);
 		pr_debug("addr %08lx, index %02lx, ioste %016lx\n",
-					 address, index, ioste.val);
-		set_iopt_cache(base,
-			get_ioc_hash_1way(ioste, address),
-			get_ioc_tag(ioste, address),
-			map_iopt_entry(address));
+					 io_address, index, ioste.val);
+		set_iopt_cache(ioc_mmio_base,
+			get_ioc_hash_1way(ioste, io_address),
+			get_ioc_tag(ioste, io_address),
+			get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW));
 	}
-	iounmap(base);
 }
 
+static void iommu_devnode_setup(struct device_node *d)
+{
+	unsigned int *ioid;
+	unsigned long *dma_window, map_start, map_size, token;
+	struct cell_iommu *iommu;
+
+	ioid = (unsigned int *)get_property(d, "ioid", NULL);
+	if (!ioid)
+		pr_debug("No ioid entry found !\n");
+
+	dma_window = (unsigned long *)get_property(d, "ibm,dma-window", NULL);
+	if (!dma_window)
+		pr_debug("No ibm,dma-window entry found !\n");
+
+	map_start = dma_window[1];
+	map_size = dma_window[2];
+	token = dma_window[0] >> 32;
+
+	iommu = &cell_iommus[token];
+
+	cell_do_map_iommu(iommu, *ioid, map_start, map_size);
+}
+
+static void iommu_bus_setup(struct pci_bus *b)
+{
+	struct device_node *d = (struct device_node *)b->sysdata;
+	iommu_devnode_setup(d);
+}
+
+
+static int cell_map_iommu_hardcoded(int num_nodes)
+{
+	struct cell_iommu *iommu = NULL;
+
+	pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
+
+	/* node 0 */
+	iommu = &cell_iommus[0];
+	iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE);
+	iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE);
+
+	enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+	cell_do_map_iommu(iommu, 0x048a,
+			  0x20000000ul,0x20000000ul);
+
+	if (num_nodes < 2)
+		return 0;
+
+	/* node 1 */
+	iommu = &cell_iommus[1];
+	iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE);
+	iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE);
+
+	enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+	cell_do_map_iommu(iommu, 0x048a,
+			  0x20000000,0x20000000ul);
+
+	return 0;
+}
+
+
+static int cell_map_iommu(void)
+{
+	unsigned int num_nodes = 0, *node_id;
+	unsigned long *base, *mmio_base;
+	struct device_node *dn;
+	struct cell_iommu *iommu = NULL;
+
+	/* determine number of nodes (=iommus) */
+	pr_debug("%s(%d): determining number of nodes...", __FUNCTION__, __LINE__);
+	for(dn = of_find_node_by_type(NULL, "cpu");
+	    dn;
+	    dn = of_find_node_by_type(dn, "cpu")) {
+		node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+
+		if (num_nodes < *node_id)
+			num_nodes = *node_id;
+		}
+
+	num_nodes++;
+	pr_debug("%i found.\n", num_nodes);
+
+	/* map the iommu registers for each node */
+	pr_debug("%s(%d): Looping through nodes\n", __FUNCTION__, __LINE__);
+	for(dn = of_find_node_by_type(NULL, "cpu");
+	    dn;
+	    dn = of_find_node_by_type(dn, "cpu")) {
+
+		node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+		base = (unsigned long *)get_property(dn, "ioc-cache", NULL);
+		mmio_base = (unsigned long *)get_property(dn, "ioc-translation", NULL);
+
+		if (!base || !mmio_base || !node_id)
+			return cell_map_iommu_hardcoded(num_nodes);
+
+		iommu = &cell_iommus[*node_id];
+		iommu->base = *base;
+		iommu->mmio_base = *mmio_base;
+
+		iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE);
+		iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE);
+
+		enable_mapping(iommu->mapped_base,
+			       iommu->mapped_mmio_base);
+
+		/* everything else will be done in iommu_bus_setup */
+	}
+
+	return 1;
+}
 
 static void *cell_alloc_coherent(struct device *hwdev, size_t size,
 			   dma_addr_t *dma_handle, gfp_t flag)
@@ -365,11 +475,28 @@
 
 void cell_init_iommu(void)
 {
-	cell_map_iommu();
+	int setup_bus = 0;
 
-	/* Direct I/O, IOMMU off */
-	ppc_md.iommu_dev_setup = iommu_dev_setup_null;
-	ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+	if (of_find_node_by_path("/mambo")) {
+		pr_info("Not using iommu on systemsim\n");
+	} else {
+
+		if (!(of_chosen &&
+		      get_property(of_chosen, "linux,iommu-off", NULL)))
+			setup_bus = cell_map_iommu();
+
+		if (setup_bus) {
+			pr_debug("%s: IOMMU mapping activated\n", __FUNCTION__);
+			ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+			ppc_md.iommu_bus_setup = iommu_bus_setup;
+		} else {
+			pr_debug("%s: IOMMU mapping activated, "
+				 "no device action necessary\n", __FUNCTION__);
+			/* Direct I/O, IOMMU off */
+			ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+			ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+		}
+	}
 
 	pci_dma_ops.alloc_coherent = cell_alloc_coherent;
 	pci_dma_ops.free_coherent = cell_free_coherent;
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
new file mode 100644
index 0000000..85152544
--- /dev/null
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -0,0 +1,229 @@
+/*
+ * CBE Pervasive Monitor and Debug
+ *
+ * (C) Copyright IBM Corporation 2005
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ *          Michael N. Day (mnday@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+#include <linux/kallsyms.h>
+
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/reg.h>
+
+#include "pervasive.h"
+
+static DEFINE_SPINLOCK(cbe_pervasive_lock);
+struct cbe_pervasive {
+	struct pmd_regs __iomem *regs;
+	unsigned int thread;
+};
+
+/* can't use per_cpu from setup_arch */
+static struct cbe_pervasive cbe_pervasive[NR_CPUS];
+
+static void __init cbe_enable_pause_zero(void)
+{
+	unsigned long thread_switch_control;
+	unsigned long temp_register;
+	struct cbe_pervasive *p;
+	int thread;
+
+	spin_lock_irq(&cbe_pervasive_lock);
+	p = &cbe_pervasive[smp_processor_id()];
+
+	if (!cbe_pervasive->regs)
+		goto out;
+
+	pr_debug("Power Management: CPU %d\n", smp_processor_id());
+
+	 /* Enable Pause(0) control bit */
+	temp_register = in_be64(&p->regs->pm_control);
+
+	out_be64(&p->regs->pm_control,
+		 temp_register|PMD_PAUSE_ZERO_CONTROL);
+
+	/* Enable DEC and EE interrupt request */
+	thread_switch_control  = mfspr(SPRN_TSC_CELL);
+	thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
+
+	switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
+	case CTRL_CT0:
+		thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
+		thread = 0;
+		break;
+	case CTRL_CT1:
+		thread_switch_control |= TSC_CELL_DEC_ENABLE_1;
+		thread = 1;
+		break;
+	default:
+		printk(KERN_WARNING "%s: unknown configuration\n",
+			__FUNCTION__);
+		thread = -1;
+		break;
+	}
+
+	if (p->thread != thread)
+		printk(KERN_WARNING "%s: device tree inconsistant, "
+				     "cpu %i: %d/%d\n", __FUNCTION__,
+				     smp_processor_id(),
+				     p->thread, thread);
+
+	mtspr(SPRN_TSC_CELL, thread_switch_control);
+
+out:
+	spin_unlock_irq(&cbe_pervasive_lock);
+}
+
+static void cbe_idle(void)
+{
+	unsigned long ctrl;
+
+	cbe_enable_pause_zero();
+
+	while (1) {
+		if (!need_resched()) {
+			local_irq_disable();
+			while (!need_resched()) {
+				/* go into low thread priority */
+				HMT_low();
+
+				/*
+				 * atomically disable thread execution
+				 * and runlatch.
+				 * External and Decrementer exceptions
+				 * are still handled when the thread
+				 * is disabled but now enter in
+				 * cbe_system_reset_exception()
+				 */
+				ctrl = mfspr(SPRN_CTRLF);
+				ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
+				mtspr(SPRN_CTRLT, ctrl);
+			}
+			/* restore thread prio */
+			HMT_medium();
+			local_irq_enable();
+		}
+
+		/*
+		 * turn runlatch on again before scheduling the
+		 * process we just woke up
+		 */
+		ppc64_runlatch_on();
+
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
+}
+
+int cbe_system_reset_exception(struct pt_regs *regs)
+{
+	switch (regs->msr & SRR1_WAKEMASK) {
+	case SRR1_WAKEEE:
+		do_IRQ(regs);
+		break;
+	case SRR1_WAKEDEC:
+		timer_interrupt(regs);
+		break;
+	case SRR1_WAKEMT:
+		/* no action required */
+		break;
+	default:
+		/* do system reset */
+		return 0;
+	}
+	/* everything handled */
+	return 1;
+}
+
+static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p)
+{
+	struct device_node *node;
+	unsigned int *int_servers;
+	char *addr;
+	unsigned long real_address;
+	unsigned int size;
+
+	struct pmd_regs __iomem *pmd_mmio_area;
+	int hardid, thread;
+	int proplen;
+
+	pmd_mmio_area = NULL;
+	hardid = get_hard_smp_processor_id(cpu);
+	for (node = NULL; (node = of_find_node_by_type(node, "cpu"));) {
+		int_servers = (void *) get_property(node,
+				"ibm,ppc-interrupt-server#s", &proplen);
+		if (!int_servers) {
+			printk(KERN_WARNING "%s misses "
+				"ibm,ppc-interrupt-server#s property",
+				node->full_name);
+			continue;
+		}
+		for (thread = 0; thread < proplen / sizeof (int); thread++) {
+			if (hardid == int_servers[thread]) {
+				addr = get_property(node, "pervasive", NULL);
+				goto found;
+			}
+		}
+	}
+
+	printk(KERN_WARNING "%s: CPU %d not found\n", __FUNCTION__, cpu);
+	return -EINVAL;
+
+found:
+	real_address = *(unsigned long*) addr;
+	addr += sizeof (unsigned long);
+	size = *(unsigned int*) addr;
+
+	pr_debug("pervasive area for CPU %d at %lx, size %x\n",
+			cpu, real_address, size);
+	p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE);
+	p->thread = thread;
+	return 0;
+}
+
+void __init cell_pervasive_init(void)
+{
+	struct cbe_pervasive *p;
+	int cpu;
+	int ret;
+
+	if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
+		return;
+
+	for_each_cpu(cpu) {
+		p = &cbe_pervasive[cpu];
+		ret = cbe_find_pmd_mmio(cpu, p);
+		if (ret)
+			return;
+	}
+
+	ppc_md.idle_loop = cbe_idle;
+	ppc_md.system_reset_exception = cbe_system_reset_exception;
+}
diff --git a/arch/powerpc/platforms/cell/pervasive.h b/arch/powerpc/platforms/cell/pervasive.h
new file mode 100644
index 0000000..da1fb85
--- /dev/null
+++ b/arch/powerpc/platforms/cell/pervasive.h
@@ -0,0 +1,62 @@
+/*
+ * Cell Pervasive Monitor and Debug interface and HW structures
+ *
+ * (C) Copyright IBM Corporation 2005
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ *          David J. Erb (djerb@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef PERVASIVE_H
+#define PERVASIVE_H
+
+struct pmd_regs {
+	u8 pad_0x0000_0x0800[0x0800 - 0x0000];			/* 0x0000 */
+
+	/* Thermal Sensor Registers */
+	u64  ts_ctsr1;						/* 0x0800 */
+	u64  ts_ctsr2;						/* 0x0808 */
+	u64  ts_mtsr1;						/* 0x0810 */
+	u64  ts_mtsr2;						/* 0x0818 */
+	u64  ts_itr1;						/* 0x0820 */
+	u64  ts_itr2;						/* 0x0828 */
+	u64  ts_gitr;						/* 0x0830 */
+	u64  ts_isr;						/* 0x0838 */
+	u64  ts_imr;						/* 0x0840 */
+	u64  tm_cr1;						/* 0x0848 */
+	u64  tm_cr2;						/* 0x0850 */
+	u64  tm_simr;						/* 0x0858 */
+	u64  tm_tpr;						/* 0x0860 */
+	u64  tm_str1;						/* 0x0868 */
+	u64  tm_str2;						/* 0x0870 */
+	u64  tm_tsr;						/* 0x0878 */
+
+	/* Power Management */
+	u64  pm_control;					/* 0x0880 */
+#define PMD_PAUSE_ZERO_CONTROL		0x10000
+	u64  pm_status;						/* 0x0888 */
+
+	/* Time Base Register */
+	u64  tbr;						/* 0x0890 */
+
+	u8   pad_0x0898_0x1000 [0x1000 - 0x0898];		/* 0x0898 */
+};
+
+void __init cell_pervasive_init(void);
+
+#endif
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 9a49563..18e25e6 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -33,6 +33,7 @@
 #include <asm/mmu.h>
 #include <asm/processor.h>
 #include <asm/io.h>
+#include <asm/kexec.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -48,6 +49,7 @@
 
 #include "interrupt.h"
 #include "iommu.h"
+#include "pervasive.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -67,6 +69,77 @@
 	of_node_put(root);
 }
 
+#ifdef CONFIG_SPARSEMEM
+static int __init find_spu_node_id(struct device_node *spe)
+{
+	unsigned int *id;
+#ifdef CONFIG_NUMA
+	struct device_node *cpu;
+	cpu = spe->parent->parent;
+	id = (unsigned int *)get_property(cpu, "node-id", NULL);
+#else
+	id = NULL;
+#endif
+	return id ? *id : 0;
+}
+
+static void __init cell_spuprop_present(struct device_node *spe,
+				       const char *prop, int early)
+{
+	struct address_prop {
+		unsigned long address;
+		unsigned int len;
+	} __attribute__((packed)) *p;
+	int proplen;
+
+	unsigned long start_pfn, end_pfn, pfn;
+	int node_id;
+
+	p = (void*)get_property(spe, prop, &proplen);
+	WARN_ON(proplen != sizeof (*p));
+
+	node_id = find_spu_node_id(spe);
+
+	start_pfn = p->address >> PAGE_SHIFT;
+	end_pfn = (p->address + p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+	/* We need to call memory_present *before* the call to sparse_init,
+	   but we can initialize the page structs only *after* that call.
+	   Thus, we're being called twice. */
+	if (early)
+		memory_present(node_id, start_pfn, end_pfn);
+	else {
+		/* As the pages backing SPU LS and I/O are outside the range
+		   of regular memory, their page structs were not initialized
+		   by free_area_init. Do it here instead. */
+		for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+			struct page *page = pfn_to_page(pfn);
+			set_page_links(page, ZONE_DMA, node_id, pfn);
+			set_page_count(page, 1);
+			reset_page_mapcount(page);
+			SetPageReserved(page);
+			INIT_LIST_HEAD(&page->lru);
+		}
+	}
+}
+
+static void __init cell_spumem_init(int early)
+{
+	struct device_node *node;
+	for (node = of_find_node_by_type(NULL, "spe");
+			node; node = of_find_node_by_type(node, "spe")) {
+		cell_spuprop_present(node, "local-store", early);
+		cell_spuprop_present(node, "problem", early);
+		cell_spuprop_present(node, "priv1", early);
+		cell_spuprop_present(node, "priv2", early);
+	}
+}
+#else
+static void __init cell_spumem_init(int early)
+{
+}
+#endif
+
 static void cell_progress(char *s, unsigned short hex)
 {
 	printk("*** %04x : %s\n", hex, s ? s : "");
@@ -93,11 +166,14 @@
 	init_pci_config_tokens();
 	find_and_init_phbs();
 	spider_init_IRQ();
+	cell_pervasive_init();
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
 
 	mmio_nvram_init();
+
+	cell_spumem_init(0);
 }
 
 /*
@@ -113,6 +189,8 @@
 
 	ppc64_interrupt_controller = IC_CELL_PIC;
 
+	cell_spumem_init(1);
+
 	DBG(" <- cell_init_early()\n");
 }
 
@@ -125,6 +203,15 @@
 	return 1;
 }
 
+/*
+ * Cell has no legacy IO; anything calling this function has to
+ * fail or bad things will happen
+ */
+static int cell_check_legacy_ioport(unsigned int baseport)
+{
+	return -ENODEV;
+}
+
 struct machdep_calls __initdata cell_md = {
 	.probe			= cell_probe,
 	.setup_arch		= cell_setup_arch,
@@ -137,5 +224,11 @@
 	.get_rtc_time		= rtas_get_rtc_time,
 	.set_rtc_time		= rtas_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
+	.check_legacy_ioport	= cell_check_legacy_ioport,
 	.progress		= cell_progress,
+#ifdef CONFIG_KEXEC
+	.machine_kexec		= default_machine_kexec,
+	.machine_kexec_prepare	= default_machine_kexec_prepare,
+	.machine_crash_shutdown	= default_machine_crash_shutdown,
+#endif
 };
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
new file mode 100644
index 0000000..d75ae03
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -0,0 +1,711 @@
+/*
+ * Low-level SPU handling
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/mmu_context.h>
+
+#include "interrupt.h"
+
+static int __spu_trap_invalid_dma(struct spu *spu)
+{
+	pr_debug("%s\n", __FUNCTION__);
+	force_sig(SIGBUS, /* info, */ current);
+	return 0;
+}
+
+static int __spu_trap_dma_align(struct spu *spu)
+{
+	pr_debug("%s\n", __FUNCTION__);
+	force_sig(SIGBUS, /* info, */ current);
+	return 0;
+}
+
+static int __spu_trap_error(struct spu *spu)
+{
+	pr_debug("%s\n", __FUNCTION__);
+	force_sig(SIGILL, /* info, */ current);
+	return 0;
+}
+
+static void spu_restart_dma(struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
+		out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
+}
+
+static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	struct mm_struct *mm = spu->mm;
+	u64 esid, vsid;
+
+	pr_debug("%s\n", __FUNCTION__);
+
+	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
+		/* SLBs are pre-loaded for context switch, so
+		 * we should never get here!
+		 */
+		printk("%s: invalid access during switch!\n", __func__);
+		return 1;
+	}
+	if (!mm || (REGION_ID(ea) != USER_REGION_ID)) {
+		/* Future: support kernel segments so that drivers
+		 * can use SPUs.
+		 */
+		pr_debug("invalid region access at %016lx\n", ea);
+		return 1;
+	}
+
+	esid = (ea & ESID_MASK) | SLB_ESID_V;
+	vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | SLB_VSID_USER;
+	if (in_hugepage_area(mm->context, ea))
+		vsid |= SLB_VSID_L;
+
+	out_be64(&priv2->slb_index_W, spu->slb_replace);
+	out_be64(&priv2->slb_vsid_RW, vsid);
+	out_be64(&priv2->slb_esid_RW, esid);
+
+	spu->slb_replace++;
+	if (spu->slb_replace >= 8)
+		spu->slb_replace = 0;
+
+	spu_restart_dma(spu);
+
+	return 0;
+}
+
+extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
+static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
+{
+	pr_debug("%s\n", __FUNCTION__);
+
+	/* Handle kernel space hash faults immediately.
+	   User hash faults need to be deferred to process context. */
+	if ((dsisr & MFC_DSISR_PTE_NOT_FOUND)
+	    && REGION_ID(ea) != USER_REGION_ID
+	    && hash_page(ea, _PAGE_PRESENT, 0x300) == 0) {
+		spu_restart_dma(spu);
+		return 0;
+	}
+
+	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
+		printk("%s: invalid access during switch!\n", __func__);
+		return 1;
+	}
+
+	spu->dar = ea;
+	spu->dsisr = dsisr;
+	mb();
+	if (spu->stop_callback)
+		spu->stop_callback(spu);
+	return 0;
+}
+
+static int __spu_trap_mailbox(struct spu *spu)
+{
+	if (spu->ibox_callback)
+		spu->ibox_callback(spu);
+
+	/* atomically disable SPU mailbox interrupts */
+	spin_lock(&spu->register_lock);
+	spu_int_mask_and(spu, 2, ~0x1);
+	spin_unlock(&spu->register_lock);
+	return 0;
+}
+
+static int __spu_trap_stop(struct spu *spu)
+{
+	pr_debug("%s\n", __FUNCTION__);
+	spu->stop_code = in_be32(&spu->problem->spu_status_R);
+	if (spu->stop_callback)
+		spu->stop_callback(spu);
+	return 0;
+}
+
+static int __spu_trap_halt(struct spu *spu)
+{
+	pr_debug("%s\n", __FUNCTION__);
+	spu->stop_code = in_be32(&spu->problem->spu_status_R);
+	if (spu->stop_callback)
+		spu->stop_callback(spu);
+	return 0;
+}
+
+static int __spu_trap_tag_group(struct spu *spu)
+{
+	pr_debug("%s\n", __FUNCTION__);
+	/* wake_up(&spu->dma_wq); */
+	return 0;
+}
+
+static int __spu_trap_spubox(struct spu *spu)
+{
+	if (spu->wbox_callback)
+		spu->wbox_callback(spu);
+
+	/* atomically disable SPU mailbox interrupts */
+	spin_lock(&spu->register_lock);
+	spu_int_mask_and(spu, 2, ~0x10);
+	spin_unlock(&spu->register_lock);
+	return 0;
+}
+
+static irqreturn_t
+spu_irq_class_0(int irq, void *data, struct pt_regs *regs)
+{
+	struct spu *spu;
+
+	spu = data;
+	spu->class_0_pending = 1;
+	if (spu->stop_callback)
+		spu->stop_callback(spu);
+
+	return IRQ_HANDLED;
+}
+
+int
+spu_irq_class_0_bottom(struct spu *spu)
+{
+	unsigned long stat, mask;
+
+	spu->class_0_pending = 0;
+
+	mask = spu_int_mask_get(spu, 0);
+	stat = spu_int_stat_get(spu, 0);
+
+	stat &= mask;
+
+	if (stat & 1) /* invalid MFC DMA */
+		__spu_trap_invalid_dma(spu);
+
+	if (stat & 2) /* invalid DMA alignment */
+		__spu_trap_dma_align(spu);
+
+	if (stat & 4) /* error on SPU */
+		__spu_trap_error(spu);
+
+	spu_int_stat_clear(spu, 0, stat);
+
+	return (stat & 0x7) ? -EIO : 0;
+}
+EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
+
+static irqreturn_t
+spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
+{
+	struct spu *spu;
+	unsigned long stat, mask, dar, dsisr;
+
+	spu = data;
+
+	/* atomically read & clear class1 status. */
+	spin_lock(&spu->register_lock);
+	mask  = spu_int_mask_get(spu, 1);
+	stat  = spu_int_stat_get(spu, 1) & mask;
+	dar   = spu_mfc_dar_get(spu);
+	dsisr = spu_mfc_dsisr_get(spu);
+	if (stat & 2) /* mapping fault */
+		spu_mfc_dsisr_set(spu, 0ul);
+	spu_int_stat_clear(spu, 1, stat);
+	spin_unlock(&spu->register_lock);
+
+	if (stat & 1) /* segment fault */
+		__spu_trap_data_seg(spu, dar);
+
+	if (stat & 2) { /* mapping fault */
+		__spu_trap_data_map(spu, dar, dsisr);
+	}
+
+	if (stat & 4) /* ls compare & suspend on get */
+		;
+
+	if (stat & 8) /* ls compare & suspend on put */
+		;
+
+	return stat ? IRQ_HANDLED : IRQ_NONE;
+}
+EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
+
+static irqreturn_t
+spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
+{
+	struct spu *spu;
+	unsigned long stat;
+	unsigned long mask;
+
+	spu = data;
+	stat = spu_int_stat_get(spu, 2);
+	mask = spu_int_mask_get(spu, 2);
+
+	pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
+
+	stat &= mask;
+
+	if (stat & 1)  /* PPC core mailbox */
+		__spu_trap_mailbox(spu);
+
+	if (stat & 2) /* SPU stop-and-signal */
+		__spu_trap_stop(spu);
+
+	if (stat & 4) /* SPU halted */
+		__spu_trap_halt(spu);
+
+	if (stat & 8) /* DMA tag group complete */
+		__spu_trap_tag_group(spu);
+
+	if (stat & 0x10) /* SPU mailbox threshold */
+		__spu_trap_spubox(spu);
+
+	spu_int_stat_clear(spu, 2, stat);
+	return stat ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int
+spu_request_irqs(struct spu *spu)
+{
+	int ret;
+	int irq_base;
+
+	irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;
+
+	snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number);
+	ret = request_irq(irq_base + spu->isrc,
+		 spu_irq_class_0, 0, spu->irq_c0, spu);
+	if (ret)
+		goto out;
+
+	snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
+	ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
+		 spu_irq_class_1, 0, spu->irq_c1, spu);
+	if (ret)
+		goto out1;
+
+	snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number);
+	ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc,
+		 spu_irq_class_2, 0, spu->irq_c2, spu);
+	if (ret)
+		goto out2;
+	goto out;
+
+out2:
+	free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu);
+out1:
+	free_irq(irq_base + spu->isrc, spu);
+out:
+	return ret;
+}
+
+static void
+spu_free_irqs(struct spu *spu)
+{
+	int irq_base;
+
+	irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;
+
+	free_irq(irq_base + spu->isrc, spu);
+	free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu);
+	free_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, spu);
+}
+
+static LIST_HEAD(spu_list);
+static DECLARE_MUTEX(spu_mutex);
+
+static void spu_init_channels(struct spu *spu)
+{
+	static const struct {
+		 unsigned channel;
+		 unsigned count;
+	} zero_list[] = {
+		{ 0x00, 1, }, { 0x01, 1, }, { 0x03, 1, }, { 0x04, 1, },
+		{ 0x18, 1, }, { 0x19, 1, }, { 0x1b, 1, }, { 0x1d, 1, },
+	}, count_list[] = {
+		{ 0x00, 0, }, { 0x03, 0, }, { 0x04, 0, }, { 0x15, 16, },
+		{ 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, },
+		{ 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, },
+	};
+	struct spu_priv2 __iomem *priv2;
+	int i;
+
+	priv2 = spu->priv2;
+
+	/* initialize all channel data to zero */
+	for (i = 0; i < ARRAY_SIZE(zero_list); i++) {
+		int count;
+
+		out_be64(&priv2->spu_chnlcntptr_RW, zero_list[i].channel);
+		for (count = 0; count < zero_list[i].count; count++)
+			out_be64(&priv2->spu_chnldata_RW, 0);
+	}
+
+	/* initialize channel counts to meaningful values */
+	for (i = 0; i < ARRAY_SIZE(count_list); i++) {
+		out_be64(&priv2->spu_chnlcntptr_RW, count_list[i].channel);
+		out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count);
+	}
+}
+
+struct spu *spu_alloc(void)
+{
+	struct spu *spu;
+
+	down(&spu_mutex);
+	if (!list_empty(&spu_list)) {
+		spu = list_entry(spu_list.next, struct spu, list);
+		list_del_init(&spu->list);
+		pr_debug("Got SPU %x %d\n", spu->isrc, spu->number);
+	} else {
+		pr_debug("No SPU left\n");
+		spu = NULL;
+	}
+	up(&spu_mutex);
+
+	if (spu)
+		spu_init_channels(spu);
+
+	return spu;
+}
+EXPORT_SYMBOL_GPL(spu_alloc);
+
+void spu_free(struct spu *spu)
+{
+	down(&spu_mutex);
+	list_add_tail(&spu->list, &spu_list);
+	up(&spu_mutex);
+}
+EXPORT_SYMBOL_GPL(spu_free);
+
+static int spu_handle_mm_fault(struct spu *spu)
+{
+	struct mm_struct *mm = spu->mm;
+	struct vm_area_struct *vma;
+	u64 ea, dsisr, is_write;
+	int ret;
+
+	ea = spu->dar;
+	dsisr = spu->dsisr;
+#if 0
+	if (!IS_VALID_EA(ea)) {
+		return -EFAULT;
+	}
+#endif /* XXX */
+	if (mm == NULL) {
+		return -EFAULT;
+	}
+	if (mm->pgd == NULL) {
+		return -EFAULT;
+	}
+
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, ea);
+	if (!vma)
+		goto bad_area;
+	if (vma->vm_start <= ea)
+		goto good_area;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		goto bad_area;
+#if 0
+	if (expand_stack(vma, ea))
+		goto bad_area;
+#endif /* XXX */
+good_area:
+	is_write = dsisr & MFC_DSISR_ACCESS_PUT;
+	if (is_write) {
+		if (!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	} else {
+		if (dsisr & MFC_DSISR_ACCESS_DENIED)
+			goto bad_area;
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+			goto bad_area;
+	}
+	ret = 0;
+	switch (handle_mm_fault(mm, vma, ea, is_write)) {
+	case VM_FAULT_MINOR:
+		current->min_flt++;
+		break;
+	case VM_FAULT_MAJOR:
+		current->maj_flt++;
+		break;
+	case VM_FAULT_SIGBUS:
+		ret = -EFAULT;
+		goto bad_area;
+	case VM_FAULT_OOM:
+		ret = -ENOMEM;
+		goto bad_area;
+	default:
+		BUG();
+	}
+	up_read(&mm->mmap_sem);
+	return ret;
+
+bad_area:
+	up_read(&mm->mmap_sem);
+	return -EFAULT;
+}
+
+int spu_irq_class_1_bottom(struct spu *spu)
+{
+	u64 ea, dsisr, access, error = 0UL;
+	int ret = 0;
+
+	ea = spu->dar;
+	dsisr = spu->dsisr;
+	if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
+		access = (_PAGE_PRESENT | _PAGE_USER);
+		access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
+		if (hash_page(ea, access, 0x300) != 0)
+			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
+	}
+	if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) ||
+	    (dsisr & MFC_DSISR_ACCESS_DENIED)) {
+		if ((ret = spu_handle_mm_fault(spu)) != 0)
+			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
+		else
+			error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
+	}
+	spu->dar = 0UL;
+	spu->dsisr = 0UL;
+	if (!error) {
+		spu_restart_dma(spu);
+	} else {
+		__spu_trap_invalid_dma(spu);
+	}
+	return ret;
+}
+
+void spu_irq_setaffinity(struct spu *spu, int cpu)
+{
+	u64 target = iic_get_target_id(cpu);
+	u64 route = target << 48 | target << 32 | target << 16;
+	spu_int_route_set(spu, route);
+}
+EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
+
+static void __iomem * __init map_spe_prop(struct device_node *n,
+						 const char *name)
+{
+	struct address_prop {
+		unsigned long address;
+		unsigned int len;
+	} __attribute__((packed)) *prop;
+
+	void *p;
+	int proplen;
+
+	p = get_property(n, name, &proplen);
+	if (proplen != sizeof (struct address_prop))
+		return NULL;
+
+	prop = p;
+
+	return ioremap(prop->address, prop->len);
+}
+
+static void spu_unmap(struct spu *spu)
+{
+	iounmap(spu->priv2);
+	iounmap(spu->priv1);
+	iounmap(spu->problem);
+	iounmap((u8 __iomem *)spu->local_store);
+}
+
+static int __init spu_map_device(struct spu *spu, struct device_node *spe)
+{
+	char *prop;
+	int ret;
+
+	ret = -ENODEV;
+	prop = get_property(spe, "isrc", NULL);
+	if (!prop)
+		goto out;
+	spu->isrc = *(unsigned int *)prop;
+
+	spu->name = get_property(spe, "name", NULL);
+	if (!spu->name)
+		goto out;
+
+	prop = get_property(spe, "local-store", NULL);
+	if (!prop)
+		goto out;
+	spu->local_store_phys = *(unsigned long *)prop;
+
+	/* we use local store as ram, not io memory */
+	spu->local_store = (void __force *)map_spe_prop(spe, "local-store");
+	if (!spu->local_store)
+		goto out;
+
+	spu->problem= map_spe_prop(spe, "problem");
+	if (!spu->problem)
+		goto out_unmap;
+
+	spu->priv1= map_spe_prop(spe, "priv1");
+	/* priv1 is not available on a hypervisor */
+
+	spu->priv2= map_spe_prop(spe, "priv2");
+	if (!spu->priv2)
+		goto out_unmap;
+	ret = 0;
+	goto out;
+
+out_unmap:
+	spu_unmap(spu);
+out:
+	return ret;
+}
+
+static int __init find_spu_node_id(struct device_node *spe)
+{
+	unsigned int *id;
+	struct device_node *cpu;
+
+	cpu = spe->parent->parent;
+	id = (unsigned int *)get_property(cpu, "node-id", NULL);
+
+	return id ? *id : 0;
+}
+
+static int __init create_spu(struct device_node *spe)
+{
+	struct spu *spu;
+	int ret;
+	static int number;
+
+	ret = -ENOMEM;
+	spu = kmalloc(sizeof (*spu), GFP_KERNEL);
+	if (!spu)
+		goto out;
+
+	ret = spu_map_device(spu, spe);
+	if (ret)
+		goto out_free;
+
+	spu->node = find_spu_node_id(spe);
+	spu->stop_code = 0;
+	spu->slb_replace = 0;
+	spu->mm = NULL;
+	spu->ctx = NULL;
+	spu->rq = NULL;
+	spu->pid = 0;
+	spu->class_0_pending = 0;
+	spu->flags = 0UL;
+	spu->dar = 0UL;
+	spu->dsisr = 0UL;
+	spin_lock_init(&spu->register_lock);
+
+	spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
+	spu_mfc_sr1_set(spu, 0x33);
+
+	spu->ibox_callback = NULL;
+	spu->wbox_callback = NULL;
+	spu->stop_callback = NULL;
+
+	down(&spu_mutex);
+	spu->number = number++;
+	ret = spu_request_irqs(spu);
+	if (ret)
+		goto out_unmap;
+
+	list_add(&spu->list, &spu_list);
+	up(&spu_mutex);
+
+	pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
+		spu->name, spu->isrc, spu->local_store,
+		spu->problem, spu->priv1, spu->priv2, spu->number);
+	goto out;
+
+out_unmap:
+	up(&spu_mutex);
+	spu_unmap(spu);
+out_free:
+	kfree(spu);
+out:
+	return ret;
+}
+
+static void destroy_spu(struct spu *spu)
+{
+	list_del_init(&spu->list);
+
+	spu_free_irqs(spu);
+	spu_unmap(spu);
+	kfree(spu);
+}
+
+static void cleanup_spu_base(void)
+{
+	struct spu *spu, *tmp;
+	down(&spu_mutex);
+	list_for_each_entry_safe(spu, tmp, &spu_list, list)
+		destroy_spu(spu);
+	up(&spu_mutex);
+}
+module_exit(cleanup_spu_base);
+
+static int __init init_spu_base(void)
+{
+	struct device_node *node;
+	int ret;
+
+	ret = -ENODEV;
+	for (node = of_find_node_by_type(NULL, "spe");
+			node; node = of_find_node_by_type(node, "spe")) {
+		ret = create_spu(node);
+		if (ret) {
+			printk(KERN_WARNING "%s: Error initializing %s\n",
+				__FUNCTION__, node->name);
+			cleanup_spu_base();
+			break;
+		}
+	}
+	/* in some old firmware versions, the spe is called 'spc', so we
+	   look for that as well */
+	for (node = of_find_node_by_type(NULL, "spc");
+			node; node = of_find_node_by_type(node, "spc")) {
+		ret = create_spu(node);
+		if (ret) {
+			printk(KERN_WARNING "%s: Error initializing %s\n",
+				__FUNCTION__, node->name);
+			cleanup_spu_base();
+			break;
+		}
+	}
+	return ret;
+}
+module_init(init_spu_base);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
diff --git a/arch/powerpc/platforms/cell/spu_priv1.c b/arch/powerpc/platforms/cell/spu_priv1.c
new file mode 100644
index 0000000..b265642
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_priv1.c
@@ -0,0 +1,133 @@
+/*
+ * access to SPU privileged registers
+ */
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+
+void spu_int_mask_and(struct spu *spu, int class, u64 mask)
+{
+	u64 old_mask;
+
+	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+	out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_and);
+
+void spu_int_mask_or(struct spu *spu, int class, u64 mask)
+{
+	u64 old_mask;
+
+	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+	out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_or);
+
+void spu_int_mask_set(struct spu *spu, int class, u64 mask)
+{
+	out_be64(&spu->priv1->int_mask_RW[class], mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_set);
+
+u64 spu_int_mask_get(struct spu *spu, int class)
+{
+	return in_be64(&spu->priv1->int_mask_RW[class]);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_get);
+
+void spu_int_stat_clear(struct spu *spu, int class, u64 stat)
+{
+	out_be64(&spu->priv1->int_stat_RW[class], stat);
+}
+EXPORT_SYMBOL_GPL(spu_int_stat_clear);
+
+u64 spu_int_stat_get(struct spu *spu, int class)
+{
+	return in_be64(&spu->priv1->int_stat_RW[class]);
+}
+EXPORT_SYMBOL_GPL(spu_int_stat_get);
+
+void spu_int_route_set(struct spu *spu, u64 route)
+{
+	out_be64(&spu->priv1->int_route_RW, route);
+}
+EXPORT_SYMBOL_GPL(spu_int_route_set);
+
+u64 spu_mfc_dar_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->mfc_dar_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dar_get);
+
+u64 spu_mfc_dsisr_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->mfc_dsisr_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dsisr_get);
+
+void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr)
+{
+	out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dsisr_set);
+
+void spu_mfc_sdr_set(struct spu *spu, u64 sdr)
+{
+	out_be64(&spu->priv1->mfc_sdr_RW, sdr);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sdr_set);
+
+void spu_mfc_sr1_set(struct spu *spu, u64 sr1)
+{
+	out_be64(&spu->priv1->mfc_sr1_RW, sr1);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sr1_set);
+
+u64 spu_mfc_sr1_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->mfc_sr1_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sr1_get);
+
+void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
+{
+	out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_set);
+
+u64 spu_mfc_tclass_id_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->mfc_tclass_id_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_get);
+
+void spu_tlb_invalidate(struct spu *spu)
+{
+	out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
+}
+EXPORT_SYMBOL_GPL(spu_tlb_invalidate);
+
+void spu_resource_allocation_groupID_set(struct spu *spu, u64 id)
+{
+	out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_set);
+
+u64 spu_resource_allocation_groupID_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->resource_allocation_groupID_RW);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_get);
+
+void spu_resource_allocation_enable_set(struct spu *spu, u64 enable)
+{
+	out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_set);
+
+u64 spu_resource_allocation_enable_get(struct spu *spu)
+{
+	return in_be64(&spu->priv1->resource_allocation_enable_RW);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_get);
diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c
new file mode 100644
index 0000000..261b507
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_syscalls.c
@@ -0,0 +1,88 @@
+/*
+ * SPU file system -- system call stubs
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+#include <asm/spu.h>
+
+struct spufs_calls spufs_calls = {
+	.owner = NULL,
+};
+
+/* These stub syscalls are needed to have the actual implementation
+ * within a loadable module. When spufs is built into the kernel,
+ * this file is not used and the syscalls directly enter the fs code */
+
+asmlinkage long sys_spu_create(const char __user *name,
+		unsigned int flags, mode_t mode)
+{
+	long ret;
+	struct module *owner = spufs_calls.owner;
+
+	ret = -ENOSYS;
+	if (owner && try_module_get(owner)) {
+		ret = spufs_calls.create_thread(name, flags, mode);
+		module_put(owner);
+	}
+	return ret;
+}
+
+asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
+{
+	long ret;
+	struct file *filp;
+	int fput_needed;
+	struct module *owner = spufs_calls.owner;
+
+	ret = -ENOSYS;
+	if (owner && try_module_get(owner)) {
+		ret = -EBADF;
+		filp = fget_light(fd, &fput_needed);
+		if (filp) {
+			ret = spufs_calls.spu_run(filp, unpc, ustatus);
+			fput_light(filp, fput_needed);
+		}
+		module_put(owner);
+	}
+	return ret;
+}
+
+int register_spu_syscalls(struct spufs_calls *calls)
+{
+	if (spufs_calls.owner)
+		return -EBUSY;
+
+	spufs_calls.create_thread = calls->create_thread;
+	spufs_calls.spu_run = calls->spu_run;
+	smp_mb();
+	spufs_calls.owner = calls->owner;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(register_spu_syscalls);
+
+void unregister_spu_syscalls(struct spufs_calls *calls)
+{
+	BUG_ON(spufs_calls.owner != calls->owner);
+	spufs_calls.owner = NULL;
+}
+EXPORT_SYMBOL_GPL(unregister_spu_syscalls);
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
new file mode 100644
index 0000000..a7cddf4
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -0,0 +1,54 @@
+obj-$(CONFIG_SPU_FS) += spufs.o
+spufs-y += inode.o file.o context.o switch.o syscalls.o
+spufs-y += sched.o backing_ops.o hw_ops.o run.o
+
+# Rules to build switch.o with the help of SPU tool chain
+SPU_CROSS	:= spu-
+SPU_CC		:= $(SPU_CROSS)gcc
+SPU_AS		:= $(SPU_CROSS)gcc
+SPU_LD		:= $(SPU_CROSS)ld
+SPU_OBJCOPY	:= $(SPU_CROSS)objcopy
+SPU_CFLAGS	:= -O2 -Wall -I$(srctree)/include -I$(objtree)/include2
+SPU_AFLAGS	:= -c -D__ASSEMBLY__ -I$(srctree)/include -I$(objtree)/include2
+SPU_LDFLAGS	:= -N -Ttext=0x0
+
+$(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h
+
+# Compile SPU files
+      cmd_spu_cc = $(SPU_CC) $(SPU_CFLAGS) -c -o $@ $<
+quiet_cmd_spu_cc = SPU_CC  $@
+$(obj)/spu_%.o: $(src)/spu_%.c
+	$(call if_changed,spu_cc)
+
+# Assemble SPU files
+      cmd_spu_as = $(SPU_AS) $(SPU_AFLAGS) -o $@ $<
+quiet_cmd_spu_as = SPU_AS  $@
+$(obj)/spu_%.o: $(src)/spu_%.S
+	$(call if_changed,spu_as)
+
+# Link SPU Executables
+      cmd_spu_ld = $(SPU_LD) $(SPU_LDFLAGS) -o $@ $^
+quiet_cmd_spu_ld = SPU_LD  $@
+$(obj)/spu_%: $(obj)/spu_%_crt0.o $(obj)/spu_%.o
+	$(call if_changed,spu_ld)
+
+# Copy into binary format
+      cmd_spu_objcopy = $(SPU_OBJCOPY) -O binary $< $@
+quiet_cmd_spu_objcopy = OBJCOPY $@
+$(obj)/spu_%.bin: $(src)/spu_%
+	$(call if_changed,spu_objcopy)
+
+# create C code from ELF executable
+cmd_hexdump   = ( \
+		echo "/*" ; \
+		echo " * $*_dump.h: Copyright (C) 2005 IBM." ; \
+		echo " * Hex-dump auto generated from $*.c." ; \
+		echo " * Do not edit!" ; \
+		echo " */" ; \
+		echo "static unsigned int $*_code[] __page_aligned = {" ; \
+		hexdump -v -e '"0x" 4/1 "%02x" "," "\n"' $< ; \
+		echo "};" ; \
+		) > $@
+quiet_cmd_hexdump = HEXDUMP $@
+$(obj)/%_dump.h: $(obj)/%.bin
+	$(call if_changed,hexdump)
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
new file mode 100644
index 0000000..a5c489a5
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -0,0 +1,308 @@
+/* backing_ops.c - query/set operations on saved SPU context.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * These register operations allow SPUFS to operate on saved
+ * SPU contexts rather than hardware.
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/poll.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+#include "spufs.h"
+
+/*
+ * Reads/writes to various problem and priv2 registers require
+ * state changes, i.e.  generate SPU events, modify channel
+ * counts, etc.
+ */
+
+static void gen_spu_event(struct spu_context *ctx, u32 event)
+{
+	u64 ch0_cnt;
+	u64 ch0_data;
+	u64 ch1_data;
+
+	ch0_cnt = ctx->csa.spu_chnlcnt_RW[0];
+	ch0_data = ctx->csa.spu_chnldata_RW[0];
+	ch1_data = ctx->csa.spu_chnldata_RW[1];
+	ctx->csa.spu_chnldata_RW[0] |= event;
+	if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) {
+		ctx->csa.spu_chnlcnt_RW[0] = 1;
+	}
+}
+
+static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data)
+{
+	u32 mbox_stat;
+	int ret = 0;
+
+	spin_lock(&ctx->csa.register_lock);
+	mbox_stat = ctx->csa.prob.mb_stat_R;
+	if (mbox_stat & 0x0000ff) {
+		/* Read the first available word.
+		 * Implementation note: the depth
+		 * of pu_mb_R is currently 1.
+		 */
+		*data = ctx->csa.prob.pu_mb_R;
+		ctx->csa.prob.mb_stat_R &= ~(0x0000ff);
+		ctx->csa.spu_chnlcnt_RW[28] = 1;
+		gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT);
+		ret = 4;
+	}
+	spin_unlock(&ctx->csa.register_lock);
+	return ret;
+}
+
+static u32 spu_backing_mbox_stat_read(struct spu_context *ctx)
+{
+	return ctx->csa.prob.mb_stat_R;
+}
+
+static unsigned int spu_backing_mbox_stat_poll(struct spu_context *ctx,
+					  unsigned int events)
+{
+	int ret;
+	u32 stat;
+
+	ret = 0;
+	spin_lock_irq(&ctx->csa.register_lock);
+	stat = ctx->csa.prob.mb_stat_R;
+
+	/* if the requested event is there, return the poll
+	   mask, otherwise enable the interrupt to get notified,
+	   but first mark any pending interrupts as done so
+	   we don't get woken up unnecessarily */
+
+	if (events & (POLLIN | POLLRDNORM)) {
+		if (stat & 0xff0000)
+			ret |= POLLIN | POLLRDNORM;
+		else {
+			ctx->csa.priv1.int_stat_class0_RW &= ~0x1;
+			ctx->csa.priv1.int_mask_class2_RW |= 0x1;
+		}
+	}
+	if (events & (POLLOUT | POLLWRNORM)) {
+		if (stat & 0x00ff00)
+			ret = POLLOUT | POLLWRNORM;
+		else {
+			ctx->csa.priv1.int_stat_class0_RW &= ~0x10;
+			ctx->csa.priv1.int_mask_class2_RW |= 0x10;
+		}
+	}
+	spin_unlock_irq(&ctx->csa.register_lock);
+	return ret;
+}
+
+static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data)
+{
+	int ret;
+
+	spin_lock(&ctx->csa.register_lock);
+	if (ctx->csa.prob.mb_stat_R & 0xff0000) {
+		/* Read the first available word.
+		 * Implementation note: the depth
+		 * of puint_mb_R is currently 1.
+		 */
+		*data = ctx->csa.priv2.puint_mb_R;
+		ctx->csa.prob.mb_stat_R &= ~(0xff0000);
+		ctx->csa.spu_chnlcnt_RW[30] = 1;
+		gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT);
+		ret = 4;
+	} else {
+		/* make sure we get woken up by the interrupt */
+		ctx->csa.priv1.int_mask_class2_RW |= 0x1UL;
+		ret = 0;
+	}
+	spin_unlock(&ctx->csa.register_lock);
+	return ret;
+}
+
+static int spu_backing_wbox_write(struct spu_context *ctx, u32 data)
+{
+	int ret;
+
+	spin_lock(&ctx->csa.register_lock);
+	if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) {
+		int slot = ctx->csa.spu_chnlcnt_RW[29];
+		int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8;
+
+		/* We have space to write wbox_data.
+		 * Implementation note: the depth
+		 * of spu_mb_W is currently 4.
+		 */
+		BUG_ON(avail != (4 - slot));
+		ctx->csa.spu_mailbox_data[slot] = data;
+		ctx->csa.spu_chnlcnt_RW[29] = ++slot;
+		ctx->csa.prob.mb_stat_R = (((4 - slot) & 0xff) << 8);
+		gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT);
+		ret = 4;
+	} else {
+		/* make sure we get woken up by the interrupt when space
+		   becomes available */
+		ctx->csa.priv1.int_mask_class2_RW |= 0x10;
+		ret = 0;
+	}
+	spin_unlock(&ctx->csa.register_lock);
+	return ret;
+}
+
+static u32 spu_backing_signal1_read(struct spu_context *ctx)
+{
+	return ctx->csa.spu_chnldata_RW[3];
+}
+
+static void spu_backing_signal1_write(struct spu_context *ctx, u32 data)
+{
+	spin_lock(&ctx->csa.register_lock);
+	if (ctx->csa.priv2.spu_cfg_RW & 0x1)
+		ctx->csa.spu_chnldata_RW[3] |= data;
+	else
+		ctx->csa.spu_chnldata_RW[3] = data;
+	ctx->csa.spu_chnlcnt_RW[3] = 1;
+	gen_spu_event(ctx, MFC_SIGNAL_1_EVENT);
+	spin_unlock(&ctx->csa.register_lock);
+}
+
+static u32 spu_backing_signal2_read(struct spu_context *ctx)
+{
+	return ctx->csa.spu_chnldata_RW[4];
+}
+
+static void spu_backing_signal2_write(struct spu_context *ctx, u32 data)
+{
+	spin_lock(&ctx->csa.register_lock);
+	if (ctx->csa.priv2.spu_cfg_RW & 0x2)
+		ctx->csa.spu_chnldata_RW[4] |= data;
+	else
+		ctx->csa.spu_chnldata_RW[4] = data;
+	ctx->csa.spu_chnlcnt_RW[4] = 1;
+	gen_spu_event(ctx, MFC_SIGNAL_2_EVENT);
+	spin_unlock(&ctx->csa.register_lock);
+}
+
+static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val)
+{
+	u64 tmp;
+
+	spin_lock(&ctx->csa.register_lock);
+	tmp = ctx->csa.priv2.spu_cfg_RW;
+	if (val)
+		tmp |= 1;
+	else
+		tmp &= ~1;
+	ctx->csa.priv2.spu_cfg_RW = tmp;
+	spin_unlock(&ctx->csa.register_lock);
+}
+
+static u64 spu_backing_signal1_type_get(struct spu_context *ctx)
+{
+	return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0);
+}
+
+static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val)
+{
+	u64 tmp;
+
+	spin_lock(&ctx->csa.register_lock);
+	tmp = ctx->csa.priv2.spu_cfg_RW;
+	if (val)
+		tmp |= 2;
+	else
+		tmp &= ~2;
+	ctx->csa.priv2.spu_cfg_RW = tmp;
+	spin_unlock(&ctx->csa.register_lock);
+}
+
+static u64 spu_backing_signal2_type_get(struct spu_context *ctx)
+{
+	return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0);
+}
+
+static u32 spu_backing_npc_read(struct spu_context *ctx)
+{
+	return ctx->csa.prob.spu_npc_RW;
+}
+
+static void spu_backing_npc_write(struct spu_context *ctx, u32 val)
+{
+	ctx->csa.prob.spu_npc_RW = val;
+}
+
+static u32 spu_backing_status_read(struct spu_context *ctx)
+{
+	return ctx->csa.prob.spu_status_R;
+}
+
+static char *spu_backing_get_ls(struct spu_context *ctx)
+{
+	return ctx->csa.lscsa->ls;
+}
+
+static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val)
+{
+	spin_lock(&ctx->csa.register_lock);
+	ctx->csa.prob.spu_runcntl_RW = val;
+	if (val & SPU_RUNCNTL_RUNNABLE) {
+		ctx->csa.prob.spu_status_R |= SPU_STATUS_RUNNING;
+	} else {
+		ctx->csa.prob.spu_status_R &= ~SPU_STATUS_RUNNING;
+	}
+	spin_unlock(&ctx->csa.register_lock);
+}
+
+static void spu_backing_runcntl_stop(struct spu_context *ctx)
+{
+	spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
+}
+
+struct spu_context_ops spu_backing_ops = {
+	.mbox_read = spu_backing_mbox_read,
+	.mbox_stat_read = spu_backing_mbox_stat_read,
+	.mbox_stat_poll = spu_backing_mbox_stat_poll,
+	.ibox_read = spu_backing_ibox_read,
+	.wbox_write = spu_backing_wbox_write,
+	.signal1_read = spu_backing_signal1_read,
+	.signal1_write = spu_backing_signal1_write,
+	.signal2_read = spu_backing_signal2_read,
+	.signal2_write = spu_backing_signal2_write,
+	.signal1_type_set = spu_backing_signal1_type_set,
+	.signal1_type_get = spu_backing_signal1_type_get,
+	.signal2_type_set = spu_backing_signal2_type_set,
+	.signal2_type_get = spu_backing_signal2_type_get,
+	.npc_read = spu_backing_npc_read,
+	.npc_write = spu_backing_npc_write,
+	.status_read = spu_backing_status_read,
+	.get_ls = spu_backing_get_ls,
+	.runcntl_write = spu_backing_runcntl_write,
+	.runcntl_stop = spu_backing_runcntl_stop,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
new file mode 100644
index 0000000..336f238
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -0,0 +1,167 @@
+/*
+ * SPU file system -- SPU context management
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include "spufs.h"
+
+struct spu_context *alloc_spu_context(struct address_space *local_store)
+{
+	struct spu_context *ctx;
+	ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		goto out;
+	/* Binding to physical processor deferred
+	 * until spu_activate().
+	 */
+	spu_init_csa(&ctx->csa);
+	if (!ctx->csa.lscsa) {
+		goto out_free;
+	}
+	spin_lock_init(&ctx->mmio_lock);
+	kref_init(&ctx->kref);
+	init_rwsem(&ctx->state_sema);
+	init_MUTEX(&ctx->run_sema);
+	init_waitqueue_head(&ctx->ibox_wq);
+	init_waitqueue_head(&ctx->wbox_wq);
+	init_waitqueue_head(&ctx->stop_wq);
+	ctx->ibox_fasync = NULL;
+	ctx->wbox_fasync = NULL;
+	ctx->state = SPU_STATE_SAVED;
+	ctx->local_store = local_store;
+	ctx->spu = NULL;
+	ctx->ops = &spu_backing_ops;
+	ctx->owner = get_task_mm(current);
+	goto out;
+out_free:
+	kfree(ctx);
+	ctx = NULL;
+out:
+	return ctx;
+}
+
+void destroy_spu_context(struct kref *kref)
+{
+	struct spu_context *ctx;
+	ctx = container_of(kref, struct spu_context, kref);
+	down_write(&ctx->state_sema);
+	spu_deactivate(ctx);
+	ctx->ibox_fasync = NULL;
+	ctx->wbox_fasync = NULL;
+	up_write(&ctx->state_sema);
+	spu_fini_csa(&ctx->csa);
+	kfree(ctx);
+}
+
+struct spu_context * get_spu_context(struct spu_context *ctx)
+{
+	kref_get(&ctx->kref);
+	return ctx;
+}
+
+int put_spu_context(struct spu_context *ctx)
+{
+	return kref_put(&ctx->kref, &destroy_spu_context);
+}
+
+/* give up the mm reference when the context is about to be destroyed */
+void spu_forget(struct spu_context *ctx)
+{
+	struct mm_struct *mm;
+	spu_acquire_saved(ctx);
+	mm = ctx->owner;
+	ctx->owner = NULL;
+	mmput(mm);
+	spu_release(ctx);
+}
+
+void spu_acquire(struct spu_context *ctx)
+{
+	down_read(&ctx->state_sema);
+}
+
+void spu_release(struct spu_context *ctx)
+{
+	up_read(&ctx->state_sema);
+}
+
+void spu_unmap_mappings(struct spu_context *ctx)
+{
+	unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+}
+
+int spu_acquire_runnable(struct spu_context *ctx)
+{
+	int ret = 0;
+
+	down_read(&ctx->state_sema);
+	if (ctx->state == SPU_STATE_RUNNABLE) {
+		ctx->spu->prio = current->prio;
+		return 0;
+	}
+	up_read(&ctx->state_sema);
+
+	down_write(&ctx->state_sema);
+	/* ctx is about to be freed, can't acquire any more */
+	if (!ctx->owner) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (ctx->state == SPU_STATE_SAVED) {
+		ret = spu_activate(ctx, 0);
+		if (ret)
+			goto out;
+		ctx->state = SPU_STATE_RUNNABLE;
+	}
+
+	downgrade_write(&ctx->state_sema);
+	/* On success, we return holding the lock */
+
+	return ret;
+out:
+	/* Release here, to simplify calling code. */
+	up_write(&ctx->state_sema);
+
+	return ret;
+}
+
+void spu_acquire_saved(struct spu_context *ctx)
+{
+	down_read(&ctx->state_sema);
+
+	if (ctx->state == SPU_STATE_SAVED)
+		return;
+
+	up_read(&ctx->state_sema);
+	down_write(&ctx->state_sema);
+
+	if (ctx->state == SPU_STATE_RUNNABLE) {
+		spu_deactivate(ctx);
+		ctx->state = SPU_STATE_SAVED;
+	}
+
+	downgrade_write(&ctx->state_sema);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
new file mode 100644
index 0000000..dfa649c
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -0,0 +1,794 @@
+/*
+ * SPU file system -- file contents
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/ptrace.h>
+
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+
+static int
+spufs_mem_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	file->private_data = i->i_ctx;
+	file->f_mapping = i->i_ctx->local_store;
+	return 0;
+}
+
+static ssize_t
+spufs_mem_read(struct file *file, char __user *buffer,
+				size_t size, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	char *local_store;
+	int ret;
+
+	spu_acquire(ctx);
+
+	local_store = ctx->ops->get_ls(ctx);
+	ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
+
+	spu_release(ctx);
+	return ret;
+}
+
+static ssize_t
+spufs_mem_write(struct file *file, const char __user *buffer,
+					size_t size, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	char *local_store;
+	int ret;
+
+	size = min_t(ssize_t, LS_SIZE - *pos, size);
+	if (size <= 0)
+		return -EFBIG;
+	*pos += size;
+
+	spu_acquire(ctx);
+
+	local_store = ctx->ops->get_ls(ctx);
+	ret = copy_from_user(local_store + *pos - size,
+			     buffer, size) ? -EFAULT : size;
+
+	spu_release(ctx);
+	return ret;
+}
+
+#ifdef CONFIG_SPARSEMEM
+static struct page *
+spufs_mem_mmap_nopage(struct vm_area_struct *vma,
+		      unsigned long address, int *type)
+{
+	struct page *page = NOPAGE_SIGBUS;
+
+	struct spu_context *ctx = vma->vm_file->private_data;
+	unsigned long offset = address - vma->vm_start;
+	offset += vma->vm_pgoff << PAGE_SHIFT;
+
+	spu_acquire(ctx);
+
+	if (ctx->state == SPU_STATE_SAVED)
+		page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
+	else
+		page = pfn_to_page((ctx->spu->local_store_phys + offset)
+				   >> PAGE_SHIFT);
+
+	spu_release(ctx);
+
+	if (type)
+		*type = VM_FAULT_MINOR;
+
+	page_cache_get(page);
+	return page;
+}
+
+static struct vm_operations_struct spufs_mem_mmap_vmops = {
+	.nopage = spufs_mem_mmap_nopage,
+};
+
+static int
+spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (!(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	/* FIXME: */
+	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+				     | _PAGE_NO_CACHE);
+
+	vma->vm_ops = &spufs_mem_mmap_vmops;
+	return 0;
+}
+#endif
+
+static struct file_operations spufs_mem_fops = {
+	.open	 = spufs_mem_open,
+	.read    = spufs_mem_read,
+	.write   = spufs_mem_write,
+	.llseek  = generic_file_llseek,
+#ifdef CONFIG_SPARSEMEM
+	.mmap    = spufs_mem_mmap,
+#endif
+};
+
+static int
+spufs_regs_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	file->private_data = i->i_ctx;
+	return 0;
+}
+
+static ssize_t
+spufs_regs_read(struct file *file, char __user *buffer,
+		size_t size, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	int ret;
+
+	spu_acquire_saved(ctx);
+
+	ret = simple_read_from_buffer(buffer, size, pos,
+				      lscsa->gprs, sizeof lscsa->gprs);
+
+	spu_release(ctx);
+	return ret;
+}
+
+static ssize_t
+spufs_regs_write(struct file *file, const char __user *buffer,
+		 size_t size, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	int ret;
+
+	size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
+	if (size <= 0)
+		return -EFBIG;
+	*pos += size;
+
+	spu_acquire_saved(ctx);
+
+	ret = copy_from_user(lscsa->gprs + *pos - size,
+			     buffer, size) ? -EFAULT : size;
+
+	spu_release(ctx);
+	return ret;
+}
+
+static struct file_operations spufs_regs_fops = {
+	.open	 = spufs_regs_open,
+	.read    = spufs_regs_read,
+	.write   = spufs_regs_write,
+	.llseek  = generic_file_llseek,
+};
+
+static ssize_t
+spufs_fpcr_read(struct file *file, char __user * buffer,
+		size_t size, loff_t * pos)
+{
+	struct spu_context *ctx = file->private_data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	int ret;
+
+	spu_acquire_saved(ctx);
+
+	ret = simple_read_from_buffer(buffer, size, pos,
+				      &lscsa->fpcr, sizeof(lscsa->fpcr));
+
+	spu_release(ctx);
+	return ret;
+}
+
+static ssize_t
+spufs_fpcr_write(struct file *file, const char __user * buffer,
+		 size_t size, loff_t * pos)
+{
+	struct spu_context *ctx = file->private_data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	int ret;
+
+	size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
+	if (size <= 0)
+		return -EFBIG;
+	*pos += size;
+
+	spu_acquire_saved(ctx);
+
+	ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
+			     buffer, size) ? -EFAULT : size;
+
+	spu_release(ctx);
+	return ret;
+}
+
+static struct file_operations spufs_fpcr_fops = {
+	.open = spufs_regs_open,
+	.read = spufs_fpcr_read,
+	.write = spufs_fpcr_write,
+	.llseek = generic_file_llseek,
+};
+
+/* generic open function for all pipe-like files */
+static int spufs_pipe_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	file->private_data = i->i_ctx;
+
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 mbox_data;
+	int ret;
+
+	if (len < 4)
+		return -EINVAL;
+
+	spu_acquire(ctx);
+	ret = ctx->ops->mbox_read(ctx, &mbox_data);
+	spu_release(ctx);
+
+	if (!ret)
+		return -EAGAIN;
+
+	if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
+		return -EFAULT;
+
+	return 4;
+}
+
+static struct file_operations spufs_mbox_fops = {
+	.open	= spufs_pipe_open,
+	.read	= spufs_mbox_read,
+};
+
+static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 mbox_stat;
+
+	if (len < 4)
+		return -EINVAL;
+
+	spu_acquire(ctx);
+
+	mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
+
+	spu_release(ctx);
+
+	if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
+		return -EFAULT;
+
+	return 4;
+}
+
+static struct file_operations spufs_mbox_stat_fops = {
+	.open	= spufs_pipe_open,
+	.read	= spufs_mbox_stat_read,
+};
+
+/* low-level ibox access function */
+size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
+{
+	return ctx->ops->ibox_read(ctx, data);
+}
+
+static int spufs_ibox_fasync(int fd, struct file *file, int on)
+{
+	struct spu_context *ctx = file->private_data;
+
+	return fasync_helper(fd, file, on, &ctx->ibox_fasync);
+}
+
+/* interrupt-level ibox callback function. */
+void spufs_ibox_callback(struct spu *spu)
+{
+	struct spu_context *ctx = spu->ctx;
+
+	wake_up_all(&ctx->ibox_wq);
+	kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
+}
+
+static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 ibox_data;
+	ssize_t ret;
+
+	if (len < 4)
+		return -EINVAL;
+
+	spu_acquire(ctx);
+
+	ret = 0;
+	if (file->f_flags & O_NONBLOCK) {
+		if (!spu_ibox_read(ctx, &ibox_data))
+			ret = -EAGAIN;
+	} else {
+		ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
+	}
+
+	spu_release(ctx);
+
+	if (ret)
+		return ret;
+
+	ret = 4;
+	if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
+{
+	struct spu_context *ctx = file->private_data;
+	unsigned int mask;
+
+	poll_wait(file, &ctx->ibox_wq, wait);
+
+	spu_acquire(ctx);
+	mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM);
+	spu_release(ctx);
+
+	return mask;
+}
+
+static struct file_operations spufs_ibox_fops = {
+	.open	= spufs_pipe_open,
+	.read	= spufs_ibox_read,
+	.poll	= spufs_ibox_poll,
+	.fasync	= spufs_ibox_fasync,
+};
+
+static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 ibox_stat;
+
+	if (len < 4)
+		return -EINVAL;
+
+	spu_acquire(ctx);
+	ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
+	spu_release(ctx);
+
+	if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
+		return -EFAULT;
+
+	return 4;
+}
+
+static struct file_operations spufs_ibox_stat_fops = {
+	.open	= spufs_pipe_open,
+	.read	= spufs_ibox_stat_read,
+};
+
+/* low-level mailbox write */
+size_t spu_wbox_write(struct spu_context *ctx, u32 data)
+{
+	return ctx->ops->wbox_write(ctx, data);
+}
+
+static int spufs_wbox_fasync(int fd, struct file *file, int on)
+{
+	struct spu_context *ctx = file->private_data;
+	int ret;
+
+	ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
+
+	return ret;
+}
+
+/* interrupt-level wbox callback function. */
+void spufs_wbox_callback(struct spu *spu)
+{
+	struct spu_context *ctx = spu->ctx;
+
+	wake_up_all(&ctx->wbox_wq);
+	kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
+}
+
+static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 wbox_data;
+	int ret;
+
+	if (len < 4)
+		return -EINVAL;
+
+	if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
+		return -EFAULT;
+
+	spu_acquire(ctx);
+
+	ret = 0;
+	if (file->f_flags & O_NONBLOCK) {
+		if (!spu_wbox_write(ctx, wbox_data))
+			ret = -EAGAIN;
+	} else {
+		ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
+	}
+
+	spu_release(ctx);
+
+	return ret ? ret : sizeof wbox_data;
+}
+
+static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
+{
+	struct spu_context *ctx = file->private_data;
+	unsigned int mask;
+
+	poll_wait(file, &ctx->wbox_wq, wait);
+
+	spu_acquire(ctx);
+	mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM);
+	spu_release(ctx);
+
+	return mask;
+}
+
+static struct file_operations spufs_wbox_fops = {
+	.open	= spufs_pipe_open,
+	.write	= spufs_wbox_write,
+	.poll	= spufs_wbox_poll,
+	.fasync	= spufs_wbox_fasync,
+};
+
+static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 wbox_stat;
+
+	if (len < 4)
+		return -EINVAL;
+
+	spu_acquire(ctx);
+	wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
+	spu_release(ctx);
+
+	if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
+		return -EFAULT;
+
+	return 4;
+}
+
+static struct file_operations spufs_wbox_stat_fops = {
+	.open	= spufs_pipe_open,
+	.read	= spufs_wbox_stat_read,
+};
+
+static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 data;
+
+	if (len < 4)
+		return -EINVAL;
+
+	spu_acquire(ctx);
+	data = ctx->ops->signal1_read(ctx);
+	spu_release(ctx);
+
+	if (copy_to_user(buf, &data, 4))
+		return -EFAULT;
+
+	return 4;
+}
+
+static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx;
+	u32 data;
+
+	ctx = file->private_data;
+
+	if (len < 4)
+		return -EINVAL;
+
+	if (copy_from_user(&data, buf, 4))
+		return -EFAULT;
+
+	spu_acquire(ctx);
+	ctx->ops->signal1_write(ctx, data);
+	spu_release(ctx);
+
+	return 4;
+}
+
+static struct file_operations spufs_signal1_fops = {
+	.open = spufs_pipe_open,
+	.read = spufs_signal1_read,
+	.write = spufs_signal1_write,
+};
+
+static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx;
+	u32 data;
+
+	ctx = file->private_data;
+
+	if (len < 4)
+		return -EINVAL;
+
+	spu_acquire(ctx);
+	data = ctx->ops->signal2_read(ctx);
+	spu_release(ctx);
+
+	if (copy_to_user(buf, &data, 4))
+		return -EFAULT;
+
+	return 4;
+}
+
+static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
+			size_t len, loff_t *pos)
+{
+	struct spu_context *ctx;
+	u32 data;
+
+	ctx = file->private_data;
+
+	if (len < 4)
+		return -EINVAL;
+
+	if (copy_from_user(&data, buf, 4))
+		return -EFAULT;
+
+	spu_acquire(ctx);
+	ctx->ops->signal2_write(ctx, data);
+	spu_release(ctx);
+
+	return 4;
+}
+
+static struct file_operations spufs_signal2_fops = {
+	.open = spufs_pipe_open,
+	.read = spufs_signal2_read,
+	.write = spufs_signal2_write,
+};
+
+static void spufs_signal1_type_set(void *data, u64 val)
+{
+	struct spu_context *ctx = data;
+
+	spu_acquire(ctx);
+	ctx->ops->signal1_type_set(ctx, val);
+	spu_release(ctx);
+}
+
+static u64 spufs_signal1_type_get(void *data)
+{
+	struct spu_context *ctx = data;
+	u64 ret;
+
+	spu_acquire(ctx);
+	ret = ctx->ops->signal1_type_get(ctx);
+	spu_release(ctx);
+
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
+					spufs_signal1_type_set, "%llu");
+
+static void spufs_signal2_type_set(void *data, u64 val)
+{
+	struct spu_context *ctx = data;
+
+	spu_acquire(ctx);
+	ctx->ops->signal2_type_set(ctx, val);
+	spu_release(ctx);
+}
+
+static u64 spufs_signal2_type_get(void *data)
+{
+	struct spu_context *ctx = data;
+	u64 ret;
+
+	spu_acquire(ctx);
+	ret = ctx->ops->signal2_type_get(ctx);
+	spu_release(ctx);
+
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
+					spufs_signal2_type_set, "%llu");
+
+static void spufs_npc_set(void *data, u64 val)
+{
+	struct spu_context *ctx = data;
+	spu_acquire(ctx);
+	ctx->ops->npc_write(ctx, val);
+	spu_release(ctx);
+}
+
+static u64 spufs_npc_get(void *data)
+{
+	struct spu_context *ctx = data;
+	u64 ret;
+	spu_acquire(ctx);
+	ret = ctx->ops->npc_read(ctx);
+	spu_release(ctx);
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
+
+static void spufs_decr_set(void *data, u64 val)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	spu_acquire_saved(ctx);
+	lscsa->decr.slot[0] = (u32) val;
+	spu_release(ctx);
+}
+
+static u64 spufs_decr_get(void *data)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	u64 ret;
+	spu_acquire_saved(ctx);
+	ret = lscsa->decr.slot[0];
+	spu_release(ctx);
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
+			"%llx\n")
+
+static void spufs_decr_status_set(void *data, u64 val)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	spu_acquire_saved(ctx);
+	lscsa->decr_status.slot[0] = (u32) val;
+	spu_release(ctx);
+}
+
+static u64 spufs_decr_status_get(void *data)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	u64 ret;
+	spu_acquire_saved(ctx);
+	ret = lscsa->decr_status.slot[0];
+	spu_release(ctx);
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
+			spufs_decr_status_set, "%llx\n")
+
+static void spufs_spu_tag_mask_set(void *data, u64 val)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	spu_acquire_saved(ctx);
+	lscsa->tag_mask.slot[0] = (u32) val;
+	spu_release(ctx);
+}
+
+static u64 spufs_spu_tag_mask_get(void *data)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	u64 ret;
+	spu_acquire_saved(ctx);
+	ret = lscsa->tag_mask.slot[0];
+	spu_release(ctx);
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
+			spufs_spu_tag_mask_set, "%llx\n")
+
+static void spufs_event_mask_set(void *data, u64 val)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	spu_acquire_saved(ctx);
+	lscsa->event_mask.slot[0] = (u32) val;
+	spu_release(ctx);
+}
+
+static u64 spufs_event_mask_get(void *data)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	u64 ret;
+	spu_acquire_saved(ctx);
+	ret = lscsa->event_mask.slot[0];
+	spu_release(ctx);
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
+			spufs_event_mask_set, "%llx\n")
+
+static void spufs_srr0_set(void *data, u64 val)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	spu_acquire_saved(ctx);
+	lscsa->srr0.slot[0] = (u32) val;
+	spu_release(ctx);
+}
+
+static u64 spufs_srr0_get(void *data)
+{
+	struct spu_context *ctx = data;
+	struct spu_lscsa *lscsa = ctx->csa.lscsa;
+	u64 ret;
+	spu_acquire_saved(ctx);
+	ret = lscsa->srr0.slot[0];
+	spu_release(ctx);
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
+			"%llx\n")
+
+struct tree_descr spufs_dir_contents[] = {
+	{ "mem",  &spufs_mem_fops,  0666, },
+	{ "regs", &spufs_regs_fops,  0666, },
+	{ "mbox", &spufs_mbox_fops, 0444, },
+	{ "ibox", &spufs_ibox_fops, 0444, },
+	{ "wbox", &spufs_wbox_fops, 0222, },
+	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
+	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
+	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
+	{ "signal1", &spufs_signal1_fops, 0666, },
+	{ "signal2", &spufs_signal2_fops, 0666, },
+	{ "signal1_type", &spufs_signal1_type, 0666, },
+	{ "signal2_type", &spufs_signal2_type, 0666, },
+	{ "npc", &spufs_npc_ops, 0666, },
+	{ "fpcr", &spufs_fpcr_fops, 0666, },
+	{ "decr", &spufs_decr_ops, 0666, },
+	{ "decr_status", &spufs_decr_status_ops, 0666, },
+	{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
+	{ "event_mask", &spufs_event_mask_ops, 0666, },
+	{ "srr0", &spufs_srr0_ops, 0666, },
+	{},
+};
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
new file mode 100644
index 0000000..5445719
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -0,0 +1,255 @@
+/* hw_ops.c - query/set operations on active SPU context.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+#include "spufs.h"
+
+static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
+{
+	struct spu *spu = ctx->spu;
+	struct spu_problem __iomem *prob = spu->problem;
+	u32 mbox_stat;
+	int ret = 0;
+
+	spin_lock_irq(&spu->register_lock);
+	mbox_stat = in_be32(&prob->mb_stat_R);
+	if (mbox_stat & 0x0000ff) {
+		*data = in_be32(&prob->pu_mb_R);
+		ret = 4;
+	}
+	spin_unlock_irq(&spu->register_lock);
+	return ret;
+}
+
+static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
+{
+	return in_be32(&ctx->spu->problem->mb_stat_R);
+}
+
+static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx,
+					  unsigned int events)
+{
+	struct spu *spu = ctx->spu;
+	int ret = 0;
+	u32 stat;
+
+	spin_lock_irq(&spu->register_lock);
+	stat = in_be32(&spu->problem->mb_stat_R);
+
+	/* if the requested event is there, return the poll
+	   mask, otherwise enable the interrupt to get notified,
+	   but first mark any pending interrupts as done so
+	   we don't get woken up unnecessarily */
+
+	if (events & (POLLIN | POLLRDNORM)) {
+		if (stat & 0xff0000)
+			ret |= POLLIN | POLLRDNORM;
+		else {
+			spu_int_stat_clear(spu, 2, 0x1);
+			spu_int_mask_or(spu, 2, 0x1);
+		}
+	}
+	if (events & (POLLOUT | POLLWRNORM)) {
+		if (stat & 0x00ff00)
+			ret = POLLOUT | POLLWRNORM;
+		else {
+			spu_int_stat_clear(spu, 2, 0x10);
+			spu_int_mask_or(spu, 2, 0x10);
+		}
+	}
+	spin_unlock_irq(&spu->register_lock);
+	return ret;
+}
+
+static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
+{
+	struct spu *spu = ctx->spu;
+	struct spu_problem __iomem *prob = spu->problem;
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	int ret;
+
+	spin_lock_irq(&spu->register_lock);
+	if (in_be32(&prob->mb_stat_R) & 0xff0000) {
+		/* read the first available word */
+		*data = in_be64(&priv2->puint_mb_R);
+		ret = 4;
+	} else {
+		/* make sure we get woken up by the interrupt */
+		spu_int_mask_or(spu, 2, 0x1);
+		ret = 0;
+	}
+	spin_unlock_irq(&spu->register_lock);
+	return ret;
+}
+
+static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
+{
+	struct spu *spu = ctx->spu;
+	struct spu_problem __iomem *prob = spu->problem;
+	int ret;
+
+	spin_lock_irq(&spu->register_lock);
+	if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
+		/* we have space to write wbox_data to */
+		out_be32(&prob->spu_mb_W, data);
+		ret = 4;
+	} else {
+		/* make sure we get woken up by the interrupt when space
+		   becomes available */
+		spu_int_mask_or(spu, 2, 0x10);
+		ret = 0;
+	}
+	spin_unlock_irq(&spu->register_lock);
+	return ret;
+}
+
+static u32 spu_hw_signal1_read(struct spu_context *ctx)
+{
+	return in_be32(&ctx->spu->problem->signal_notify1);
+}
+
+static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
+{
+	out_be32(&ctx->spu->problem->signal_notify1, data);
+}
+
+static u32 spu_hw_signal2_read(struct spu_context *ctx)
+{
+	return in_be32(&ctx->spu->problem->signal_notify1);
+}
+
+static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
+{
+	out_be32(&ctx->spu->problem->signal_notify2, data);
+}
+
+static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
+{
+	struct spu *spu = ctx->spu;
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 tmp;
+
+	spin_lock_irq(&spu->register_lock);
+	tmp = in_be64(&priv2->spu_cfg_RW);
+	if (val)
+		tmp |= 1;
+	else
+		tmp &= ~1;
+	out_be64(&priv2->spu_cfg_RW, tmp);
+	spin_unlock_irq(&spu->register_lock);
+}
+
+static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
+{
+	return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
+}
+
+static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
+{
+	struct spu *spu = ctx->spu;
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 tmp;
+
+	spin_lock_irq(&spu->register_lock);
+	tmp = in_be64(&priv2->spu_cfg_RW);
+	if (val)
+		tmp |= 2;
+	else
+		tmp &= ~2;
+	out_be64(&priv2->spu_cfg_RW, tmp);
+	spin_unlock_irq(&spu->register_lock);
+}
+
+static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
+{
+	return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
+}
+
+static u32 spu_hw_npc_read(struct spu_context *ctx)
+{
+	return in_be32(&ctx->spu->problem->spu_npc_RW);
+}
+
+static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
+{
+	out_be32(&ctx->spu->problem->spu_npc_RW, val);
+}
+
+static u32 spu_hw_status_read(struct spu_context *ctx)
+{
+	return in_be32(&ctx->spu->problem->spu_status_R);
+}
+
+static char *spu_hw_get_ls(struct spu_context *ctx)
+{
+	return ctx->spu->local_store;
+}
+
+static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
+{
+	eieio();
+	out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
+}
+
+static void spu_hw_runcntl_stop(struct spu_context *ctx)
+{
+	spin_lock_irq(&ctx->spu->register_lock);
+	out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+	while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
+		cpu_relax();
+	spin_unlock_irq(&ctx->spu->register_lock);
+}
+
+struct spu_context_ops spu_hw_ops = {
+	.mbox_read = spu_hw_mbox_read,
+	.mbox_stat_read = spu_hw_mbox_stat_read,
+	.mbox_stat_poll = spu_hw_mbox_stat_poll,
+	.ibox_read = spu_hw_ibox_read,
+	.wbox_write = spu_hw_wbox_write,
+	.signal1_read = spu_hw_signal1_read,
+	.signal1_write = spu_hw_signal1_write,
+	.signal2_read = spu_hw_signal2_read,
+	.signal2_write = spu_hw_signal2_write,
+	.signal1_type_set = spu_hw_signal1_type_set,
+	.signal1_type_get = spu_hw_signal1_type_get,
+	.signal2_type_set = spu_hw_signal2_type_set,
+	.signal2_type_get = spu_hw_signal2_type_get,
+	.npc_read = spu_hw_npc_read,
+	.npc_write = spu_hw_npc_write,
+	.status_read = spu_hw_status_read,
+	.get_ls = spu_hw_get_ls,
+	.runcntl_write = spu_hw_runcntl_write,
+	.runcntl_stop = spu_hw_runcntl_stop,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
new file mode 100644
index 0000000..1f3507c
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -0,0 +1,486 @@
+/*
+ * SPU file system
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/backing-dev.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/parser.h>
+
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+static kmem_cache_t *spufs_inode_cache;
+
+static struct inode *
+spufs_alloc_inode(struct super_block *sb)
+{
+	struct spufs_inode_info *ei;
+
+	ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void
+spufs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
+}
+
+static void
+spufs_init_once(void *p, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct spufs_inode_info *ei = p;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+
+static struct inode *
+spufs_new_inode(struct super_block *sb, int mode)
+{
+	struct inode *inode;
+
+	inode = new_inode(sb);
+	if (!inode)
+		goto out;
+
+	inode->i_mode = mode;
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_blksize = PAGE_CACHE_SIZE;
+	inode->i_blocks = 0;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+out:
+	return inode;
+}
+
+static int
+spufs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	struct inode *inode = dentry->d_inode;
+
+	if ((attr->ia_valid & ATTR_SIZE) &&
+	    (attr->ia_size != inode->i_size))
+		return -EINVAL;
+	return inode_setattr(inode, attr);
+}
+
+
+static int
+spufs_new_file(struct super_block *sb, struct dentry *dentry,
+		struct file_operations *fops, int mode,
+		struct spu_context *ctx)
+{
+	static struct inode_operations spufs_file_iops = {
+		.setattr = spufs_setattr,
+	};
+	struct inode *inode;
+	int ret;
+
+	ret = -ENOSPC;
+	inode = spufs_new_inode(sb, S_IFREG | mode);
+	if (!inode)
+		goto out;
+
+	ret = 0;
+	inode->i_op = &spufs_file_iops;
+	inode->i_fop = fops;
+	inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
+	d_add(dentry, inode);
+out:
+	return ret;
+}
+
+static void
+spufs_delete_inode(struct inode *inode)
+{
+	if (SPUFS_I(inode)->i_ctx)
+		put_spu_context(SPUFS_I(inode)->i_ctx);
+	clear_inode(inode);
+}
+
+static void spufs_prune_dir(struct dentry *dir)
+{
+	struct dentry *dentry, *tmp;
+	down(&dir->d_inode->i_sem);
+	list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
+		spin_lock(&dcache_lock);
+		spin_lock(&dentry->d_lock);
+		if (!(d_unhashed(dentry)) && dentry->d_inode) {
+			dget_locked(dentry);
+			__d_drop(dentry);
+			spin_unlock(&dentry->d_lock);
+			simple_unlink(dir->d_inode, dentry);
+			spin_unlock(&dcache_lock);
+			dput(dentry);
+		} else {
+			spin_unlock(&dentry->d_lock);
+			spin_unlock(&dcache_lock);
+		}
+	}
+	shrink_dcache_parent(dir);
+	up(&dir->d_inode->i_sem);
+}
+
+static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+{
+	struct spu_context *ctx;
+
+	/* remove all entries */
+	down(&root->i_sem);
+	spufs_prune_dir(dir_dentry);
+	up(&root->i_sem);
+
+	/* We have to give up the mm_struct */
+	ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx;
+	spu_forget(ctx);
+
+	/* XXX Do we need to hold i_sem here ? */
+	return simple_rmdir(root, dir_dentry);
+}
+
+static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
+			  int mode, struct spu_context *ctx)
+{
+	struct dentry *dentry;
+	int ret;
+
+	while (files->name && files->name[0]) {
+		ret = -ENOMEM;
+		dentry = d_alloc_name(dir, files->name);
+		if (!dentry)
+			goto out;
+		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
+					files->mode & mode, ctx);
+		if (ret)
+			goto out;
+		files++;
+	}
+	return 0;
+out:
+	spufs_prune_dir(dir);
+	return ret;
+}
+
+static int spufs_dir_close(struct inode *inode, struct file *file)
+{
+	struct inode *dir;
+	struct dentry *dentry;
+	int ret;
+
+	dentry = file->f_dentry;
+	dir = dentry->d_parent->d_inode;
+
+	ret = spufs_rmdir(dir, dentry);
+	WARN_ON(ret);
+
+	return dcache_dir_close(inode, file);
+}
+
+struct inode_operations spufs_dir_inode_operations = {
+	.lookup = simple_lookup,
+};
+
+struct file_operations spufs_context_fops = {
+	.open		= dcache_dir_open,
+	.release	= spufs_dir_close,
+	.llseek		= dcache_dir_lseek,
+	.read		= generic_read_dir,
+	.readdir	= dcache_readdir,
+	.fsync		= simple_sync_file,
+};
+
+static int
+spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	int ret;
+	struct inode *inode;
+	struct spu_context *ctx;
+
+	ret = -ENOSPC;
+	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
+	if (!inode)
+		goto out;
+
+	if (dir->i_mode & S_ISGID) {
+		inode->i_gid = dir->i_gid;
+		inode->i_mode &= S_ISGID;
+	}
+	ctx = alloc_spu_context(inode->i_mapping);
+	SPUFS_I(inode)->i_ctx = ctx;
+	if (!ctx)
+		goto out_iput;
+
+	inode->i_op = &spufs_dir_inode_operations;
+	inode->i_fop = &simple_dir_operations;
+	ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
+	if (ret)
+		goto out_free_ctx;
+
+	d_instantiate(dentry, inode);
+	dget(dentry);
+	dir->i_nlink++;
+	dentry->d_inode->i_nlink++;
+	goto out;
+
+out_free_ctx:
+	put_spu_context(ctx);
+out_iput:
+	iput(inode);
+out:
+	return ret;
+}
+
+static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt)
+{
+	int ret;
+	struct file *filp;
+
+	ret = get_unused_fd();
+	if (ret < 0) {
+		dput(dentry);
+		mntput(mnt);
+		goto out;
+	}
+
+	filp = dentry_open(dentry, mnt, O_RDONLY);
+	if (IS_ERR(filp)) {
+		put_unused_fd(ret);
+		ret = PTR_ERR(filp);
+		goto out;
+	}
+
+	filp->f_op = &spufs_context_fops;
+	fd_install(ret, filp);
+out:
+	return ret;
+}
+
+static struct file_system_type spufs_type;
+
+long spufs_create_thread(struct nameidata *nd,
+			 unsigned int flags, mode_t mode)
+{
+	struct dentry *dentry;
+	int ret;
+
+	/* need to be at the root of spufs */
+	ret = -EINVAL;
+	if (nd->dentry->d_sb->s_type != &spufs_type ||
+	    nd->dentry != nd->dentry->d_sb->s_root)
+		goto out;
+
+	dentry = lookup_create(nd, 1);
+	ret = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
+		goto out_dir;
+
+	ret = -EEXIST;
+	if (dentry->d_inode)
+		goto out_dput;
+
+	mode &= ~current->fs->umask;
+	ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO);
+	if (ret)
+		goto out_dput;
+
+	/*
+	 * get references for dget and mntget, will be released
+	 * in error path of *_open().
+	 */
+	ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
+	if (ret < 0)
+		spufs_rmdir(nd->dentry->d_inode, dentry);
+
+out_dput:
+	dput(dentry);
+out_dir:
+	up(&nd->dentry->d_inode->i_sem);
+out:
+	return ret;
+}
+
+/* File system initialization */
+enum {
+	Opt_uid, Opt_gid, Opt_err,
+};
+
+static match_table_t spufs_tokens = {
+	{ Opt_uid, "uid=%d" },
+	{ Opt_gid, "gid=%d" },
+	{ Opt_err, NULL  },
+};
+
+static int
+spufs_parse_options(char *options, struct inode *root)
+{
+	char *p;
+	substring_t args[MAX_OPT_ARGS];
+
+	while ((p = strsep(&options, ",")) != NULL) {
+		int token, option;
+
+		if (!*p)
+			continue;
+
+		token = match_token(p, spufs_tokens, args);
+		switch (token) {
+		case Opt_uid:
+			if (match_int(&args[0], &option))
+				return 0;
+			root->i_uid = option;
+			break;
+		case Opt_gid:
+			if (match_int(&args[0], &option))
+				return 0;
+			root->i_gid = option;
+			break;
+		default:
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int
+spufs_create_root(struct super_block *sb, void *data)
+{
+	struct inode *inode;
+	int ret;
+
+	ret = -ENOMEM;
+	inode = spufs_new_inode(sb, S_IFDIR | 0775);
+	if (!inode)
+		goto out;
+
+	inode->i_op = &spufs_dir_inode_operations;
+	inode->i_fop = &simple_dir_operations;
+	SPUFS_I(inode)->i_ctx = NULL;
+
+	ret = -EINVAL;
+	if (!spufs_parse_options(data, inode))
+		goto out_iput;
+
+	ret = -ENOMEM;
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root)
+		goto out_iput;
+
+	return 0;
+out_iput:
+	iput(inode);
+out:
+	return ret;
+}
+
+static int
+spufs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	static struct super_operations s_ops = {
+		.alloc_inode = spufs_alloc_inode,
+		.destroy_inode = spufs_destroy_inode,
+		.statfs = simple_statfs,
+		.delete_inode = spufs_delete_inode,
+		.drop_inode = generic_delete_inode,
+	};
+
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = SPUFS_MAGIC;
+	sb->s_op = &s_ops;
+
+	return spufs_create_root(sb, data);
+}
+
+static struct super_block *
+spufs_get_sb(struct file_system_type *fstype, int flags,
+		const char *name, void *data)
+{
+	return get_sb_single(fstype, flags, data, spufs_fill_super);
+}
+
+static struct file_system_type spufs_type = {
+	.owner = THIS_MODULE,
+	.name = "spufs",
+	.get_sb = spufs_get_sb,
+	.kill_sb = kill_litter_super,
+};
+
+static int spufs_init(void)
+{
+	int ret;
+	ret = -ENOMEM;
+	spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
+			sizeof(struct spufs_inode_info), 0,
+			SLAB_HWCACHE_ALIGN, spufs_init_once, NULL);
+
+	if (!spufs_inode_cache)
+		goto out;
+	if (spu_sched_init() != 0) {
+		kmem_cache_destroy(spufs_inode_cache);
+		goto out;
+	}
+	ret = register_filesystem(&spufs_type);
+	if (ret)
+		goto out_cache;
+	ret = register_spu_syscalls(&spufs_calls);
+	if (ret)
+		goto out_fs;
+	return 0;
+out_fs:
+	unregister_filesystem(&spufs_type);
+out_cache:
+	kmem_cache_destroy(spufs_inode_cache);
+out:
+	return ret;
+}
+module_init(spufs_init);
+
+static void spufs_exit(void)
+{
+	spu_sched_exit();
+	unregister_spu_syscalls(&spufs_calls);
+	unregister_filesystem(&spufs_type);
+	kmem_cache_destroy(spufs_inode_cache);
+}
+module_exit(spufs_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
+
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
new file mode 100644
index 0000000..18ea886
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -0,0 +1,131 @@
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+
+#include <asm/spu.h>
+
+#include "spufs.h"
+
+/* interrupt-level stop callback function. */
+void spufs_stop_callback(struct spu *spu)
+{
+	struct spu_context *ctx = spu->ctx;
+
+	wake_up_all(&ctx->stop_wq);
+}
+
+static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+{
+	struct spu *spu;
+	u64 pte_fault;
+
+	*stat = ctx->ops->status_read(ctx);
+	if (ctx->state != SPU_STATE_RUNNABLE)
+		return 1;
+	spu = ctx->spu;
+	pte_fault = spu->dsisr &
+	    (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
+	return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
+}
+
+static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
+			       u32 * status)
+{
+	int ret;
+
+	if ((ret = spu_acquire_runnable(ctx)) != 0)
+		return ret;
+	ctx->ops->npc_write(ctx, *npc);
+	ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+	return 0;
+}
+
+static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
+			       u32 * status)
+{
+	int ret = 0;
+
+	*status = ctx->ops->status_read(ctx);
+	*npc = ctx->ops->npc_read(ctx);
+	spu_release(ctx);
+
+	if (signal_pending(current))
+		ret = -ERESTARTSYS;
+	if (unlikely(current->ptrace & PT_PTRACED)) {
+		if ((*status & SPU_STATUS_STOPPED_BY_STOP)
+		    && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
+			force_sig(SIGTRAP, current);
+			ret = -ERESTARTSYS;
+		}
+	}
+	return ret;
+}
+
+static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
+				         u32 *status)
+{
+	int ret;
+
+	if ((ret = spu_run_fini(ctx, npc, status)) != 0)
+		return ret;
+	if (*status & (SPU_STATUS_STOPPED_BY_STOP |
+		       SPU_STATUS_STOPPED_BY_HALT)) {
+		return *status;
+	}
+	if ((ret = spu_run_init(ctx, npc, status)) != 0)
+		return ret;
+	return 0;
+}
+
+static inline int spu_process_events(struct spu_context *ctx)
+{
+	struct spu *spu = ctx->spu;
+	u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
+	int ret = 0;
+
+	if (spu->dsisr & pte_fault)
+		ret = spu_irq_class_1_bottom(spu);
+	if (spu->class_0_pending)
+		ret = spu_irq_class_0_bottom(spu);
+	if (!ret && signal_pending(current))
+		ret = -ERESTARTSYS;
+	return ret;
+}
+
+long spufs_run_spu(struct file *file, struct spu_context *ctx,
+		   u32 * npc, u32 * status)
+{
+	int ret;
+
+	if (down_interruptible(&ctx->run_sema))
+		return -ERESTARTSYS;
+
+	ret = spu_run_init(ctx, npc, status);
+	if (ret)
+		goto out;
+
+	do {
+		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
+		if (unlikely(ret))
+			break;
+		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
+			ret = spu_reacquire_runnable(ctx, npc, status);
+			if (ret)
+				goto out;
+			continue;
+		}
+		ret = spu_process_events(ctx);
+
+	} while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
+				      SPU_STATUS_STOPPED_BY_HALT)));
+
+	ctx->ops->runcntl_stop(ctx);
+	ret = spu_run_fini(ctx, npc, status);
+	if (!ret)
+		ret = *status;
+	spu_yield(ctx);
+
+out:
+	up(&ctx->run_sema);
+	return ret;
+}
+
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
new file mode 100644
index 0000000..963182f
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -0,0 +1,461 @@
+/* sched.c - SPU scheduler.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * SPU scheduler, based on Linux thread priority.  For now use
+ * a simple "cooperative" yield model with no preemption.  SPU
+ * scheduling will eventually be preemptive: When a thread with
+ * a higher static priority gets ready to run, then an active SPU
+ * context will be preempted and returned to the waitq.
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/completion.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include "spufs.h"
+
+#define SPU_MIN_TIMESLICE 	(100 * HZ / 1000)
+
+#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
+struct spu_prio_array {
+	atomic_t nr_blocked;
+	unsigned long bitmap[SPU_BITMAP_SIZE];
+	wait_queue_head_t waitq[MAX_PRIO];
+};
+
+/* spu_runqueue - This is the main runqueue data structure for SPUs. */
+struct spu_runqueue {
+	struct semaphore sem;
+	unsigned long nr_active;
+	unsigned long nr_idle;
+	unsigned long nr_switches;
+	struct list_head active_list;
+	struct list_head idle_list;
+	struct spu_prio_array prio;
+};
+
+static struct spu_runqueue *spu_runqueues = NULL;
+
+static inline struct spu_runqueue *spu_rq(void)
+{
+	/* Future: make this a per-NODE array,
+	 * and use cpu_to_node(smp_processor_id())
+	 */
+	return spu_runqueues;
+}
+
+static inline struct spu *del_idle(struct spu_runqueue *rq)
+{
+	struct spu *spu;
+
+	BUG_ON(rq->nr_idle <= 0);
+	BUG_ON(list_empty(&rq->idle_list));
+	/* Future: Move SPU out of low-power SRI state. */
+	spu = list_entry(rq->idle_list.next, struct spu, sched_list);
+	list_del_init(&spu->sched_list);
+	rq->nr_idle--;
+	return spu;
+}
+
+static inline void del_active(struct spu_runqueue *rq, struct spu *spu)
+{
+	BUG_ON(rq->nr_active <= 0);
+	BUG_ON(list_empty(&rq->active_list));
+	list_del_init(&spu->sched_list);
+	rq->nr_active--;
+}
+
+static inline void add_idle(struct spu_runqueue *rq, struct spu *spu)
+{
+	/* Future: Put SPU into low-power SRI state. */
+	list_add_tail(&spu->sched_list, &rq->idle_list);
+	rq->nr_idle++;
+}
+
+static inline void add_active(struct spu_runqueue *rq, struct spu *spu)
+{
+	rq->nr_active++;
+	rq->nr_switches++;
+	list_add_tail(&spu->sched_list, &rq->active_list);
+}
+
+static void prio_wakeup(struct spu_runqueue *rq)
+{
+	if (atomic_read(&rq->prio.nr_blocked) && rq->nr_idle) {
+		int best = sched_find_first_bit(rq->prio.bitmap);
+		if (best < MAX_PRIO) {
+			wait_queue_head_t *wq = &rq->prio.waitq[best];
+			wake_up_interruptible_nr(wq, 1);
+		}
+	}
+}
+
+static void prio_wait(struct spu_runqueue *rq, struct spu_context *ctx,
+		      u64 flags)
+{
+	int prio = current->prio;
+	wait_queue_head_t *wq = &rq->prio.waitq[prio];
+	DEFINE_WAIT(wait);
+
+	__set_bit(prio, rq->prio.bitmap);
+	atomic_inc(&rq->prio.nr_blocked);
+	prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE);
+	if (!signal_pending(current)) {
+		up(&rq->sem);
+		up_write(&ctx->state_sema);
+		pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
+			 current->pid, current->prio);
+		schedule();
+		down_write(&ctx->state_sema);
+		down(&rq->sem);
+	}
+	finish_wait(wq, &wait);
+	atomic_dec(&rq->prio.nr_blocked);
+	if (!waitqueue_active(wq))
+		__clear_bit(prio, rq->prio.bitmap);
+}
+
+static inline int is_best_prio(struct spu_runqueue *rq)
+{
+	int best_prio;
+
+	best_prio = sched_find_first_bit(rq->prio.bitmap);
+	return (current->prio < best_prio) ? 1 : 0;
+}
+
+static inline void mm_needs_global_tlbie(struct mm_struct *mm)
+{
+	/* Global TLBIE broadcast required with SPEs. */
+#if (NR_CPUS > 1)
+	__cpus_setall(&mm->cpu_vm_mask, NR_CPUS);
+#else
+	__cpus_setall(&mm->cpu_vm_mask, NR_CPUS+1); /* is this ok? */
+#endif
+}
+
+static inline void bind_context(struct spu *spu, struct spu_context *ctx)
+{
+	pr_debug("%s: pid=%d SPU=%d\n", __FUNCTION__, current->pid,
+		 spu->number);
+	spu->ctx = ctx;
+	spu->flags = 0;
+	ctx->flags = 0;
+	ctx->spu = spu;
+	ctx->ops = &spu_hw_ops;
+	spu->pid = current->pid;
+	spu->prio = current->prio;
+	spu->mm = ctx->owner;
+	mm_needs_global_tlbie(spu->mm);
+	spu->ibox_callback = spufs_ibox_callback;
+	spu->wbox_callback = spufs_wbox_callback;
+	spu->stop_callback = spufs_stop_callback;
+	mb();
+	spu_unmap_mappings(ctx);
+	spu_restore(&ctx->csa, spu);
+	spu->timestamp = jiffies;
+}
+
+static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
+{
+	pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__,
+		 spu->pid, spu->number);
+	spu_unmap_mappings(ctx);
+	spu_save(&ctx->csa, spu);
+	spu->timestamp = jiffies;
+	ctx->state = SPU_STATE_SAVED;
+	spu->ibox_callback = NULL;
+	spu->wbox_callback = NULL;
+	spu->stop_callback = NULL;
+	spu->mm = NULL;
+	spu->pid = 0;
+	spu->prio = MAX_PRIO;
+	ctx->ops = &spu_backing_ops;
+	ctx->spu = NULL;
+	ctx->flags = 0;
+	spu->flags = 0;
+	spu->ctx = NULL;
+}
+
+static void spu_reaper(void *data)
+{
+	struct spu_context *ctx = data;
+	struct spu *spu;
+
+	down_write(&ctx->state_sema);
+	spu = ctx->spu;
+	if (spu && test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
+		if (atomic_read(&spu->rq->prio.nr_blocked)) {
+			pr_debug("%s: spu=%d\n", __func__, spu->number);
+			ctx->ops->runcntl_stop(ctx);
+			spu_deactivate(ctx);
+			wake_up_all(&ctx->stop_wq);
+		} else {
+			clear_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
+		}
+	}
+	up_write(&ctx->state_sema);
+	put_spu_context(ctx);
+}
+
+static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu)
+{
+	struct spu_context *ctx = get_spu_context(spu->ctx);
+	unsigned long now = jiffies;
+	unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE;
+
+	set_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
+	INIT_WORK(&ctx->reap_work, spu_reaper, ctx);
+	if (time_after(now, expire))
+		schedule_work(&ctx->reap_work);
+	else
+		schedule_delayed_work(&ctx->reap_work, expire - now);
+}
+
+static void check_preempt_active(struct spu_runqueue *rq)
+{
+	struct list_head *p;
+	struct spu *worst = NULL;
+
+	list_for_each(p, &rq->active_list) {
+		struct spu *spu = list_entry(p, struct spu, sched_list);
+		struct spu_context *ctx = spu->ctx;
+		if (!test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
+			if (!worst || (spu->prio > worst->prio)) {
+				worst = spu;
+			}
+		}
+	}
+	if (worst && (current->prio < worst->prio))
+		schedule_spu_reaper(rq, worst);
+}
+
+static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags)
+{
+	struct spu_runqueue *rq;
+	struct spu *spu = NULL;
+
+	rq = spu_rq();
+	down(&rq->sem);
+	for (;;) {
+		if (rq->nr_idle > 0) {
+			if (is_best_prio(rq)) {
+				/* Fall through. */
+				spu = del_idle(rq);
+				break;
+			} else {
+				prio_wakeup(rq);
+				up(&rq->sem);
+				yield();
+				if (signal_pending(current)) {
+					return NULL;
+				}
+				rq = spu_rq();
+				down(&rq->sem);
+				continue;
+			}
+		} else {
+			check_preempt_active(rq);
+			prio_wait(rq, ctx, flags);
+			if (signal_pending(current)) {
+				prio_wakeup(rq);
+				spu = NULL;
+				break;
+			}
+			continue;
+		}
+	}
+	up(&rq->sem);
+	return spu;
+}
+
+static void put_idle_spu(struct spu *spu)
+{
+	struct spu_runqueue *rq = spu->rq;
+
+	down(&rq->sem);
+	add_idle(rq, spu);
+	prio_wakeup(rq);
+	up(&rq->sem);
+}
+
+static int get_active_spu(struct spu *spu)
+{
+	struct spu_runqueue *rq = spu->rq;
+	struct list_head *p;
+	struct spu *tmp;
+	int rc = 0;
+
+	down(&rq->sem);
+	list_for_each(p, &rq->active_list) {
+		tmp = list_entry(p, struct spu, sched_list);
+		if (tmp == spu) {
+			del_active(rq, spu);
+			rc = 1;
+			break;
+		}
+	}
+	up(&rq->sem);
+	return rc;
+}
+
+static void put_active_spu(struct spu *spu)
+{
+	struct spu_runqueue *rq = spu->rq;
+
+	down(&rq->sem);
+	add_active(rq, spu);
+	up(&rq->sem);
+}
+
+/* Lock order:
+ *	spu_activate() & spu_deactivate() require the
+ *	caller to have down_write(&ctx->state_sema).
+ *
+ *	The rq->sem is breifly held (inside or outside a
+ *	given ctx lock) for list management, but is never
+ *	held during save/restore.
+ */
+
+int spu_activate(struct spu_context *ctx, u64 flags)
+{
+	struct spu *spu;
+
+	if (ctx->spu)
+		return 0;
+	spu = get_idle_spu(ctx, flags);
+	if (!spu)
+		return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
+	bind_context(spu, ctx);
+	/*
+	 * We're likely to wait for interrupts on the same
+	 * CPU that we are now on, so send them here.
+	 */
+	spu_irq_setaffinity(spu, raw_smp_processor_id());
+	put_active_spu(spu);
+	return 0;
+}
+
+void spu_deactivate(struct spu_context *ctx)
+{
+	struct spu *spu;
+	int needs_idle;
+
+	spu = ctx->spu;
+	if (!spu)
+		return;
+	needs_idle = get_active_spu(spu);
+	unbind_context(spu, ctx);
+	if (needs_idle)
+		put_idle_spu(spu);
+}
+
+void spu_yield(struct spu_context *ctx)
+{
+	struct spu *spu;
+	int need_yield = 0;
+
+	down_write(&ctx->state_sema);
+	spu = ctx->spu;
+	if (spu && (sched_find_first_bit(spu->rq->prio.bitmap) < MAX_PRIO)) {
+		pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number);
+		spu_deactivate(ctx);
+		ctx->state = SPU_STATE_SAVED;
+		need_yield = 1;
+	} else if (spu) {
+		spu->prio = MAX_PRIO;
+	}
+	up_write(&ctx->state_sema);
+	if (unlikely(need_yield))
+		yield();
+}
+
+int __init spu_sched_init(void)
+{
+	struct spu_runqueue *rq;
+	struct spu *spu;
+	int i;
+
+	rq = spu_runqueues = kmalloc(sizeof(struct spu_runqueue), GFP_KERNEL);
+	if (!rq) {
+		printk(KERN_WARNING "%s: Unable to allocate runqueues.\n",
+		       __FUNCTION__);
+		return 1;
+	}
+	memset(rq, 0, sizeof(struct spu_runqueue));
+	init_MUTEX(&rq->sem);
+	INIT_LIST_HEAD(&rq->active_list);
+	INIT_LIST_HEAD(&rq->idle_list);
+	rq->nr_active = 0;
+	rq->nr_idle = 0;
+	rq->nr_switches = 0;
+	atomic_set(&rq->prio.nr_blocked, 0);
+	for (i = 0; i < MAX_PRIO; i++) {
+		init_waitqueue_head(&rq->prio.waitq[i]);
+		__clear_bit(i, rq->prio.bitmap);
+	}
+	__set_bit(MAX_PRIO, rq->prio.bitmap);
+	for (;;) {
+		spu = spu_alloc();
+		if (!spu)
+			break;
+		pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number);
+		add_idle(rq, spu);
+		spu->rq = rq;
+		spu->timestamp = jiffies;
+	}
+	if (!rq->nr_idle) {
+		printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__);
+		kfree(rq);
+		return 1;
+	}
+	return 0;
+}
+
+void __exit spu_sched_exit(void)
+{
+	struct spu_runqueue *rq = spu_rq();
+	struct spu *spu;
+
+	if (!rq) {
+		printk(KERN_WARNING "%s: no runqueues!\n", __FUNCTION__);
+		return;
+	}
+	while (rq->nr_idle > 0) {
+		spu = del_idle(rq);
+		if (!spu)
+			break;
+		spu_free(spu);
+	}
+	kfree(rq);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore.c b/arch/powerpc/platforms/cell/spufs/spu_restore.c
new file mode 100644
index 0000000..0bf723d
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore.c
@@ -0,0 +1,336 @@
+/*
+ * spu_restore.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * SPU-side context restore sequence outlined in
+ * Synergistic Processor Element Book IV
+ *
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef LS_SIZE
+#define LS_SIZE                 0x40000	/* 256K (in bytes) */
+#endif
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+#include <spu_intrinsics.h>
+#include <asm/spu_csa.h>
+#include "spu_utils.h"
+
+#define BR_INSTR		0x327fff80	/* br -4         */
+#define NOP_INSTR		0x40200000	/* nop           */
+#define HEQ_INSTR		0x7b000000	/* heq $0, $0    */
+#define STOP_INSTR		0x00000000	/* stop 0x0      */
+#define ILLEGAL_INSTR		0x00800000	/* illegal instr */
+#define RESTORE_COMPLETE	0x00003ffc	/* stop 0x3ffc   */
+
+static inline void fetch_regs_from_mem(addr64 lscsa_ea)
+{
+	unsigned int ls = (unsigned int)&regs_spill[0];
+	unsigned int size = sizeof(regs_spill);
+	unsigned int tag_id = 0;
+	unsigned int cmd = 0x40;	/* GET */
+
+	spu_writech(MFC_LSA, ls);
+	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+	spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+	spu_writech(MFC_Size, size);
+	spu_writech(MFC_TagID, tag_id);
+	spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void restore_upper_240kb(addr64 lscsa_ea)
+{
+	unsigned int ls = 16384;
+	unsigned int list = (unsigned int)&dma_list[0];
+	unsigned int size = sizeof(dma_list);
+	unsigned int tag_id = 0;
+	unsigned int cmd = 0x44;	/* GETL */
+
+	/* Restore, Step 4:
+	 *    Enqueue the GETL command (tag 0) to the MFC SPU command
+	 *    queue to transfer the upper 240 kb of LS from CSA.
+	 */
+	spu_writech(MFC_LSA, ls);
+	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+	spu_writech(MFC_EAL, list);
+	spu_writech(MFC_Size, size);
+	spu_writech(MFC_TagID, tag_id);
+	spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void restore_decr(void)
+{
+	unsigned int offset;
+	unsigned int decr_running;
+	unsigned int decr;
+
+	/* Restore, Step 6:
+	 *    If the LSCSA "decrementer running" flag is set
+	 *    then write the SPU_WrDec channel with the
+	 *    decrementer value from LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(decr_status);
+	decr_running = regs_spill[offset].slot[0];
+	if (decr_running) {
+		offset = LSCSA_QW_OFFSET(decr);
+		decr = regs_spill[offset].slot[0];
+		spu_writech(SPU_WrDec, decr);
+	}
+}
+
+static inline void write_ppu_mb(void)
+{
+	unsigned int offset;
+	unsigned int data;
+
+	/* Restore, Step 11:
+	 *    Write the MFC_WrOut_MB channel with the PPU_MB
+	 *    data from LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(ppu_mb);
+	data = regs_spill[offset].slot[0];
+	spu_writech(SPU_WrOutMbox, data);
+}
+
+static inline void write_ppuint_mb(void)
+{
+	unsigned int offset;
+	unsigned int data;
+
+	/* Restore, Step 12:
+	 *    Write the MFC_WrInt_MB channel with the PPUINT_MB
+	 *    data from LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(ppuint_mb);
+	data = regs_spill[offset].slot[0];
+	spu_writech(SPU_WrOutIntrMbox, data);
+}
+
+static inline void restore_fpcr(void)
+{
+	unsigned int offset;
+	vector unsigned int fpcr;
+
+	/* Restore, Step 13:
+	 *    Restore the floating-point status and control
+	 *    register from the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(fpcr);
+	fpcr = regs_spill[offset].v;
+	spu_mtfpscr(fpcr);
+}
+
+static inline void restore_srr0(void)
+{
+	unsigned int offset;
+	unsigned int srr0;
+
+	/* Restore, Step 14:
+	 *    Restore the SPU SRR0 data from the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(srr0);
+	srr0 = regs_spill[offset].slot[0];
+	spu_writech(SPU_WrSRR0, srr0);
+}
+
+static inline void restore_event_mask(void)
+{
+	unsigned int offset;
+	unsigned int event_mask;
+
+	/* Restore, Step 15:
+	 *    Restore the SPU_RdEventMsk data from the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(event_mask);
+	event_mask = regs_spill[offset].slot[0];
+	spu_writech(SPU_WrEventMask, event_mask);
+}
+
+static inline void restore_tag_mask(void)
+{
+	unsigned int offset;
+	unsigned int tag_mask;
+
+	/* Restore, Step 16:
+	 *    Restore the SPU_RdTagMsk data from the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(tag_mask);
+	tag_mask = regs_spill[offset].slot[0];
+	spu_writech(MFC_WrTagMask, tag_mask);
+}
+
+static inline void restore_complete(void)
+{
+	extern void exit_fini(void);
+	unsigned int *exit_instrs = (unsigned int *)exit_fini;
+	unsigned int offset;
+	unsigned int stopped_status;
+	unsigned int stopped_code;
+
+	/* Restore, Step 18:
+	 *    Issue a stop-and-signal instruction with
+	 *    "good context restore" signal value.
+	 *
+	 * Restore, Step 19:
+	 *    There may be additional instructions placed
+	 *    here by the PPE Sequence for SPU Context
+	 *    Restore in order to restore the correct
+	 *    "stopped state".
+	 *
+	 *    This step is handled here by analyzing the
+	 *    LSCSA.stopped_status and then modifying the
+	 *    exit() function to behave appropriately.
+	 */
+
+	offset = LSCSA_QW_OFFSET(stopped_status);
+	stopped_status = regs_spill[offset].slot[0];
+	stopped_code = regs_spill[offset].slot[1];
+
+	switch (stopped_status) {
+	case SPU_STOPPED_STATUS_P_I:
+		/* SPU_Status[P,I]=1.  Add illegal instruction
+		 * followed by stop-and-signal instruction after
+		 * end of restore code.
+		 */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = ILLEGAL_INSTR;
+		exit_instrs[2] = STOP_INSTR | stopped_code;
+		break;
+	case SPU_STOPPED_STATUS_P_H:
+		/* SPU_Status[P,H]=1.  Add 'heq $0, $0' followed
+		 * by stop-and-signal instruction after end of
+		 * restore code.
+		 */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = HEQ_INSTR;
+		exit_instrs[2] = STOP_INSTR | stopped_code;
+		break;
+	case SPU_STOPPED_STATUS_S_P:
+		/* SPU_Status[S,P]=1.  Add nop instruction
+		 * followed by 'br -4' after end of restore
+		 * code.
+		 */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = STOP_INSTR | stopped_code;
+		exit_instrs[2] = NOP_INSTR;
+		exit_instrs[3] = BR_INSTR;
+		break;
+	case SPU_STOPPED_STATUS_S_I:
+		/* SPU_Status[S,I]=1.  Add  illegal instruction
+		 * followed by 'br -4' after end of restore code.
+		 */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = ILLEGAL_INSTR;
+		exit_instrs[2] = NOP_INSTR;
+		exit_instrs[3] = BR_INSTR;
+		break;
+	case SPU_STOPPED_STATUS_I:
+		/* SPU_Status[I]=1. Add illegal instruction followed
+		 * by infinite loop after end of restore sequence.
+		 */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = ILLEGAL_INSTR;
+		exit_instrs[2] = NOP_INSTR;
+		exit_instrs[3] = BR_INSTR;
+		break;
+	case SPU_STOPPED_STATUS_S:
+		/* SPU_Status[S]=1. Add two 'nop' instructions. */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = NOP_INSTR;
+		exit_instrs[2] = NOP_INSTR;
+		exit_instrs[3] = BR_INSTR;
+		break;
+	case SPU_STOPPED_STATUS_H:
+		/* SPU_Status[H]=1. Add 'heq $0, $0' instruction
+		 * after end of restore code.
+		 */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = HEQ_INSTR;
+		exit_instrs[2] = NOP_INSTR;
+		exit_instrs[3] = BR_INSTR;
+		break;
+	case SPU_STOPPED_STATUS_P:
+		/* SPU_Status[P]=1. Add stop-and-signal instruction
+		 * after end of restore code.
+		 */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = STOP_INSTR | stopped_code;
+		break;
+	case SPU_STOPPED_STATUS_R:
+		/* SPU_Status[I,S,H,P,R]=0. Add infinite loop. */
+		exit_instrs[0] = RESTORE_COMPLETE;
+		exit_instrs[1] = NOP_INSTR;
+		exit_instrs[2] = NOP_INSTR;
+		exit_instrs[3] = BR_INSTR;
+		break;
+	default:
+		/* SPU_Status[R]=1. No additonal instructions. */
+		break;
+	}
+	spu_sync();
+}
+
+/**
+ * main - entry point for SPU-side context restore.
+ *
+ * This code deviates from the documented sequence in the
+ * following aspects:
+ *
+ * 	1. The EA for LSCSA is passed from PPE in the
+ *	   signal notification channels.
+ *	2. The register spill area is pulled by SPU
+ *	   into LS, rather than pushed by PPE.
+ *	3. All 128 registers are restored by exit().
+ *	4. The exit() function is modified at run
+ *	   time in order to properly restore the
+ *	   SPU_Status register.
+ */
+int main()
+{
+	addr64 lscsa_ea;
+
+	lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
+	lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
+	fetch_regs_from_mem(lscsa_ea);
+
+	set_event_mask();		/* Step 1.  */
+	set_tag_mask();			/* Step 2.  */
+	build_dma_list(lscsa_ea);	/* Step 3.  */
+	restore_upper_240kb(lscsa_ea);	/* Step 4.  */
+					/* Step 5: done by 'exit'. */
+	restore_decr();			/* Step 6. */
+	enqueue_putllc(lscsa_ea);	/* Step 7. */
+	set_tag_update();		/* Step 8. */
+	read_tag_status();		/* Step 9. */
+	read_llar_status();		/* Step 10. */
+	write_ppu_mb();			/* Step 11. */
+	write_ppuint_mb();		/* Step 12. */
+	restore_fpcr();			/* Step 13. */
+	restore_srr0();			/* Step 14. */
+	restore_event_mask();		/* Step 15. */
+	restore_tag_mask();		/* Step 16. */
+					/* Step 17. done by 'exit'. */
+	restore_complete();		/* Step 18. */
+
+	return 0;
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S b/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S
new file mode 100644
index 0000000..2905949
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S
@@ -0,0 +1,116 @@
+/*
+ * crt0_r.S: Entry function for SPU-side context restore.
+ *
+ * Copyright (C) 2005 IBM
+ *
+ * Entry and exit function for SPU-side of the context restore
+ * sequence.  Sets up an initial stack frame, then branches to
+ * 'main'.  On return, restores all 128 registers from the LSCSA
+ * and exits.
+ *
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/spu_csa.h>
+
+.data
+.align 7
+.globl regs_spill
+regs_spill:
+.space SIZEOF_SPU_SPILL_REGS, 0x0
+
+.text
+.global _start
+_start:
+	/* Initialize the stack pointer to point to 16368
+	 * (16kb-16). The back chain pointer is initialized
+	 * to NULL.
+	 */
+	il      $0, 0
+	il      $SP, 16368
+	stqd    $0, 0($SP)
+
+	/* Allocate a minimum stack frame for the called main.
+	 * This is needed so that main has a place to save the
+	 * link register when it calls another function.
+	 */
+	stqd    $SP, -160($SP)
+	ai      $SP, $SP, -160
+
+	/* Call the program's main function. */
+	brsl    $0, main
+
+.global exit
+.global	_exit
+exit:
+_exit:
+	/* SPU Context Restore, Step 5: Restore the remaining 112 GPRs. */
+	ila     $3, regs_spill + 256
+restore_regs:
+	lqr     $4, restore_reg_insts
+restore_reg_loop:
+	ai      $4, $4, 4
+	.balignl 16, 0x40200000
+restore_reg_insts:       /* must be quad-word aligned. */
+	lqd     $16, 0($3)
+	lqd     $17, 16($3)
+	lqd     $18, 32($3)
+	lqd     $19, 48($3)
+	andi    $5, $4, 0x7F
+	stqr    $4, restore_reg_insts
+	ai      $3, $3, 64
+	brnz    $5, restore_reg_loop
+
+	/* SPU Context Restore Step 17: Restore the first 16 GPRs. */
+	lqa $0, regs_spill + 0
+	lqa $1, regs_spill + 16
+	lqa $2, regs_spill + 32
+	lqa $3, regs_spill + 48
+	lqa $4, regs_spill + 64
+	lqa $5, regs_spill + 80
+	lqa $6, regs_spill + 96
+	lqa $7, regs_spill + 112
+	lqa $8, regs_spill + 128
+	lqa $9, regs_spill + 144
+	lqa $10, regs_spill + 160
+	lqa $11, regs_spill + 176
+	lqa $12, regs_spill + 192
+	lqa $13, regs_spill + 208
+	lqa $14, regs_spill + 224
+	lqa $15, regs_spill + 240
+
+	/* Under normal circumstances, the 'exit' function
+	 * terminates with 'stop SPU_RESTORE_COMPLETE',
+	 * indicating that the SPU-side restore code has
+	 * completed.
+	 *
+	 * However it is possible that instructions immediately
+	 * following the 'stop 0x3ffc' have been modified at run
+	 * time so as to recreate the exact SPU_Status settings
+	 * from the application, e.g. illegal instruciton, halt,
+	 * etc.
+	 */
+.global exit_fini
+.global	_exit_fini
+exit_fini:
+_exit_fini:
+	stop	SPU_RESTORE_COMPLETE
+	stop	0
+	stop	0
+	stop	0
+
+	/* Pad the size of this crt0.o to be multiple of 16 bytes. */
+.balignl 16, 0x0
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
new file mode 100644
index 0000000..1b2355f
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
@@ -0,0 +1,231 @@
+/*
+ * spu_restore_dump.h: Copyright (C) 2005 IBM.
+ * Hex-dump auto generated from spu_restore.c.
+ * Do not edit!
+ */
+static unsigned int spu_restore_code[] __page_aligned = {
+0x40800000, 0x409ff801, 0x24000080, 0x24fd8081,
+0x1cd80081, 0x33001180, 0x42030003, 0x33800284,
+0x1c010204, 0x40200000, 0x40200000, 0x40200000,
+0x34000190, 0x34004191, 0x34008192, 0x3400c193,
+0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffa85,
+0x3080a000, 0x3080a201, 0x3080a402, 0x3080a603,
+0x3080a804, 0x3080aa05, 0x3080ac06, 0x3080ae07,
+0x3080b008, 0x3080b209, 0x3080b40a, 0x3080b60b,
+0x3080b80c, 0x3080ba0d, 0x3080bc0e, 0x3080be0f,
+0x00003ffc, 0x00000000, 0x00000000, 0x00000000,
+0x01a00182, 0x3ec00083, 0xb0a14103, 0x01a00204,
+0x3ec10082, 0x4202800e, 0x04000703, 0xb0a14202,
+0x21a00803, 0x3fbf028d, 0x3f20068d, 0x3fbe0682,
+0x3fe30102, 0x21a00882, 0x3f82028f, 0x3fe3078f,
+0x3fbf0784, 0x3f200204, 0x3fbe0204, 0x3fe30204,
+0x04000203, 0x21a00903, 0x40848002, 0x21a00982,
+0x40800003, 0x21a00a03, 0x40802002, 0x21a00a82,
+0x21a00083, 0x40800082, 0x21a00b02, 0x10002818,
+0x40a80002, 0x32800007, 0x4207000c, 0x18008208,
+0x40a0000b, 0x4080020a, 0x40800709, 0x00200000,
+0x42070002, 0x3ac30384, 0x1cffc489, 0x00200000,
+0x18008383, 0x38830382, 0x4cffc486, 0x3ac28185,
+0xb0408584, 0x28830382, 0x1c020387, 0x38828182,
+0xb0408405, 0x1802c408, 0x28828182, 0x217ff886,
+0x04000583, 0x21a00803, 0x3fbe0682, 0x3fe30102,
+0x04000106, 0x21a00886, 0x04000603, 0x21a00903,
+0x40803c02, 0x21a00982, 0x40800003, 0x04000184,
+0x21a00a04, 0x40802202, 0x21a00a82, 0x42028005,
+0x34208702, 0x21002282, 0x21a00804, 0x21a00886,
+0x3fbf0782, 0x3f200102, 0x3fbe0102, 0x3fe30102,
+0x21a00902, 0x40804003, 0x21a00983, 0x21a00a04,
+0x40805a02, 0x21a00a82, 0x40800083, 0x21a00b83,
+0x01a00c02, 0x01a00d83, 0x3420c282, 0x21a00e02,
+0x34210283, 0x21a00f03, 0x34200284, 0x77400200,
+0x3421c282, 0x21a00702, 0x34218283, 0x21a00083,
+0x34214282, 0x21a00b02, 0x4200480c, 0x00200000,
+0x1c010286, 0x34220284, 0x34220302, 0x0f608203,
+0x5c024204, 0x3b81810b, 0x42013c02, 0x00200000,
+0x18008185, 0x38808183, 0x3b814182, 0x21004e84,
+0x4020007f, 0x35000100, 0x000004e0, 0x000002a0,
+0x000002e8, 0x00000428, 0x00000360, 0x000002e8,
+0x000004a0, 0x00000468, 0x000003c8, 0x00000360,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40085,
+0x10009c09, 0x3ac10606, 0xb060c105, 0x4020007f,
+0x4020007f, 0x20801203, 0x38810602, 0xb0408586,
+0x28810602, 0x32004180, 0x34204702, 0x21a00382,
+0x4020007f, 0x327fdc80, 0x409ffe02, 0x30801203,
+0x40800204, 0x3ec40087, 0x40800405, 0x00200000,
+0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a,
+0xb060c107, 0x20801203, 0x41004003, 0x38810602,
+0x4020007f, 0xb0408188, 0x4020007f, 0x28810602,
+0x41201002, 0x38814603, 0x10009c09, 0xb060c109,
+0x4020007f, 0x28814603, 0x41193f83, 0x38818602,
+0x60ffc003, 0xb040818a, 0x28818602, 0x32003080,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087,
+0x41201008, 0x10009c14, 0x40800405, 0x3ac10609,
+0x40800606, 0x3ac1460a, 0xb060c107, 0x3ac1860b,
+0x20801203, 0x38810602, 0xb0408409, 0x28810602,
+0x38814603, 0xb060c40a, 0x4020007f, 0x28814603,
+0x41193f83, 0x38818602, 0x60ffc003, 0xb040818b,
+0x28818602, 0x32002380, 0x409ffe02, 0x30801204,
+0x40800205, 0x3ec40083, 0x40800406, 0x3ac14607,
+0x3ac18608, 0xb0810103, 0x41004002, 0x20801204,
+0x4020007f, 0x38814603, 0x10009c0b, 0xb060c107,
+0x4020007f, 0x4020007f, 0x28814603, 0x38818602,
+0x4020007f, 0x4020007f, 0xb0408588, 0x28818602,
+0x4020007f, 0x32001780, 0x409ffe02, 0x1000640e,
+0x40800204, 0x30801203, 0x40800405, 0x3ec40087,
+0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a,
+0xb060c107, 0x20801203, 0x413d8003, 0x38810602,
+0x4020007f, 0x327fd780, 0x409ffe02, 0x10007f0c,
+0x40800205, 0x30801204, 0x40800406, 0x3ec40083,
+0x3ac14607, 0x3ac18608, 0xb0810103, 0x413d8002,
+0x20801204, 0x38814603, 0x4020007f, 0x327feb80,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087,
+0x40800405, 0x1000650a, 0x40800606, 0x3ac10608,
+0x3ac14609, 0x3ac1860a, 0xb060c107, 0x20801203,
+0x38810602, 0xb0408588, 0x4020007f, 0x327fc980,
+0x00400000, 0x40800003, 0x4020007f, 0x35000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save.c b/arch/powerpc/platforms/cell/spufs/spu_save.c
new file mode 100644
index 0000000..196033b
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_save.c
@@ -0,0 +1,195 @@
+/*
+ * spu_save.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * SPU-side context save sequence outlined in
+ * Synergistic Processor Element Book IV
+ *
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef LS_SIZE
+#define LS_SIZE                 0x40000	/* 256K (in bytes) */
+#endif
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+#include <spu_intrinsics.h>
+#include <asm/spu_csa.h>
+#include "spu_utils.h"
+
+static inline void save_event_mask(void)
+{
+	unsigned int offset;
+
+	/* Save, Step 2:
+	 *    Read the SPU_RdEventMsk channel and save to the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(event_mask);
+	regs_spill[offset].slot[0] = spu_readch(SPU_RdEventStatMask);
+}
+
+static inline void save_tag_mask(void)
+{
+	unsigned int offset;
+
+	/* Save, Step 3:
+	 *    Read the SPU_RdTagMsk channel and save to the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(tag_mask);
+	regs_spill[offset].slot[0] = spu_readch(MFC_RdTagMask);
+}
+
+static inline void save_upper_240kb(addr64 lscsa_ea)
+{
+	unsigned int ls = 16384;
+	unsigned int list = (unsigned int)&dma_list[0];
+	unsigned int size = sizeof(dma_list);
+	unsigned int tag_id = 0;
+	unsigned int cmd = 0x24;	/* PUTL */
+
+	/* Save, Step 7:
+	 *    Enqueue the PUTL command (tag 0) to the MFC SPU command
+	 *    queue to transfer the remaining 240 kb of LS to CSA.
+	 */
+	spu_writech(MFC_LSA, ls);
+	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+	spu_writech(MFC_EAL, list);
+	spu_writech(MFC_Size, size);
+	spu_writech(MFC_TagID, tag_id);
+	spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void save_fpcr(void)
+{
+	// vector unsigned int fpcr;
+	unsigned int offset;
+
+	/* Save, Step 9:
+	 *    Issue the floating-point status and control register
+	 *    read instruction, and save to the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(fpcr);
+	regs_spill[offset].v = spu_mffpscr();
+}
+
+static inline void save_decr(void)
+{
+	unsigned int offset;
+
+	/* Save, Step 10:
+	 *    Read and save the SPU_RdDec channel data to
+	 *    the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(decr);
+	regs_spill[offset].slot[0] = spu_readch(SPU_RdDec);
+}
+
+static inline void save_srr0(void)
+{
+	unsigned int offset;
+
+	/* Save, Step 11:
+	 *    Read and save the SPU_WSRR0 channel data to
+	 *    the LSCSA.
+	 */
+	offset = LSCSA_QW_OFFSET(srr0);
+	regs_spill[offset].slot[0] = spu_readch(SPU_RdSRR0);
+}
+
+static inline void spill_regs_to_mem(addr64 lscsa_ea)
+{
+	unsigned int ls = (unsigned int)&regs_spill[0];
+	unsigned int size = sizeof(regs_spill);
+	unsigned int tag_id = 0;
+	unsigned int cmd = 0x20;	/* PUT */
+
+	/* Save, Step 13:
+	 *    Enqueue a PUT command (tag 0) to send the LSCSA
+	 *    to the CSA.
+	 */
+	spu_writech(MFC_LSA, ls);
+	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+	spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+	spu_writech(MFC_Size, size);
+	spu_writech(MFC_TagID, tag_id);
+	spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void enqueue_sync(addr64 lscsa_ea)
+{
+	unsigned int tag_id = 0;
+	unsigned int cmd = 0xCC;
+
+	/* Save, Step 14:
+	 *    Enqueue an MFC_SYNC command (tag 0).
+	 */
+	spu_writech(MFC_TagID, tag_id);
+	spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void save_complete(void)
+{
+	/* Save, Step 18:
+	 *    Issue a stop-and-signal instruction indicating
+	 *    "save complete".  Note: This function will not
+	 *    return!!
+	 */
+	spu_stop(SPU_SAVE_COMPLETE);
+}
+
+/**
+ * main - entry point for SPU-side context save.
+ *
+ * This code deviates from the documented sequence as follows:
+ *
+ *      1. The EA for LSCSA is passed from PPE in the
+ *         signal notification channels.
+ *      2. All 128 registers are saved by crt0.o.
+ */
+int main()
+{
+	addr64 lscsa_ea;
+
+	lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
+	lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
+
+	/* Step 1: done by exit(). */
+	save_event_mask();	/* Step 2.  */
+	save_tag_mask();	/* Step 3.  */
+	set_event_mask();	/* Step 4.  */
+	set_tag_mask();		/* Step 5.  */
+	build_dma_list(lscsa_ea);	/* Step 6.  */
+	save_upper_240kb(lscsa_ea);	/* Step 7.  */
+	/* Step 8: done by exit(). */
+	save_fpcr();		/* Step 9.  */
+	save_decr();		/* Step 10. */
+	save_srr0();		/* Step 11. */
+	enqueue_putllc(lscsa_ea);	/* Step 12. */
+	spill_regs_to_mem(lscsa_ea);	/* Step 13. */
+	enqueue_sync(lscsa_ea);	/* Step 14. */
+	set_tag_update();	/* Step 15. */
+	read_tag_status();	/* Step 16. */
+	read_llar_status();	/* Step 17. */
+	save_complete();	/* Step 18. */
+
+	return 0;
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S b/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S
new file mode 100644
index 0000000..6659d6a
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S
@@ -0,0 +1,102 @@
+/*
+ * crt0_s.S: Entry function for SPU-side context save.
+ *
+ * Copyright (C) 2005 IBM
+ *
+ * Entry function for SPU-side of the context save sequence.
+ * Saves all 128 GPRs, sets up an initial stack frame, then
+ * branches to 'main'.
+ *
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/spu_csa.h>
+
+.data
+.align 7
+.globl regs_spill
+regs_spill:
+.space SIZEOF_SPU_SPILL_REGS, 0x0
+
+.text
+.global _start
+_start:
+	/* SPU Context Save Step 1: Save the first 16 GPRs. */
+	stqa $0, regs_spill + 0
+	stqa $1, regs_spill + 16
+	stqa $2, regs_spill + 32
+	stqa $3, regs_spill + 48
+	stqa $4, regs_spill + 64
+	stqa $5, regs_spill + 80
+	stqa $6, regs_spill + 96
+	stqa $7, regs_spill + 112
+	stqa $8, regs_spill + 128
+	stqa $9, regs_spill + 144
+	stqa $10, regs_spill + 160
+	stqa $11, regs_spill + 176
+	stqa $12, regs_spill + 192
+	stqa $13, regs_spill + 208
+	stqa $14, regs_spill + 224
+	stqa $15, regs_spill + 240
+
+	/* SPU Context Save, Step 8: Save the remaining 112 GPRs. */
+	ila     $3, regs_spill + 256
+save_regs:
+	lqr     $4, save_reg_insts
+save_reg_loop:
+	ai      $4, $4, 4
+	.balignl 16, 0x40200000
+save_reg_insts:       /* must be quad-word aligned. */
+	stqd    $16, 0($3)
+	stqd    $17, 16($3)
+	stqd    $18, 32($3)
+	stqd    $19, 48($3)
+	andi    $5, $4, 0x7F
+	stqr    $4, save_reg_insts
+	ai      $3, $3, 64
+	brnz    $5, save_reg_loop
+
+	/* Initialize the stack pointer to point to 16368
+	 * (16kb-16). The back chain pointer is initialized
+	 * to NULL.
+	 */
+	il	$0, 0
+	il	$SP, 16368
+	stqd	$0, 0($SP)
+
+	/* Allocate a minimum stack frame for the called main.
+	 * This is needed so that main has a place to save the
+	 * link register when it calls another function.
+	 */
+	stqd	$SP, -160($SP)
+	ai	$SP, $SP, -160
+
+	/* Call the program's main function. */
+	brsl	$0, main
+
+	/* In this case main should not return; if it does
+	 * there has been an error in the sequence.  Execute
+	 * stop-and-signal with code=0.
+	 */
+.global exit
+.global	_exit
+exit:
+_exit:
+	stop	0x0
+
+	/* Pad the size of this crt0.o to be multiple of 16 bytes. */
+.balignl 16, 0x0
+
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped
new file mode 100644
index 0000000..39e5400
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped
@@ -0,0 +1,191 @@
+/*
+ * spu_save_dump.h: Copyright (C) 2005 IBM.
+ * Hex-dump auto generated from spu_save.c.
+ * Do not edit!
+ */
+static unsigned int spu_save_code[] __page_aligned = {
+0x20805000, 0x20805201, 0x20805402, 0x20805603,
+0x20805804, 0x20805a05, 0x20805c06, 0x20805e07,
+0x20806008, 0x20806209, 0x2080640a, 0x2080660b,
+0x2080680c, 0x20806a0d, 0x20806c0e, 0x20806e0f,
+0x4201c003, 0x33800184, 0x1c010204, 0x40200000,
+0x24000190, 0x24004191, 0x24008192, 0x2400c193,
+0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffb85,
+0x40800000, 0x409ff801, 0x24000080, 0x24fd8081,
+0x1cd80081, 0x33000180, 0x00000000, 0x00000000,
+0x01a00182, 0x3ec00083, 0xb1c38103, 0x01a00204,
+0x3ec10082, 0x4201400d, 0xb1c38202, 0x01a00583,
+0x34218682, 0x3ed80684, 0xb0408184, 0x24218682,
+0x01a00603, 0x00200000, 0x34214682, 0x3ed40684,
+0xb0408184, 0x40800003, 0x24214682, 0x21a00083,
+0x40800082, 0x21a00b02, 0x4020007f, 0x1000251e,
+0x40a80002, 0x32800008, 0x4205c00c, 0x00200000,
+0x40a0000b, 0x3f82070f, 0x4080020a, 0x40800709,
+0x3fe3078f, 0x3fbf0783, 0x3f200183, 0x3fbe0183,
+0x3fe30187, 0x18008387, 0x4205c002, 0x3ac30404,
+0x1cffc489, 0x00200000, 0x18008403, 0x38830402,
+0x4cffc486, 0x3ac28185, 0xb0408584, 0x28830402,
+0x1c020408, 0x38828182, 0xb0408385, 0x1802c387,
+0x28828182, 0x217ff886, 0x04000582, 0x32800007,
+0x21a00802, 0x3fbf0705, 0x3f200285, 0x3fbe0285,
+0x3fe30285, 0x21a00885, 0x04000603, 0x21a00903,
+0x40803c02, 0x21a00982, 0x04000386, 0x21a00a06,
+0x40801202, 0x21a00a82, 0x73000003, 0x24200683,
+0x01a00404, 0x00200000, 0x34204682, 0x3ec40683,
+0xb0408203, 0x24204682, 0x01a00783, 0x00200000,
+0x3421c682, 0x3edc0684, 0xb0408184, 0x2421c682,
+0x21a00806, 0x21a00885, 0x3fbf0784, 0x3f200204,
+0x3fbe0204, 0x3fe30204, 0x21a00904, 0x40804002,
+0x21a00982, 0x21a00a06, 0x40805a02, 0x21a00a82,
+0x04000683, 0x21a00803, 0x21a00885, 0x21a00904,
+0x40848002, 0x21a00982, 0x21a00a06, 0x40801002,
+0x21a00a82, 0x21a00a06, 0x40806602, 0x00200000,
+0x35800009, 0x21a00a82, 0x40800083, 0x21a00b83,
+0x01a00c02, 0x01a00d83, 0x00003ffb, 0x40800003,
+0x4020007f, 0x35000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/spu_utils.h b/arch/powerpc/platforms/cell/spufs/spu_utils.h
new file mode 100644
index 0000000..58359fe
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_utils.h
@@ -0,0 +1,160 @@
+/*
+ * utils.h: Utilities for SPU-side of the context switch operation.
+ *
+ * (C) Copyright IBM 2005
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SPU_CONTEXT_UTILS_H_
+#define _SPU_CONTEXT_UTILS_H_
+
+/*
+ * 64-bit safe EA.
+ */
+typedef union {
+	unsigned long long ull;
+	unsigned int ui[2];
+} addr64;
+
+/*
+ * 128-bit register template.
+ */
+typedef union {
+	unsigned int slot[4];
+	vector unsigned int v;
+} spu_reg128v;
+
+/*
+ * DMA list structure.
+ */
+struct dma_list_elem {
+	unsigned int size;
+	unsigned int ea_low;
+};
+
+/*
+ * Declare storage for 8-byte aligned DMA list.
+ */
+struct dma_list_elem dma_list[15] __attribute__ ((aligned(8)));
+
+/*
+ * External definition for storage
+ * declared in crt0.
+ */
+extern spu_reg128v regs_spill[NR_SPU_SPILL_REGS];
+
+/*
+ * Compute LSCSA byte offset for a given field.
+ */
+static struct spu_lscsa *dummy = (struct spu_lscsa *)0;
+#define LSCSA_BYTE_OFFSET(_field)  \
+	((char *)(&(dummy->_field)) - (char *)(&(dummy->gprs[0].slot[0])))
+#define LSCSA_QW_OFFSET(_field)  (LSCSA_BYTE_OFFSET(_field) >> 4)
+
+static inline void set_event_mask(void)
+{
+	unsigned int event_mask = 0;
+
+	/* Save, Step 4:
+	 * Restore, Step 1:
+	 *    Set the SPU_RdEventMsk channel to zero to mask
+	 *    all events.
+	 */
+	spu_writech(SPU_WrEventMask, event_mask);
+}
+
+static inline void set_tag_mask(void)
+{
+	unsigned int tag_mask = 1;
+
+	/* Save, Step 5:
+	 * Restore, Step 2:
+	 *    Set the SPU_WrTagMsk channel to '01' to unmask
+	 *    only tag group 0.
+	 */
+	spu_writech(MFC_WrTagMask, tag_mask);
+}
+
+static inline void build_dma_list(addr64 lscsa_ea)
+{
+	unsigned int ea_low;
+	int i;
+
+	/* Save, Step 6:
+	 * Restore, Step 3:
+	 *    Update the effective address for the CSA in the
+	 *    pre-canned DMA-list in local storage.
+	 */
+	ea_low = lscsa_ea.ui[1];
+	ea_low += LSCSA_BYTE_OFFSET(ls[16384]);
+
+	for (i = 0; i < 15; i++, ea_low += 16384) {
+		dma_list[i].size = 16384;
+		dma_list[i].ea_low = ea_low;
+	}
+}
+
+static inline void enqueue_putllc(addr64 lscsa_ea)
+{
+	unsigned int ls = 0;
+	unsigned int size = 128;
+	unsigned int tag_id = 0;
+	unsigned int cmd = 0xB4;	/* PUTLLC */
+
+	/* Save, Step 12:
+	 * Restore, Step 7:
+	 *    Send a PUTLLC (tag 0) command to the MFC using
+	 *    an effective address in the CSA in order to
+	 *    remove any possible lock-line reservation.
+	 */
+	spu_writech(MFC_LSA, ls);
+	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+	spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+	spu_writech(MFC_Size, size);
+	spu_writech(MFC_TagID, tag_id);
+	spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void set_tag_update(void)
+{
+	unsigned int update_any = 1;
+
+	/* Save, Step 15:
+	 * Restore, Step 8:
+	 *    Write the MFC_TagUpdate channel with '01'.
+	 */
+	spu_writech(MFC_WrTagUpdate, update_any);
+}
+
+static inline void read_tag_status(void)
+{
+	/* Save, Step 16:
+	 * Restore, Step 9:
+	 *    Read the MFC_TagStat channel data.
+	 */
+	spu_readch(MFC_RdTagStat);
+}
+
+static inline void read_llar_status(void)
+{
+	/* Save, Step 17:
+	 * Restore, Step 10:
+	 *    Read the MFC_AtomicStat channel data.
+	 */
+	spu_readch(MFC_RdAtomicStat);
+}
+
+#endif				/* _SPU_CONTEXT_UTILS_H_ */
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
new file mode 100644
index 0000000..db2601f
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -0,0 +1,163 @@
+/*
+ * SPU file system
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef SPUFS_H
+#define SPUFS_H
+
+#include <linux/kref.h>
+#include <linux/rwsem.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+
+/* The magic number for our file system */
+enum {
+	SPUFS_MAGIC = 0x23c9b64e,
+};
+
+struct spu_context_ops;
+
+#define SPU_CONTEXT_PREEMPT          0UL
+
+struct spu_context {
+	struct spu *spu;		  /* pointer to a physical SPU */
+	struct spu_state csa;		  /* SPU context save area. */
+	spinlock_t mmio_lock;		  /* protects mmio access */
+	struct address_space *local_store;/* local store backing store */
+
+	enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
+	struct rw_semaphore state_sema;
+	struct semaphore run_sema;
+
+	struct mm_struct *owner;
+
+	struct kref kref;
+	wait_queue_head_t ibox_wq;
+	wait_queue_head_t wbox_wq;
+	wait_queue_head_t stop_wq;
+	struct fasync_struct *ibox_fasync;
+	struct fasync_struct *wbox_fasync;
+	struct spu_context_ops *ops;
+	struct work_struct reap_work;
+	u64 flags;
+};
+
+/* SPU context query/set operations. */
+struct spu_context_ops {
+	int (*mbox_read) (struct spu_context * ctx, u32 * data);
+	 u32(*mbox_stat_read) (struct spu_context * ctx);
+	unsigned int (*mbox_stat_poll)(struct spu_context *ctx,
+					unsigned int events);
+	int (*ibox_read) (struct spu_context * ctx, u32 * data);
+	int (*wbox_write) (struct spu_context * ctx, u32 data);
+	 u32(*signal1_read) (struct spu_context * ctx);
+	void (*signal1_write) (struct spu_context * ctx, u32 data);
+	 u32(*signal2_read) (struct spu_context * ctx);
+	void (*signal2_write) (struct spu_context * ctx, u32 data);
+	void (*signal1_type_set) (struct spu_context * ctx, u64 val);
+	 u64(*signal1_type_get) (struct spu_context * ctx);
+	void (*signal2_type_set) (struct spu_context * ctx, u64 val);
+	 u64(*signal2_type_get) (struct spu_context * ctx);
+	 u32(*npc_read) (struct spu_context * ctx);
+	void (*npc_write) (struct spu_context * ctx, u32 data);
+	 u32(*status_read) (struct spu_context * ctx);
+	char*(*get_ls) (struct spu_context * ctx);
+	void (*runcntl_write) (struct spu_context * ctx, u32 data);
+	void (*runcntl_stop) (struct spu_context * ctx);
+};
+
+extern struct spu_context_ops spu_hw_ops;
+extern struct spu_context_ops spu_backing_ops;
+
+struct spufs_inode_info {
+	struct spu_context *i_ctx;
+	struct inode vfs_inode;
+};
+#define SPUFS_I(inode) \
+	container_of(inode, struct spufs_inode_info, vfs_inode)
+
+extern struct tree_descr spufs_dir_contents[];
+
+/* system call implementation */
+long spufs_run_spu(struct file *file,
+		   struct spu_context *ctx, u32 *npc, u32 *status);
+long spufs_create_thread(struct nameidata *nd,
+			 unsigned int flags, mode_t mode);
+extern struct file_operations spufs_context_fops;
+
+/* context management */
+struct spu_context * alloc_spu_context(struct address_space *local_store);
+void destroy_spu_context(struct kref *kref);
+struct spu_context * get_spu_context(struct spu_context *ctx);
+int put_spu_context(struct spu_context *ctx);
+void spu_unmap_mappings(struct spu_context *ctx);
+
+void spu_forget(struct spu_context *ctx);
+void spu_acquire(struct spu_context *ctx);
+void spu_release(struct spu_context *ctx);
+int spu_acquire_runnable(struct spu_context *ctx);
+void spu_acquire_saved(struct spu_context *ctx);
+
+int spu_activate(struct spu_context *ctx, u64 flags);
+void spu_deactivate(struct spu_context *ctx);
+void spu_yield(struct spu_context *ctx);
+int __init spu_sched_init(void);
+void __exit spu_sched_exit(void);
+
+/*
+ * spufs_wait
+ * 	Same as wait_event_interruptible(), except that here
+ *	we need to call spu_release(ctx) before sleeping, and
+ *	then spu_acquire(ctx) when awoken.
+ */
+
+#define spufs_wait(wq, condition)					\
+({									\
+	int __ret = 0;							\
+	DEFINE_WAIT(__wait);						\
+	for (;;) {							\
+		prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);	\
+		if (condition)						\
+			break;						\
+		if (!signal_pending(current)) {				\
+			spu_release(ctx);				\
+			schedule();					\
+			spu_acquire(ctx);				\
+			continue;					\
+		}							\
+		__ret = -ERESTARTSYS;					\
+		break;							\
+	}								\
+	finish_wait(&(wq), &__wait);					\
+	__ret;								\
+})
+
+size_t spu_wbox_write(struct spu_context *ctx, u32 data);
+size_t spu_ibox_read(struct spu_context *ctx, u32 *data);
+
+/* irq callback funcs. */
+void spufs_ibox_callback(struct spu *spu);
+void spufs_wbox_callback(struct spu *spu);
+void spufs_stop_callback(struct spu *spu);
+
+#endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
new file mode 100644
index 0000000..1061c12
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -0,0 +1,2180 @@
+/*
+ * spu_switch.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * Host-side part of SPU context switch sequence outlined in
+ * Synergistic Processor Element, Book IV.
+ *
+ * A fully premptive switch of an SPE is very expensive in terms
+ * of time and system resources.  SPE Book IV indicates that SPE
+ * allocation should follow a "serially reusable device" model,
+ * in which the SPE is assigned a task until it completes.  When
+ * this is not possible, this sequence may be used to premptively
+ * save, and then later (optionally) restore the context of a
+ * program executing on an SPE.
+ *
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+
+#include "spu_save_dump.h"
+#include "spu_restore_dump.h"
+
+#if 0
+#define POLL_WHILE_TRUE(_c) {				\
+    do {						\
+    } while (_c);					\
+  }
+#else
+#define RELAX_SPIN_COUNT				1000
+#define POLL_WHILE_TRUE(_c) {				\
+    do {						\
+	int _i;						\
+	for (_i=0; _i<RELAX_SPIN_COUNT && (_c); _i++) { \
+	    cpu_relax();				\
+	}						\
+	if (unlikely(_c)) yield();			\
+	else break;					\
+    } while (_c);					\
+  }
+#endif				/* debug */
+
+#define POLL_WHILE_FALSE(_c) 	POLL_WHILE_TRUE(!(_c))
+
+static inline void acquire_spu_lock(struct spu *spu)
+{
+	/* Save, Step 1:
+	 * Restore, Step 1:
+	 *    Acquire SPU-specific mutual exclusion lock.
+	 *    TBD.
+	 */
+}
+
+static inline void release_spu_lock(struct spu *spu)
+{
+	/* Restore, Step 76:
+	 *    Release SPU-specific mutual exclusion lock.
+	 *    TBD.
+	 */
+}
+
+static inline int check_spu_isolate(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	u32 isolate_state;
+
+	/* Save, Step 2:
+	 * Save, Step 6:
+	 *     If SPU_Status[E,L,IS] any field is '1', this
+	 *     SPU is in isolate state and cannot be context
+	 *     saved at this time.
+	 */
+	isolate_state = SPU_STATUS_ISOLATED_STATE |
+	    SPU_STATUS_ISOLATED_LOAD_STAUTUS | SPU_STATUS_ISOLATED_EXIT_STAUTUS;
+	return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0;
+}
+
+static inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 3:
+	 * Restore, Step 2:
+	 *     Save INT_Mask_class0 in CSA.
+	 *     Write INT_MASK_class0 with value of 0.
+	 *     Save INT_Mask_class1 in CSA.
+	 *     Write INT_MASK_class1 with value of 0.
+	 *     Save INT_Mask_class2 in CSA.
+	 *     Write INT_MASK_class2 with value of 0.
+	 */
+	spin_lock_irq(&spu->register_lock);
+	if (csa) {
+		csa->priv1.int_mask_class0_RW = spu_int_mask_get(spu, 0);
+		csa->priv1.int_mask_class1_RW = spu_int_mask_get(spu, 1);
+		csa->priv1.int_mask_class2_RW = spu_int_mask_get(spu, 2);
+	}
+	spu_int_mask_set(spu, 0, 0ul);
+	spu_int_mask_set(spu, 1, 0ul);
+	spu_int_mask_set(spu, 2, 0ul);
+	eieio();
+	spin_unlock_irq(&spu->register_lock);
+}
+
+static inline void set_watchdog_timer(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 4:
+	 * Restore, Step 25.
+	 *    Set a software watchdog timer, which specifies the
+	 *    maximum allowable time for a context save sequence.
+	 *
+	 *    For present, this implementation will not set a global
+	 *    watchdog timer, as virtualization & variable system load
+	 *    may cause unpredictable execution times.
+	 */
+}
+
+static inline void inhibit_user_access(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 5:
+	 * Restore, Step 3:
+	 *     Inhibit user-space access (if provided) to this
+	 *     SPU by unmapping the virtual pages assigned to
+	 *     the SPU memory-mapped I/O (MMIO) for problem
+	 *     state. TBD.
+	 */
+}
+
+static inline void set_switch_pending(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 7:
+	 * Restore, Step 5:
+	 *     Set a software context switch pending flag.
+	 */
+	set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
+	mb();
+}
+
+static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 8:
+	 *     Read and save MFC_CNTL[Ss].
+	 */
+	if (csa) {
+		csa->priv2.mfc_control_RW = in_be64(&priv2->mfc_control_RW) &
+		    MFC_CNTL_SUSPEND_DMA_STATUS_MASK;
+	}
+}
+
+static inline void save_spu_runcntl(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 9:
+	 *     Save SPU_Runcntl in the CSA.  This value contains
+	 *     the "Application Desired State".
+	 */
+	csa->prob.spu_runcntl_RW = in_be32(&prob->spu_runcntl_RW);
+}
+
+static inline void save_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 10:
+	 *     Save MFC_SR1 in the CSA.
+	 */
+	csa->priv1.mfc_sr1_RW = spu_mfc_sr1_get(spu);
+}
+
+static inline void save_spu_status(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 11:
+	 *     Read SPU_Status[R], and save to CSA.
+	 */
+	if ((in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) == 0) {
+		csa->prob.spu_status_R = in_be32(&prob->spu_status_R);
+	} else {
+		u32 stopped;
+
+		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+		eieio();
+		POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+				SPU_STATUS_RUNNING);
+		stopped =
+		    SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP |
+		    SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
+		if ((in_be32(&prob->spu_status_R) & stopped) == 0)
+			csa->prob.spu_status_R = SPU_STATUS_RUNNING;
+		else
+			csa->prob.spu_status_R = in_be32(&prob->spu_status_R);
+	}
+}
+
+static inline void save_mfc_decr(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 12:
+	 *     Read MFC_CNTL[Ds].  Update saved copy of
+	 *     CSA.MFC_CNTL[Ds].
+	 */
+	if (in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING) {
+		csa->priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
+		csa->suspend_time = get_cycles();
+		out_be64(&priv2->spu_chnlcntptr_RW, 7ULL);
+		eieio();
+		csa->spu_chnldata_RW[7] = in_be64(&priv2->spu_chnldata_RW);
+		eieio();
+	}
+}
+
+static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 13:
+	 *     Write MFC_CNTL[Dh] set to a '1' to halt
+	 *     the decrementer.
+	 */
+	out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED);
+	eieio();
+}
+
+static inline void save_timebase(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 14:
+	 *    Read PPE Timebase High and Timebase low registers
+	 *    and save in CSA.  TBD.
+	 */
+	csa->suspend_time = get_cycles();
+}
+
+static inline void remove_other_spu_access(struct spu_state *csa,
+					   struct spu *spu)
+{
+	/* Save, Step 15:
+	 *     Remove other SPU access to this SPU by unmapping
+	 *     this SPU's pages from their address space.  TBD.
+	 */
+}
+
+static inline void do_mfc_mssync(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 16:
+	 * Restore, Step 11.
+	 *     Write SPU_MSSync register. Poll SPU_MSSync[P]
+	 *     for a value of 0.
+	 */
+	out_be64(&prob->spc_mssync_RW, 1UL);
+	POLL_WHILE_TRUE(in_be64(&prob->spc_mssync_RW) & MS_SYNC_PENDING);
+}
+
+static inline void issue_mfc_tlbie(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 17:
+	 * Restore, Step 12.
+	 * Restore, Step 48.
+	 *     Write TLB_Invalidate_Entry[IS,VPN,L,Lp]=0 register.
+	 *     Then issue a PPE sync instruction.
+	 */
+	spu_tlb_invalidate(spu);
+	mb();
+}
+
+static inline void handle_pending_interrupts(struct spu_state *csa,
+					     struct spu *spu)
+{
+	/* Save, Step 18:
+	 *     Handle any pending interrupts from this SPU
+	 *     here.  This is OS or hypervisor specific.  One
+	 *     option is to re-enable interrupts to handle any
+	 *     pending interrupts, with the interrupt handlers
+	 *     recognizing the software Context Switch Pending
+	 *     flag, to ensure the SPU execution or MFC command
+	 *     queue is not restarted.  TBD.
+	 */
+}
+
+static inline void save_mfc_queues(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	int i;
+
+	/* Save, Step 19:
+	 *     If MFC_Cntl[Se]=0 then save
+	 *     MFC command queues.
+	 */
+	if ((in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DMA_QUEUES_EMPTY) == 0) {
+		for (i = 0; i < 8; i++) {
+			csa->priv2.puq[i].mfc_cq_data0_RW =
+			    in_be64(&priv2->puq[i].mfc_cq_data0_RW);
+			csa->priv2.puq[i].mfc_cq_data1_RW =
+			    in_be64(&priv2->puq[i].mfc_cq_data1_RW);
+			csa->priv2.puq[i].mfc_cq_data2_RW =
+			    in_be64(&priv2->puq[i].mfc_cq_data2_RW);
+			csa->priv2.puq[i].mfc_cq_data3_RW =
+			    in_be64(&priv2->puq[i].mfc_cq_data3_RW);
+		}
+		for (i = 0; i < 16; i++) {
+			csa->priv2.spuq[i].mfc_cq_data0_RW =
+			    in_be64(&priv2->spuq[i].mfc_cq_data0_RW);
+			csa->priv2.spuq[i].mfc_cq_data1_RW =
+			    in_be64(&priv2->spuq[i].mfc_cq_data1_RW);
+			csa->priv2.spuq[i].mfc_cq_data2_RW =
+			    in_be64(&priv2->spuq[i].mfc_cq_data2_RW);
+			csa->priv2.spuq[i].mfc_cq_data3_RW =
+			    in_be64(&priv2->spuq[i].mfc_cq_data3_RW);
+		}
+	}
+}
+
+static inline void save_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 20:
+	 *     Save the PPU_QueryMask register
+	 *     in the CSA.
+	 */
+	csa->prob.dma_querymask_RW = in_be32(&prob->dma_querymask_RW);
+}
+
+static inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 21:
+	 *     Save the PPU_QueryType register
+	 *     in the CSA.
+	 */
+	csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW);
+}
+
+static inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 22:
+	 *     Save the MFC_CSR_TSQ register
+	 *     in the LSCSA.
+	 */
+	csa->priv2.spu_tag_status_query_RW =
+	    in_be64(&priv2->spu_tag_status_query_RW);
+}
+
+static inline void save_mfc_csr_cmd(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 23:
+	 *     Save the MFC_CSR_CMD1 and MFC_CSR_CMD2
+	 *     registers in the CSA.
+	 */
+	csa->priv2.spu_cmd_buf1_RW = in_be64(&priv2->spu_cmd_buf1_RW);
+	csa->priv2.spu_cmd_buf2_RW = in_be64(&priv2->spu_cmd_buf2_RW);
+}
+
+static inline void save_mfc_csr_ato(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 24:
+	 *     Save the MFC_CSR_ATO register in
+	 *     the CSA.
+	 */
+	csa->priv2.spu_atomic_status_RW = in_be64(&priv2->spu_atomic_status_RW);
+}
+
+static inline void save_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 25:
+	 *     Save the MFC_TCLASS_ID register in
+	 *     the CSA.
+	 */
+	csa->priv1.mfc_tclass_id_RW = spu_mfc_tclass_id_get(spu);
+}
+
+static inline void set_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 26:
+	 * Restore, Step 23.
+	 *     Write the MFC_TCLASS_ID register with
+	 *     the value 0x10000000.
+	 */
+	spu_mfc_tclass_id_set(spu, 0x10000000);
+	eieio();
+}
+
+static inline void purge_mfc_queue(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 27:
+	 * Restore, Step 14.
+	 *     Write MFC_CNTL[Pc]=1 (purge queue).
+	 */
+	out_be64(&priv2->mfc_control_RW, MFC_CNTL_PURGE_DMA_REQUEST);
+	eieio();
+}
+
+static inline void wait_purge_complete(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 28:
+	 *     Poll MFC_CNTL[Ps] until value '11' is read
+	 *     (purge complete).
+	 */
+	POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) &
+			 MFC_CNTL_PURGE_DMA_COMPLETE);
+}
+
+static inline void save_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	int i;
+
+	/* Save, Step 29:
+	 *     If MFC_SR1[R]='1', save SLBs in CSA.
+	 */
+	if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) {
+		csa->priv2.slb_index_W = in_be64(&priv2->slb_index_W);
+		for (i = 0; i < 8; i++) {
+			out_be64(&priv2->slb_index_W, i);
+			eieio();
+			csa->slb_esid_RW[i] = in_be64(&priv2->slb_esid_RW);
+			csa->slb_vsid_RW[i] = in_be64(&priv2->slb_vsid_RW);
+			eieio();
+		}
+	}
+}
+
+static inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 30:
+	 * Restore, Step 18:
+	 *     Write MFC_SR1 with MFC_SR1[D=0,S=1] and
+	 *     MFC_SR1[TL,R,Pr,T] set correctly for the
+	 *     OS specific environment.
+	 *
+	 *     Implementation note: The SPU-side code
+	 *     for save/restore is privileged, so the
+	 *     MFC_SR1[Pr] bit is not set.
+	 *
+	 */
+	spu_mfc_sr1_set(spu, (MFC_STATE1_MASTER_RUN_CONTROL_MASK |
+			      MFC_STATE1_RELOCATE_MASK |
+			      MFC_STATE1_BUS_TLBIE_MASK));
+}
+
+static inline void save_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 31:
+	 *     Save SPU_NPC in the CSA.
+	 */
+	csa->prob.spu_npc_RW = in_be32(&prob->spu_npc_RW);
+}
+
+static inline void save_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 32:
+	 *     Save SPU_PrivCntl in the CSA.
+	 */
+	csa->priv2.spu_privcntl_RW = in_be64(&priv2->spu_privcntl_RW);
+}
+
+static inline void reset_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 33:
+	 * Restore, Step 16:
+	 *     Write SPU_PrivCntl[S,Le,A] fields reset to 0.
+	 */
+	out_be64(&priv2->spu_privcntl_RW, 0UL);
+	eieio();
+}
+
+static inline void save_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 34:
+	 *     Save SPU_LSLR in the CSA.
+	 */
+	csa->priv2.spu_lslr_RW = in_be64(&priv2->spu_lslr_RW);
+}
+
+static inline void reset_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 35:
+	 * Restore, Step 17.
+	 *     Reset SPU_LSLR.
+	 */
+	out_be64(&priv2->spu_lslr_RW, LS_ADDR_MASK);
+	eieio();
+}
+
+static inline void save_spu_cfg(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 36:
+	 *     Save SPU_Cfg in the CSA.
+	 */
+	csa->priv2.spu_cfg_RW = in_be64(&priv2->spu_cfg_RW);
+}
+
+static inline void save_pm_trace(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 37:
+	 *     Save PM_Trace_Tag_Wait_Mask in the CSA.
+	 *     Not performed by this implementation.
+	 */
+}
+
+static inline void save_mfc_rag(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 38:
+	 *     Save RA_GROUP_ID register and the
+	 *     RA_ENABLE reigster in the CSA.
+	 */
+	csa->priv1.resource_allocation_groupID_RW =
+		spu_resource_allocation_groupID_get(spu);
+	csa->priv1.resource_allocation_enable_RW =
+		spu_resource_allocation_enable_get(spu);
+}
+
+static inline void save_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 39:
+	 *     Save MB_Stat register in the CSA.
+	 */
+	csa->prob.mb_stat_R = in_be32(&prob->mb_stat_R);
+}
+
+static inline void save_ppu_mb(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 40:
+	 *     Save the PPU_MB register in the CSA.
+	 */
+	csa->prob.pu_mb_R = in_be32(&prob->pu_mb_R);
+}
+
+static inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 41:
+	 *     Save the PPUINT_MB register in the CSA.
+	 */
+	csa->priv2.puint_mb_R = in_be64(&priv2->puint_mb_R);
+}
+
+static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 idx, ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+	int i;
+
+	/* Save, Step 42:
+	 *     Save the following CH: [0,1,3,4,24,25,27]
+	 */
+	for (i = 0; i < 7; i++) {
+		idx = ch_indices[i];
+		out_be64(&priv2->spu_chnlcntptr_RW, idx);
+		eieio();
+		csa->spu_chnldata_RW[idx] = in_be64(&priv2->spu_chnldata_RW);
+		csa->spu_chnlcnt_RW[idx] = in_be64(&priv2->spu_chnlcnt_RW);
+		out_be64(&priv2->spu_chnldata_RW, 0UL);
+		out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+		eieio();
+	}
+}
+
+static inline void save_spu_mb(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	int i;
+
+	/* Save, Step 43:
+	 *     Save SPU Read Mailbox Channel.
+	 */
+	out_be64(&priv2->spu_chnlcntptr_RW, 29UL);
+	eieio();
+	csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW);
+	for (i = 0; i < 4; i++) {
+		csa->spu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW);
+	}
+	out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+	eieio();
+}
+
+static inline void save_mfc_cmd(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 44:
+	 *     Save MFC_CMD Channel.
+	 */
+	out_be64(&priv2->spu_chnlcntptr_RW, 21UL);
+	eieio();
+	csa->spu_chnlcnt_RW[21] = in_be64(&priv2->spu_chnlcnt_RW);
+	eieio();
+}
+
+static inline void reset_ch(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 ch_indices[4] = { 21UL, 23UL, 28UL, 30UL };
+	u64 ch_counts[4] = { 16UL, 1UL, 1UL, 1UL };
+	u64 idx;
+	int i;
+
+	/* Save, Step 45:
+	 *     Reset the following CH: [21, 23, 28, 30]
+	 */
+	for (i = 0; i < 4; i++) {
+		idx = ch_indices[i];
+		out_be64(&priv2->spu_chnlcntptr_RW, idx);
+		eieio();
+		out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+		eieio();
+	}
+}
+
+static inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 46:
+	 * Restore, Step 25.
+	 *     Write MFC_CNTL[Sc]=0 (resume queue processing).
+	 */
+	out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE);
+}
+
+static inline void invalidate_slbs(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Save, Step 45:
+	 * Restore, Step 19:
+	 *     If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All.
+	 */
+	if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) {
+		out_be64(&priv2->slb_invalidate_all_W, 0UL);
+		eieio();
+	}
+}
+
+static inline void get_kernel_slb(u64 ea, u64 slb[2])
+{
+	slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
+	slb[1] = (ea & ESID_MASK) | SLB_ESID_V;
+
+	/* Large pages are used for kernel text/data, but not vmalloc.  */
+	if (cpu_has_feature(CPU_FTR_16M_PAGE)
+	    && REGION_ID(ea) == KERNEL_REGION_ID)
+		slb[0] |= SLB_VSID_L;
+}
+
+static inline void load_mfc_slb(struct spu *spu, u64 slb[2], int slbe)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	out_be64(&priv2->slb_index_W, slbe);
+	eieio();
+	out_be64(&priv2->slb_vsid_RW, slb[0]);
+	out_be64(&priv2->slb_esid_RW, slb[1]);
+	eieio();
+}
+
+static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+	u64 code_slb[2];
+	u64 lscsa_slb[2];
+
+	/* Save, Step 47:
+	 * Restore, Step 30.
+	 *     If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All
+	 *     register, then initialize SLB_VSID and SLB_ESID
+	 *     to provide access to SPU context save code and
+	 *     LSCSA.
+	 *
+	 *     This implementation places both the context
+	 *     switch code and LSCSA in kernel address space.
+	 *
+	 *     Further this implementation assumes that the
+	 *     MFC_SR1[R]=1 (in other words, assume that
+	 *     translation is desired by OS environment).
+	 */
+	invalidate_slbs(csa, spu);
+	get_kernel_slb((unsigned long)&spu_save_code[0], code_slb);
+	get_kernel_slb((unsigned long)csa->lscsa, lscsa_slb);
+	load_mfc_slb(spu, code_slb, 0);
+	if ((lscsa_slb[0] != code_slb[0]) || (lscsa_slb[1] != code_slb[1]))
+		load_mfc_slb(spu, lscsa_slb, 1);
+}
+
+static inline void set_switch_active(struct spu_state *csa, struct spu *spu)
+{
+	/* Save, Step 48:
+	 * Restore, Step 23.
+	 *     Change the software context switch pending flag
+	 *     to context switch active.
+	 */
+	set_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
+	clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
+	mb();
+}
+
+static inline void enable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+	unsigned long class1_mask = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
+	    CLASS1_ENABLE_STORAGE_FAULT_INTR;
+
+	/* Save, Step 49:
+	 * Restore, Step 22:
+	 *     Reset and then enable interrupts, as
+	 *     needed by OS.
+	 *
+	 *     This implementation enables only class1
+	 *     (translation) interrupts.
+	 */
+	spin_lock_irq(&spu->register_lock);
+	spu_int_stat_clear(spu, 0, ~0ul);
+	spu_int_stat_clear(spu, 1, ~0ul);
+	spu_int_stat_clear(spu, 2, ~0ul);
+	spu_int_mask_set(spu, 0, 0ul);
+	spu_int_mask_set(spu, 1, class1_mask);
+	spu_int_mask_set(spu, 2, 0ul);
+	spin_unlock_irq(&spu->register_lock);
+}
+
+static inline int send_mfc_dma(struct spu *spu, unsigned long ea,
+			       unsigned int ls_offset, unsigned int size,
+			       unsigned int tag, unsigned int rclass,
+			       unsigned int cmd)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	union mfc_tag_size_class_cmd command;
+	unsigned int transfer_size;
+	volatile unsigned int status = 0x0;
+
+	while (size > 0) {
+		transfer_size =
+		    (size > MFC_MAX_DMA_SIZE) ? MFC_MAX_DMA_SIZE : size;
+		command.u.mfc_size = transfer_size;
+		command.u.mfc_tag = tag;
+		command.u.mfc_rclassid = rclass;
+		command.u.mfc_cmd = cmd;
+		do {
+			out_be32(&prob->mfc_lsa_W, ls_offset);
+			out_be64(&prob->mfc_ea_W, ea);
+			out_be64(&prob->mfc_union_W.all64, command.all64);
+			status =
+			    in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
+			if (unlikely(status & 0x2)) {
+				cpu_relax();
+			}
+		} while (status & 0x3);
+		size -= transfer_size;
+		ea += transfer_size;
+		ls_offset += transfer_size;
+	}
+	return 0;
+}
+
+static inline void save_ls_16kb(struct spu_state *csa, struct spu *spu)
+{
+	unsigned long addr = (unsigned long)&csa->lscsa->ls[0];
+	unsigned int ls_offset = 0x0;
+	unsigned int size = 16384;
+	unsigned int tag = 0;
+	unsigned int rclass = 0;
+	unsigned int cmd = MFC_PUT_CMD;
+
+	/* Save, Step 50:
+	 *     Issue a DMA command to copy the first 16K bytes
+	 *     of local storage to the CSA.
+	 */
+	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void set_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 51:
+	 * Restore, Step 31.
+	 *     Write SPU_NPC[IE]=0 and SPU_NPC[LSA] to entry
+	 *     point address of context save code in local
+	 *     storage.
+	 *
+	 *     This implementation uses SPU-side save/restore
+	 *     programs with entry points at LSA of 0.
+	 */
+	out_be32(&prob->spu_npc_RW, 0);
+	eieio();
+}
+
+static inline void set_signot1(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	union {
+		u64 ull;
+		u32 ui[2];
+	} addr64;
+
+	/* Save, Step 52:
+	 * Restore, Step 32:
+	 *    Write SPU_Sig_Notify_1 register with upper 32-bits
+	 *    of the CSA.LSCSA effective address.
+	 */
+	addr64.ull = (u64) csa->lscsa;
+	out_be32(&prob->signal_notify1, addr64.ui[0]);
+	eieio();
+}
+
+static inline void set_signot2(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	union {
+		u64 ull;
+		u32 ui[2];
+	} addr64;
+
+	/* Save, Step 53:
+	 * Restore, Step 33:
+	 *    Write SPU_Sig_Notify_2 register with lower 32-bits
+	 *    of the CSA.LSCSA effective address.
+	 */
+	addr64.ull = (u64) csa->lscsa;
+	out_be32(&prob->signal_notify2, addr64.ui[1]);
+	eieio();
+}
+
+static inline void send_save_code(struct spu_state *csa, struct spu *spu)
+{
+	unsigned long addr = (unsigned long)&spu_save_code[0];
+	unsigned int ls_offset = 0x0;
+	unsigned int size = sizeof(spu_save_code);
+	unsigned int tag = 0;
+	unsigned int rclass = 0;
+	unsigned int cmd = MFC_GETFS_CMD;
+
+	/* Save, Step 54:
+	 *     Issue a DMA command to copy context save code
+	 *     to local storage and start SPU.
+	 */
+	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void set_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Save, Step 55:
+	 * Restore, Step 38.
+	 *     Write PPU_QueryMask=1 (enable Tag Group 0)
+	 *     and issue eieio instruction.
+	 */
+	out_be32(&prob->dma_querymask_RW, MFC_TAGID_TO_TAGMASK(0));
+	eieio();
+}
+
+static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	u32 mask = MFC_TAGID_TO_TAGMASK(0);
+	unsigned long flags;
+
+	/* Save, Step 56:
+	 * Restore, Step 39.
+	 * Restore, Step 39.
+	 * Restore, Step 46.
+	 *     Poll PPU_TagStatus[gn] until 01 (Tag group 0 complete)
+	 *     or write PPU_QueryType[TS]=01 and wait for Tag Group
+	 *     Complete Interrupt.  Write INT_Stat_Class0 or
+	 *     INT_Stat_Class2 with value of 'handled'.
+	 */
+	POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask);
+
+	local_irq_save(flags);
+	spu_int_stat_clear(spu, 0, ~(0ul));
+	spu_int_stat_clear(spu, 2, ~(0ul));
+	local_irq_restore(flags);
+}
+
+static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	unsigned long flags;
+
+	/* Save, Step 57:
+	 * Restore, Step 40.
+	 *     Poll until SPU_Status[R]=0 or wait for SPU Class 0
+	 *     or SPU Class 2 interrupt.  Write INT_Stat_class0
+	 *     or INT_Stat_class2 with value of handled.
+	 */
+	POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
+
+	local_irq_save(flags);
+	spu_int_stat_clear(spu, 0, ~(0ul));
+	spu_int_stat_clear(spu, 2, ~(0ul));
+	local_irq_restore(flags);
+}
+
+static inline int check_save_status(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	u32 complete;
+
+	/* Save, Step 54:
+	 *     If SPU_Status[P]=1 and SPU_Status[SC] = "success",
+	 *     context save succeeded, otherwise context save
+	 *     failed.
+	 */
+	complete = ((SPU_SAVE_COMPLETE << SPU_STOP_STATUS_SHIFT) |
+		    SPU_STATUS_STOPPED_BY_STOP);
+	return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;
+}
+
+static inline void terminate_spu_app(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 4:
+	 *    If required, notify the "using application" that
+	 *    the SPU task has been terminated.  TBD.
+	 */
+}
+
+static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 7:
+	 * Restore, Step 47.
+	 *     Write MFC_Cntl[Dh,Sc]='1','1' to suspend
+	 *     the queue and halt the decrementer.
+	 */
+	out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE |
+		 MFC_CNTL_DECREMENTER_HALTED);
+	eieio();
+}
+
+static inline void wait_suspend_mfc_complete(struct spu_state *csa,
+					     struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 8:
+	 * Restore, Step 47.
+	 *     Poll MFC_CNTL[Ss] until 11 is returned.
+	 */
+	POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) &
+			 MFC_CNTL_SUSPEND_COMPLETE);
+}
+
+static inline int suspend_spe(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Restore, Step 9:
+	 *    If SPU_Status[R]=1, stop SPU execution
+	 *    and wait for stop to complete.
+	 *
+	 *    Returns       1 if SPU_Status[R]=1 on entry.
+	 *                  0 otherwise
+	 */
+	if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) {
+		if (in_be32(&prob->spu_status_R) &
+		    SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+					SPU_STATUS_RUNNING);
+		}
+		if ((in_be32(&prob->spu_status_R) &
+		     SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+		    || (in_be32(&prob->spu_status_R) &
+			SPU_STATUS_ISOLATED_STATE)) {
+			out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+			eieio();
+			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+					SPU_STATUS_RUNNING);
+			out_be32(&prob->spu_runcntl_RW, 0x2);
+			eieio();
+			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+					SPU_STATUS_RUNNING);
+		}
+		if (in_be32(&prob->spu_status_R) &
+		    SPU_STATUS_WAITING_FOR_CHANNEL) {
+			out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+			eieio();
+			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+					SPU_STATUS_RUNNING);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Restore, Step 10:
+	 *    If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1,
+	 *    release SPU from isolate state.
+	 */
+	if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) {
+		if (in_be32(&prob->spu_status_R) &
+		    SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+			spu_mfc_sr1_set(spu,
+					MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+			eieio();
+			out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+			eieio();
+			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+					SPU_STATUS_RUNNING);
+		}
+		if ((in_be32(&prob->spu_status_R) &
+		     SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+		    || (in_be32(&prob->spu_status_R) &
+			SPU_STATUS_ISOLATED_STATE)) {
+			spu_mfc_sr1_set(spu,
+					MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+			eieio();
+			out_be32(&prob->spu_runcntl_RW, 0x2);
+			eieio();
+			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+					SPU_STATUS_RUNNING);
+		}
+	}
+}
+
+static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+	u64 idx;
+	int i;
+
+	/* Restore, Step 20:
+	 *     Reset the following CH: [0,1,3,4,24,25,27]
+	 */
+	for (i = 0; i < 7; i++) {
+		idx = ch_indices[i];
+		out_be64(&priv2->spu_chnlcntptr_RW, idx);
+		eieio();
+		out_be64(&priv2->spu_chnldata_RW, 0UL);
+		out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+		eieio();
+	}
+}
+
+static inline void reset_ch_part2(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 ch_indices[5] = { 21UL, 23UL, 28UL, 29UL, 30UL };
+	u64 ch_counts[5] = { 16UL, 1UL, 1UL, 0UL, 1UL };
+	u64 idx;
+	int i;
+
+	/* Restore, Step 21:
+	 *     Reset the following CH: [21, 23, 28, 29, 30]
+	 */
+	for (i = 0; i < 5; i++) {
+		idx = ch_indices[i];
+		out_be64(&priv2->spu_chnlcntptr_RW, idx);
+		eieio();
+		out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+		eieio();
+	}
+}
+
+static inline void setup_spu_status_part1(struct spu_state *csa,
+					  struct spu *spu)
+{
+	u32 status_P = SPU_STATUS_STOPPED_BY_STOP;
+	u32 status_I = SPU_STATUS_INVALID_INSTR;
+	u32 status_H = SPU_STATUS_STOPPED_BY_HALT;
+	u32 status_S = SPU_STATUS_SINGLE_STEP;
+	u32 status_S_I = SPU_STATUS_SINGLE_STEP | SPU_STATUS_INVALID_INSTR;
+	u32 status_S_P = SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_STOP;
+	u32 status_P_H = SPU_STATUS_STOPPED_BY_HALT |SPU_STATUS_STOPPED_BY_STOP;
+	u32 status_P_I = SPU_STATUS_STOPPED_BY_STOP |SPU_STATUS_INVALID_INSTR;
+	u32 status_code;
+
+	/* Restore, Step 27:
+	 *     If the CSA.SPU_Status[I,S,H,P]=1 then add the correct
+	 *     instruction sequence to the end of the SPU based restore
+	 *     code (after the "context restored" stop and signal) to
+	 *     restore the correct SPU status.
+	 *
+	 *     NOTE: Rather than modifying the SPU executable, we
+	 *     instead add a new 'stopped_status' field to the
+	 *     LSCSA.  The SPU-side restore reads this field and
+	 *     takes the appropriate action when exiting.
+	 */
+
+	status_code =
+	    (csa->prob.spu_status_R >> SPU_STOP_STATUS_SHIFT) & 0xFFFF;
+	if ((csa->prob.spu_status_R & status_P_I) == status_P_I) {
+
+		/* SPU_Status[P,I]=1 - Illegal Instruction followed
+		 * by Stop and Signal instruction, followed by 'br -4'.
+		 *
+		 */
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_I;
+		csa->lscsa->stopped_status.slot[1] = status_code;
+
+	} else if ((csa->prob.spu_status_R & status_P_H) == status_P_H) {
+
+		/* SPU_Status[P,H]=1 - Halt Conditional, followed
+		 * by Stop and Signal instruction, followed by
+		 * 'br -4'.
+		 */
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_H;
+		csa->lscsa->stopped_status.slot[1] = status_code;
+
+	} else if ((csa->prob.spu_status_R & status_S_P) == status_S_P) {
+
+		/* SPU_Status[S,P]=1 - Stop and Signal instruction
+		 * followed by 'br -4'.
+		 */
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_P;
+		csa->lscsa->stopped_status.slot[1] = status_code;
+
+	} else if ((csa->prob.spu_status_R & status_S_I) == status_S_I) {
+
+		/* SPU_Status[S,I]=1 - Illegal instruction followed
+		 * by 'br -4'.
+		 */
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_I;
+		csa->lscsa->stopped_status.slot[1] = status_code;
+
+	} else if ((csa->prob.spu_status_R & status_P) == status_P) {
+
+		/* SPU_Status[P]=1 - Stop and Signal instruction
+		 * followed by 'br -4'.
+		 */
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P;
+		csa->lscsa->stopped_status.slot[1] = status_code;
+
+	} else if ((csa->prob.spu_status_R & status_H) == status_H) {
+
+		/* SPU_Status[H]=1 - Halt Conditional, followed
+		 * by 'br -4'.
+		 */
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_H;
+
+	} else if ((csa->prob.spu_status_R & status_S) == status_S) {
+
+		/* SPU_Status[S]=1 - Two nop instructions.
+		 */
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S;
+
+	} else if ((csa->prob.spu_status_R & status_I) == status_I) {
+
+		/* SPU_Status[I]=1 - Illegal instruction followed
+		 * by 'br -4'.
+		 */
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_I;
+
+	}
+}
+
+static inline void setup_spu_status_part2(struct spu_state *csa,
+					  struct spu *spu)
+{
+	u32 mask;
+
+	/* Restore, Step 28:
+	 *     If the CSA.SPU_Status[I,S,H,P,R]=0 then
+	 *     add a 'br *' instruction to the end of
+	 *     the SPU based restore code.
+	 *
+	 *     NOTE: Rather than modifying the SPU executable, we
+	 *     instead add a new 'stopped_status' field to the
+	 *     LSCSA.  The SPU-side restore reads this field and
+	 *     takes the appropriate action when exiting.
+	 */
+	mask = SPU_STATUS_INVALID_INSTR |
+	    SPU_STATUS_SINGLE_STEP |
+	    SPU_STATUS_STOPPED_BY_HALT |
+	    SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING;
+	if (!(csa->prob.spu_status_R & mask)) {
+		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_R;
+	}
+}
+
+static inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 29:
+	 *     Restore RA_GROUP_ID register and the
+	 *     RA_ENABLE reigster from the CSA.
+	 */
+	spu_resource_allocation_groupID_set(spu,
+			csa->priv1.resource_allocation_groupID_RW);
+	spu_resource_allocation_enable_set(spu,
+			csa->priv1.resource_allocation_enable_RW);
+}
+
+static inline void send_restore_code(struct spu_state *csa, struct spu *spu)
+{
+	unsigned long addr = (unsigned long)&spu_restore_code[0];
+	unsigned int ls_offset = 0x0;
+	unsigned int size = sizeof(spu_restore_code);
+	unsigned int tag = 0;
+	unsigned int rclass = 0;
+	unsigned int cmd = MFC_GETFS_CMD;
+
+	/* Restore, Step 37:
+	 *     Issue MFC DMA command to copy context
+	 *     restore code to local storage.
+	 */
+	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void setup_decr(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 34:
+	 *     If CSA.MFC_CNTL[Ds]=1 (decrementer was
+	 *     running) then adjust decrementer, set
+	 *     decrementer running status in LSCSA,
+	 *     and set decrementer "wrapped" status
+	 *     in LSCSA.
+	 */
+	if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) {
+		cycles_t resume_time = get_cycles();
+		cycles_t delta_time = resume_time - csa->suspend_time;
+
+		csa->lscsa->decr.slot[0] = delta_time;
+	}
+}
+
+static inline void setup_ppu_mb(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 35:
+	 *     Copy the CSA.PU_MB data into the LSCSA.
+	 */
+	csa->lscsa->ppu_mb.slot[0] = csa->prob.pu_mb_R;
+}
+
+static inline void setup_ppuint_mb(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 36:
+	 *     Copy the CSA.PUINT_MB data into the LSCSA.
+	 */
+	csa->lscsa->ppuint_mb.slot[0] = csa->priv2.puint_mb_R;
+}
+
+static inline int check_restore_status(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	u32 complete;
+
+	/* Restore, Step 40:
+	 *     If SPU_Status[P]=1 and SPU_Status[SC] = "success",
+	 *     context restore succeeded, otherwise context restore
+	 *     failed.
+	 */
+	complete = ((SPU_RESTORE_COMPLETE << SPU_STOP_STATUS_SHIFT) |
+		    SPU_STATUS_STOPPED_BY_STOP);
+	return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;
+}
+
+static inline void restore_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 41:
+	 *     Restore SPU_PrivCntl from the CSA.
+	 */
+	out_be64(&priv2->spu_privcntl_RW, csa->priv2.spu_privcntl_RW);
+	eieio();
+}
+
+static inline void restore_status_part1(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	u32 mask;
+
+	/* Restore, Step 42:
+	 *     If any CSA.SPU_Status[I,S,H,P]=1, then
+	 *     restore the error or single step state.
+	 */
+	mask = SPU_STATUS_INVALID_INSTR |
+	    SPU_STATUS_SINGLE_STEP |
+	    SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
+	if (csa->prob.spu_status_R & mask) {
+		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+		eieio();
+		POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+				SPU_STATUS_RUNNING);
+	}
+}
+
+static inline void restore_status_part2(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	u32 mask;
+
+	/* Restore, Step 43:
+	 *     If all CSA.SPU_Status[I,S,H,P,R]=0 then write
+	 *     SPU_RunCntl[R0R1]='01', wait for SPU_Status[R]=1,
+	 *     then write '00' to SPU_RunCntl[R0R1] and wait
+	 *     for SPU_Status[R]=0.
+	 */
+	mask = SPU_STATUS_INVALID_INSTR |
+	    SPU_STATUS_SINGLE_STEP |
+	    SPU_STATUS_STOPPED_BY_HALT |
+	    SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING;
+	if (!(csa->prob.spu_status_R & mask)) {
+		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+		eieio();
+		POLL_WHILE_FALSE(in_be32(&prob->spu_status_R) &
+				 SPU_STATUS_RUNNING);
+		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+		eieio();
+		POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+				SPU_STATUS_RUNNING);
+	}
+}
+
+static inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu)
+{
+	unsigned long addr = (unsigned long)&csa->lscsa->ls[0];
+	unsigned int ls_offset = 0x0;
+	unsigned int size = 16384;
+	unsigned int tag = 0;
+	unsigned int rclass = 0;
+	unsigned int cmd = MFC_GET_CMD;
+
+	/* Restore, Step 44:
+	 *     Issue a DMA command to restore the first
+	 *     16kb of local storage from CSA.
+	 */
+	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 49:
+	 *     Write INT_MASK_class0 with value of 0.
+	 *     Write INT_MASK_class1 with value of 0.
+	 *     Write INT_MASK_class2 with value of 0.
+	 *     Write INT_STAT_class0 with value of -1.
+	 *     Write INT_STAT_class1 with value of -1.
+	 *     Write INT_STAT_class2 with value of -1.
+	 */
+	spin_lock_irq(&spu->register_lock);
+	spu_int_mask_set(spu, 0, 0ul);
+	spu_int_mask_set(spu, 1, 0ul);
+	spu_int_mask_set(spu, 2, 0ul);
+	spu_int_stat_clear(spu, 0, ~0ul);
+	spu_int_stat_clear(spu, 1, ~0ul);
+	spu_int_stat_clear(spu, 2, ~0ul);
+	spin_unlock_irq(&spu->register_lock);
+}
+
+static inline void restore_mfc_queues(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	int i;
+
+	/* Restore, Step 50:
+	 *     If MFC_Cntl[Se]!=0 then restore
+	 *     MFC command queues.
+	 */
+	if ((csa->priv2.mfc_control_RW & MFC_CNTL_DMA_QUEUES_EMPTY_MASK) == 0) {
+		for (i = 0; i < 8; i++) {
+			out_be64(&priv2->puq[i].mfc_cq_data0_RW,
+				 csa->priv2.puq[i].mfc_cq_data0_RW);
+			out_be64(&priv2->puq[i].mfc_cq_data1_RW,
+				 csa->priv2.puq[i].mfc_cq_data1_RW);
+			out_be64(&priv2->puq[i].mfc_cq_data2_RW,
+				 csa->priv2.puq[i].mfc_cq_data2_RW);
+			out_be64(&priv2->puq[i].mfc_cq_data3_RW,
+				 csa->priv2.puq[i].mfc_cq_data3_RW);
+		}
+		for (i = 0; i < 16; i++) {
+			out_be64(&priv2->spuq[i].mfc_cq_data0_RW,
+				 csa->priv2.spuq[i].mfc_cq_data0_RW);
+			out_be64(&priv2->spuq[i].mfc_cq_data1_RW,
+				 csa->priv2.spuq[i].mfc_cq_data1_RW);
+			out_be64(&priv2->spuq[i].mfc_cq_data2_RW,
+				 csa->priv2.spuq[i].mfc_cq_data2_RW);
+			out_be64(&priv2->spuq[i].mfc_cq_data3_RW,
+				 csa->priv2.spuq[i].mfc_cq_data3_RW);
+		}
+	}
+	eieio();
+}
+
+static inline void restore_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Restore, Step 51:
+	 *     Restore the PPU_QueryMask register from CSA.
+	 */
+	out_be32(&prob->dma_querymask_RW, csa->prob.dma_querymask_RW);
+	eieio();
+}
+
+static inline void restore_ppu_querytype(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Restore, Step 52:
+	 *     Restore the PPU_QueryType register from CSA.
+	 */
+	out_be32(&prob->dma_querytype_RW, csa->prob.dma_querytype_RW);
+	eieio();
+}
+
+static inline void restore_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 53:
+	 *     Restore the MFC_CSR_TSQ register from CSA.
+	 */
+	out_be64(&priv2->spu_tag_status_query_RW,
+		 csa->priv2.spu_tag_status_query_RW);
+	eieio();
+}
+
+static inline void restore_mfc_csr_cmd(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 54:
+	 *     Restore the MFC_CSR_CMD1 and MFC_CSR_CMD2
+	 *     registers from CSA.
+	 */
+	out_be64(&priv2->spu_cmd_buf1_RW, csa->priv2.spu_cmd_buf1_RW);
+	out_be64(&priv2->spu_cmd_buf2_RW, csa->priv2.spu_cmd_buf2_RW);
+	eieio();
+}
+
+static inline void restore_mfc_csr_ato(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 55:
+	 *     Restore the MFC_CSR_ATO register from CSA.
+	 */
+	out_be64(&priv2->spu_atomic_status_RW, csa->priv2.spu_atomic_status_RW);
+}
+
+static inline void restore_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 56:
+	 *     Restore the MFC_TCLASS_ID register from CSA.
+	 */
+	spu_mfc_tclass_id_set(spu, csa->priv1.mfc_tclass_id_RW);
+	eieio();
+}
+
+static inline void set_llr_event(struct spu_state *csa, struct spu *spu)
+{
+	u64 ch0_cnt, ch0_data;
+	u64 ch1_data;
+
+	/* Restore, Step 57:
+	 *    Set the Lock Line Reservation Lost Event by:
+	 *      1. OR CSA.SPU_Event_Status with bit 21 (Lr) set to 1.
+	 *      2. If CSA.SPU_Channel_0_Count=0 and
+	 *         CSA.SPU_Wr_Event_Mask[Lr]=1 and
+	 *         CSA.SPU_Event_Status[Lr]=0 then set
+	 *         CSA.SPU_Event_Status_Count=1.
+	 */
+	ch0_cnt = csa->spu_chnlcnt_RW[0];
+	ch0_data = csa->spu_chnldata_RW[0];
+	ch1_data = csa->spu_chnldata_RW[1];
+	csa->spu_chnldata_RW[0] |= MFC_LLR_LOST_EVENT;
+	if ((ch0_cnt == 0) && !(ch0_data & MFC_LLR_LOST_EVENT) &&
+	    (ch1_data & MFC_LLR_LOST_EVENT)) {
+		csa->spu_chnlcnt_RW[0] = 1;
+	}
+}
+
+static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 58:
+	 *     If the status of the CSA software decrementer
+	 *     "wrapped" flag is set, OR in a '1' to
+	 *     CSA.SPU_Event_Status[Tm].
+	 */
+	if (csa->lscsa->decr_status.slot[0] == 1) {
+		csa->spu_chnldata_RW[0] |= 0x20;
+	}
+	if ((csa->lscsa->decr_status.slot[0] == 1) &&
+	    (csa->spu_chnlcnt_RW[0] == 0 &&
+	     ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) &&
+	     ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) {
+		csa->spu_chnlcnt_RW[0] = 1;
+	}
+}
+
+static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 idx, ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+	int i;
+
+	/* Restore, Step 59:
+	 *     Restore the following CH: [0,1,3,4,24,25,27]
+	 */
+	for (i = 0; i < 7; i++) {
+		idx = ch_indices[i];
+		out_be64(&priv2->spu_chnlcntptr_RW, idx);
+		eieio();
+		out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[idx]);
+		out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[idx]);
+		eieio();
+	}
+}
+
+static inline void restore_ch_part2(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 ch_indices[3] = { 9UL, 21UL, 23UL };
+	u64 ch_counts[3] = { 1UL, 16UL, 1UL };
+	u64 idx;
+	int i;
+
+	/* Restore, Step 60:
+	 *     Restore the following CH: [9,21,23].
+	 */
+	ch_counts[0] = 1UL;
+	ch_counts[1] = csa->spu_chnlcnt_RW[21];
+	ch_counts[2] = 1UL;
+	for (i = 0; i < 3; i++) {
+		idx = ch_indices[i];
+		out_be64(&priv2->spu_chnlcntptr_RW, idx);
+		eieio();
+		out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+		eieio();
+	}
+}
+
+static inline void restore_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 61:
+	 *     Restore the SPU_LSLR register from CSA.
+	 */
+	out_be64(&priv2->spu_lslr_RW, csa->priv2.spu_lslr_RW);
+	eieio();
+}
+
+static inline void restore_spu_cfg(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 62:
+	 *     Restore the SPU_Cfg register from CSA.
+	 */
+	out_be64(&priv2->spu_cfg_RW, csa->priv2.spu_cfg_RW);
+	eieio();
+}
+
+static inline void restore_pm_trace(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 63:
+	 *     Restore PM_Trace_Tag_Wait_Mask from CSA.
+	 *     Not performed by this implementation.
+	 */
+}
+
+static inline void restore_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Restore, Step 64:
+	 *     Restore SPU_NPC from CSA.
+	 */
+	out_be32(&prob->spu_npc_RW, csa->prob.spu_npc_RW);
+	eieio();
+}
+
+static inline void restore_spu_mb(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	int i;
+
+	/* Restore, Step 65:
+	 *     Restore MFC_RdSPU_MB from CSA.
+	 */
+	out_be64(&priv2->spu_chnlcntptr_RW, 29UL);
+	eieio();
+	out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]);
+	for (i = 0; i < 4; i++) {
+		out_be64(&priv2->spu_chnldata_RW, csa->spu_mailbox_data[i]);
+	}
+	eieio();
+}
+
+static inline void check_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+	u32 dummy = 0;
+
+	/* Restore, Step 66:
+	 *     If CSA.MB_Stat[P]=0 (mailbox empty) then
+	 *     read from the PPU_MB register.
+	 */
+	if ((csa->prob.mb_stat_R & 0xFF) == 0) {
+		dummy = in_be32(&prob->pu_mb_R);
+		eieio();
+	}
+}
+
+static inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	u64 dummy = 0UL;
+
+	/* Restore, Step 66:
+	 *     If CSA.MB_Stat[I]=0 (mailbox empty) then
+	 *     read from the PPUINT_MB register.
+	 */
+	if ((csa->prob.mb_stat_R & 0xFF0000) == 0) {
+		dummy = in_be64(&priv2->puint_mb_R);
+		eieio();
+		spu_int_stat_clear(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
+		eieio();
+	}
+}
+
+static inline void restore_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+	int i;
+
+	/* Restore, Step 68:
+	 *     If MFC_SR1[R]='1', restore SLBs from CSA.
+	 */
+	if (csa->priv1.mfc_sr1_RW & MFC_STATE1_RELOCATE_MASK) {
+		for (i = 0; i < 8; i++) {
+			out_be64(&priv2->slb_index_W, i);
+			eieio();
+			out_be64(&priv2->slb_esid_RW, csa->slb_esid_RW[i]);
+			out_be64(&priv2->slb_vsid_RW, csa->slb_vsid_RW[i]);
+			eieio();
+		}
+		out_be64(&priv2->slb_index_W, csa->priv2.slb_index_W);
+		eieio();
+	}
+}
+
+static inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 69:
+	 *     Restore the MFC_SR1 register from CSA.
+	 */
+	spu_mfc_sr1_set(spu, csa->priv1.mfc_sr1_RW);
+	eieio();
+}
+
+static inline void restore_other_spu_access(struct spu_state *csa,
+					    struct spu *spu)
+{
+	/* Restore, Step 70:
+	 *     Restore other SPU mappings to this SPU. TBD.
+	 */
+}
+
+static inline void restore_spu_runcntl(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_problem __iomem *prob = spu->problem;
+
+	/* Restore, Step 71:
+	 *     If CSA.SPU_Status[R]=1 then write
+	 *     SPU_RunCntl[R0R1]='01'.
+	 */
+	if (csa->prob.spu_status_R & SPU_STATUS_RUNNING) {
+		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+		eieio();
+	}
+}
+
+static inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 72:
+	 *    Restore the MFC_CNTL register for the CSA.
+	 */
+	out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW);
+	eieio();
+}
+
+static inline void enable_user_access(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 73:
+	 *     Enable user-space access (if provided) to this
+	 *     SPU by mapping the virtual pages assigned to
+	 *     the SPU memory-mapped I/O (MMIO) for problem
+	 *     state. TBD.
+	 */
+}
+
+static inline void reset_switch_active(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 74:
+	 *     Reset the "context switch active" flag.
+	 */
+	clear_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
+	mb();
+}
+
+static inline void reenable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+	/* Restore, Step 75:
+	 *     Re-enable SPU interrupts.
+	 */
+	spin_lock_irq(&spu->register_lock);
+	spu_int_mask_set(spu, 0, csa->priv1.int_mask_class0_RW);
+	spu_int_mask_set(spu, 1, csa->priv1.int_mask_class1_RW);
+	spu_int_mask_set(spu, 2, csa->priv1.int_mask_class2_RW);
+	spin_unlock_irq(&spu->register_lock);
+}
+
+static int quiece_spu(struct spu_state *prev, struct spu *spu)
+{
+	/*
+	 * Combined steps 2-18 of SPU context save sequence, which
+	 * quiesce the SPU state (disable SPU execution, MFC command
+	 * queues, decrementer, SPU interrupts, etc.).
+	 *
+	 * Returns      0 on success.
+	 *              2 if failed step 2.
+	 *              6 if failed step 6.
+	 */
+
+	if (check_spu_isolate(prev, spu)) {	/* Step 2. */
+		return 2;
+	}
+	disable_interrupts(prev, spu);	        /* Step 3. */
+	set_watchdog_timer(prev, spu);	        /* Step 4. */
+	inhibit_user_access(prev, spu);	        /* Step 5. */
+	if (check_spu_isolate(prev, spu)) {	/* Step 6. */
+		return 6;
+	}
+	set_switch_pending(prev, spu);	        /* Step 7. */
+	save_mfc_cntl(prev, spu);		/* Step 8. */
+	save_spu_runcntl(prev, spu);	        /* Step 9. */
+	save_mfc_sr1(prev, spu);	        /* Step 10. */
+	save_spu_status(prev, spu);	        /* Step 11. */
+	save_mfc_decr(prev, spu);	        /* Step 12. */
+	halt_mfc_decr(prev, spu);	        /* Step 13. */
+	save_timebase(prev, spu);		/* Step 14. */
+	remove_other_spu_access(prev, spu);	/* Step 15. */
+	do_mfc_mssync(prev, spu);	        /* Step 16. */
+	issue_mfc_tlbie(prev, spu);	        /* Step 17. */
+	handle_pending_interrupts(prev, spu);	/* Step 18. */
+
+	return 0;
+}
+
+static void save_csa(struct spu_state *prev, struct spu *spu)
+{
+	/*
+	 * Combine steps 19-44 of SPU context save sequence, which
+	 * save regions of the privileged & problem state areas.
+	 */
+
+	save_mfc_queues(prev, spu);	/* Step 19. */
+	save_ppu_querymask(prev, spu);	/* Step 20. */
+	save_ppu_querytype(prev, spu);	/* Step 21. */
+	save_mfc_csr_tsq(prev, spu);	/* Step 22. */
+	save_mfc_csr_cmd(prev, spu);	/* Step 23. */
+	save_mfc_csr_ato(prev, spu);	/* Step 24. */
+	save_mfc_tclass_id(prev, spu);	/* Step 25. */
+	set_mfc_tclass_id(prev, spu);	/* Step 26. */
+	purge_mfc_queue(prev, spu);	/* Step 27. */
+	wait_purge_complete(prev, spu);	/* Step 28. */
+	save_mfc_slbs(prev, spu);	/* Step 29. */
+	setup_mfc_sr1(prev, spu);	/* Step 30. */
+	save_spu_npc(prev, spu);	/* Step 31. */
+	save_spu_privcntl(prev, spu);	/* Step 32. */
+	reset_spu_privcntl(prev, spu);	/* Step 33. */
+	save_spu_lslr(prev, spu);	/* Step 34. */
+	reset_spu_lslr(prev, spu);	/* Step 35. */
+	save_spu_cfg(prev, spu);	/* Step 36. */
+	save_pm_trace(prev, spu);	/* Step 37. */
+	save_mfc_rag(prev, spu);	/* Step 38. */
+	save_ppu_mb_stat(prev, spu);	/* Step 39. */
+	save_ppu_mb(prev, spu);	        /* Step 40. */
+	save_ppuint_mb(prev, spu);	/* Step 41. */
+	save_ch_part1(prev, spu);	/* Step 42. */
+	save_spu_mb(prev, spu);	        /* Step 43. */
+	save_mfc_cmd(prev, spu);	/* Step 44. */
+	reset_ch(prev, spu);	        /* Step 45. */
+}
+
+static void save_lscsa(struct spu_state *prev, struct spu *spu)
+{
+	/*
+	 * Perform steps 46-57 of SPU context save sequence,
+	 * which save regions of the local store and register
+	 * file.
+	 */
+
+	resume_mfc_queue(prev, spu);	/* Step 46. */
+	setup_mfc_slbs(prev, spu);	/* Step 47. */
+	set_switch_active(prev, spu);	/* Step 48. */
+	enable_interrupts(prev, spu);	/* Step 49. */
+	save_ls_16kb(prev, spu);	/* Step 50. */
+	set_spu_npc(prev, spu);	        /* Step 51. */
+	set_signot1(prev, spu);		/* Step 52. */
+	set_signot2(prev, spu);		/* Step 53. */
+	send_save_code(prev, spu);	/* Step 54. */
+	set_ppu_querymask(prev, spu);	/* Step 55. */
+	wait_tag_complete(prev, spu);	/* Step 56. */
+	wait_spu_stopped(prev, spu);	/* Step 57. */
+}
+
+static void harvest(struct spu_state *prev, struct spu *spu)
+{
+	/*
+	 * Perform steps 2-25 of SPU context restore sequence,
+	 * which resets an SPU either after a failed save, or
+	 * when using SPU for first time.
+	 */
+
+	disable_interrupts(prev, spu);	        /* Step 2.  */
+	inhibit_user_access(prev, spu);	        /* Step 3.  */
+	terminate_spu_app(prev, spu);	        /* Step 4.  */
+	set_switch_pending(prev, spu);	        /* Step 5.  */
+	remove_other_spu_access(prev, spu);	/* Step 6.  */
+	suspend_mfc(prev, spu);	                /* Step 7.  */
+	wait_suspend_mfc_complete(prev, spu);	/* Step 8.  */
+	if (!suspend_spe(prev, spu))	        /* Step 9.  */
+		clear_spu_status(prev, spu);	/* Step 10. */
+	do_mfc_mssync(prev, spu);	        /* Step 11. */
+	issue_mfc_tlbie(prev, spu);	        /* Step 12. */
+	handle_pending_interrupts(prev, spu);	/* Step 13. */
+	purge_mfc_queue(prev, spu);	        /* Step 14. */
+	wait_purge_complete(prev, spu);	        /* Step 15. */
+	reset_spu_privcntl(prev, spu);	        /* Step 16. */
+	reset_spu_lslr(prev, spu);              /* Step 17. */
+	setup_mfc_sr1(prev, spu);	        /* Step 18. */
+	invalidate_slbs(prev, spu);	        /* Step 19. */
+	reset_ch_part1(prev, spu);	        /* Step 20. */
+	reset_ch_part2(prev, spu);	        /* Step 21. */
+	enable_interrupts(prev, spu);	        /* Step 22. */
+	set_switch_active(prev, spu);	        /* Step 23. */
+	set_mfc_tclass_id(prev, spu);	        /* Step 24. */
+	resume_mfc_queue(prev, spu);	        /* Step 25. */
+}
+
+static void restore_lscsa(struct spu_state *next, struct spu *spu)
+{
+	/*
+	 * Perform steps 26-40 of SPU context restore sequence,
+	 * which restores regions of the local store and register
+	 * file.
+	 */
+
+	set_watchdog_timer(next, spu);	        /* Step 26. */
+	setup_spu_status_part1(next, spu);	/* Step 27. */
+	setup_spu_status_part2(next, spu);	/* Step 28. */
+	restore_mfc_rag(next, spu);	        /* Step 29. */
+	setup_mfc_slbs(next, spu);	        /* Step 30. */
+	set_spu_npc(next, spu);	                /* Step 31. */
+	set_signot1(next, spu);	                /* Step 32. */
+	set_signot2(next, spu);	                /* Step 33. */
+	setup_decr(next, spu);	                /* Step 34. */
+	setup_ppu_mb(next, spu);	        /* Step 35. */
+	setup_ppuint_mb(next, spu);	        /* Step 36. */
+	send_restore_code(next, spu);	        /* Step 37. */
+	set_ppu_querymask(next, spu);	        /* Step 38. */
+	wait_tag_complete(next, spu);	        /* Step 39. */
+	wait_spu_stopped(next, spu);	        /* Step 40. */
+}
+
+static void restore_csa(struct spu_state *next, struct spu *spu)
+{
+	/*
+	 * Combine steps 41-76 of SPU context restore sequence, which
+	 * restore regions of the privileged & problem state areas.
+	 */
+
+	restore_spu_privcntl(next, spu);	/* Step 41. */
+	restore_status_part1(next, spu);	/* Step 42. */
+	restore_status_part2(next, spu);	/* Step 43. */
+	restore_ls_16kb(next, spu);	        /* Step 44. */
+	wait_tag_complete(next, spu);	        /* Step 45. */
+	suspend_mfc(next, spu);	                /* Step 46. */
+	wait_suspend_mfc_complete(next, spu);	/* Step 47. */
+	issue_mfc_tlbie(next, spu);	        /* Step 48. */
+	clear_interrupts(next, spu);	        /* Step 49. */
+	restore_mfc_queues(next, spu);	        /* Step 50. */
+	restore_ppu_querymask(next, spu);	/* Step 51. */
+	restore_ppu_querytype(next, spu);	/* Step 52. */
+	restore_mfc_csr_tsq(next, spu);	        /* Step 53. */
+	restore_mfc_csr_cmd(next, spu);	        /* Step 54. */
+	restore_mfc_csr_ato(next, spu);	        /* Step 55. */
+	restore_mfc_tclass_id(next, spu);	/* Step 56. */
+	set_llr_event(next, spu);	        /* Step 57. */
+	restore_decr_wrapped(next, spu);	/* Step 58. */
+	restore_ch_part1(next, spu);	        /* Step 59. */
+	restore_ch_part2(next, spu);	        /* Step 60. */
+	restore_spu_lslr(next, spu);	        /* Step 61. */
+	restore_spu_cfg(next, spu);	        /* Step 62. */
+	restore_pm_trace(next, spu);	        /* Step 63. */
+	restore_spu_npc(next, spu);	        /* Step 64. */
+	restore_spu_mb(next, spu);	        /* Step 65. */
+	check_ppu_mb_stat(next, spu);	        /* Step 66. */
+	check_ppuint_mb_stat(next, spu);	/* Step 67. */
+	restore_mfc_slbs(next, spu);	        /* Step 68. */
+	restore_mfc_sr1(next, spu);	        /* Step 69. */
+	restore_other_spu_access(next, spu);	/* Step 70. */
+	restore_spu_runcntl(next, spu);	        /* Step 71. */
+	restore_mfc_cntl(next, spu);	        /* Step 72. */
+	enable_user_access(next, spu);	        /* Step 73. */
+	reset_switch_active(next, spu);	        /* Step 74. */
+	reenable_interrupts(next, spu);	        /* Step 75. */
+}
+
+static int __do_spu_save(struct spu_state *prev, struct spu *spu)
+{
+	int rc;
+
+	/*
+	 * SPU context save can be broken into three phases:
+	 *
+	 *     (a) quiesce [steps 2-16].
+	 *     (b) save of CSA, performed by PPE [steps 17-42]
+	 *     (c) save of LSCSA, mostly performed by SPU [steps 43-52].
+	 *
+	 * Returns      0 on success.
+	 *              2,6 if failed to quiece SPU
+	 *              53 if SPU-side of save failed.
+	 */
+
+	rc = quiece_spu(prev, spu);	        /* Steps 2-16. */
+	switch (rc) {
+	default:
+	case 2:
+	case 6:
+		harvest(prev, spu);
+		return rc;
+		break;
+	case 0:
+		break;
+	}
+	save_csa(prev, spu);	                /* Steps 17-43. */
+	save_lscsa(prev, spu);	                /* Steps 44-53. */
+	return check_save_status(prev, spu);	/* Step 54.     */
+}
+
+static int __do_spu_restore(struct spu_state *next, struct spu *spu)
+{
+	int rc;
+
+	/*
+	 * SPU context restore can be broken into three phases:
+	 *
+	 *    (a) harvest (or reset) SPU [steps 2-24].
+	 *    (b) restore LSCSA [steps 25-40], mostly performed by SPU.
+	 *    (c) restore CSA [steps 41-76], performed by PPE.
+	 *
+	 * The 'harvest' step is not performed here, but rather
+	 * as needed below.
+	 */
+
+	restore_lscsa(next, spu);	        /* Steps 24-39. */
+	rc = check_restore_status(next, spu);	/* Step 40.     */
+	switch (rc) {
+	default:
+		/* Failed. Return now. */
+		return rc;
+		break;
+	case 0:
+		/* Fall through to next step. */
+		break;
+	}
+	restore_csa(next, spu);
+
+	return 0;
+}
+
+/**
+ * spu_save - SPU context save, with locking.
+ * @prev: pointer to SPU context save area, to be saved.
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Acquire locks, perform the save operation then return.
+ */
+int spu_save(struct spu_state *prev, struct spu *spu)
+{
+	int rc;
+
+	acquire_spu_lock(spu);	        /* Step 1.     */
+	rc = __do_spu_save(prev, spu);	/* Steps 2-53. */
+	release_spu_lock(spu);
+	if (rc) {
+		panic("%s failed on SPU[%d], rc=%d.\n",
+		      __func__, spu->number, rc);
+	}
+	return rc;
+}
+
+/**
+ * spu_restore - SPU context restore, with harvest and locking.
+ * @new: pointer to SPU context save area, to be restored.
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Perform harvest + restore, as we may not be coming
+ * from a previous succesful save operation, and the
+ * hardware state is unknown.
+ */
+int spu_restore(struct spu_state *new, struct spu *spu)
+{
+	int rc;
+
+	acquire_spu_lock(spu);
+	harvest(NULL, spu);
+	spu->stop_code = 0;
+	spu->dar = 0;
+	spu->dsisr = 0;
+	spu->slb_replace = 0;
+	spu->class_0_pending = 0;
+	rc = __do_spu_restore(new, spu);
+	release_spu_lock(spu);
+	if (rc) {
+		panic("%s failed on SPU[%d] rc=%d.\n",
+		       __func__, spu->number, rc);
+	}
+	return rc;
+}
+
+/**
+ * spu_harvest - SPU harvest (reset) operation
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Perform SPU harvest (reset) operation.
+ */
+void spu_harvest(struct spu *spu)
+{
+	acquire_spu_lock(spu);
+	harvest(NULL, spu);
+	release_spu_lock(spu);
+}
+
+static void init_prob(struct spu_state *csa)
+{
+	csa->spu_chnlcnt_RW[9] = 1;
+	csa->spu_chnlcnt_RW[21] = 16;
+	csa->spu_chnlcnt_RW[23] = 1;
+	csa->spu_chnlcnt_RW[28] = 1;
+	csa->spu_chnlcnt_RW[30] = 1;
+	csa->prob.spu_runcntl_RW = SPU_RUNCNTL_STOP;
+}
+
+static void init_priv1(struct spu_state *csa)
+{
+	/* Enable decode, relocate, tlbie response, master runcntl. */
+	csa->priv1.mfc_sr1_RW = MFC_STATE1_LOCAL_STORAGE_DECODE_MASK |
+	    MFC_STATE1_MASTER_RUN_CONTROL_MASK |
+	    MFC_STATE1_PROBLEM_STATE_MASK |
+	    MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK;
+
+	/* Set storage description.  */
+	csa->priv1.mfc_sdr_RW = mfspr(SPRN_SDR1);
+
+	/* Enable OS-specific set of interrupts. */
+	csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR |
+	    CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR |
+	    CLASS0_ENABLE_SPU_ERROR_INTR;
+	csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
+	    CLASS1_ENABLE_STORAGE_FAULT_INTR;
+	csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR |
+	    CLASS2_ENABLE_SPU_HALT_INTR;
+}
+
+static void init_priv2(struct spu_state *csa)
+{
+	csa->priv2.spu_lslr_RW = LS_ADDR_MASK;
+	csa->priv2.mfc_control_RW = MFC_CNTL_RESUME_DMA_QUEUE |
+	    MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION |
+	    MFC_CNTL_DMA_QUEUES_EMPTY_MASK;
+}
+
+/**
+ * spu_alloc_csa - allocate and initialize an SPU context save area.
+ *
+ * Allocate and initialize the contents of an SPU context save area.
+ * This includes enabling address translation, interrupt masks, etc.,
+ * as appropriate for the given OS environment.
+ *
+ * Note that storage for the 'lscsa' is allocated separately,
+ * as it is by far the largest of the context save regions,
+ * and may need to be pinned or otherwise specially aligned.
+ */
+void spu_init_csa(struct spu_state *csa)
+{
+	struct spu_lscsa *lscsa;
+	unsigned char *p;
+
+	if (!csa)
+		return;
+	memset(csa, 0, sizeof(struct spu_state));
+
+	lscsa = vmalloc(sizeof(struct spu_lscsa));
+	if (!lscsa)
+		return;
+
+	memset(lscsa, 0, sizeof(struct spu_lscsa));
+	csa->lscsa = lscsa;
+	csa->register_lock = SPIN_LOCK_UNLOCKED;
+
+	/* Set LS pages reserved to allow for user-space mapping. */
+	for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		SetPageReserved(vmalloc_to_page(p));
+
+	init_prob(csa);
+	init_priv1(csa);
+	init_priv2(csa);
+}
+
+void spu_fini_csa(struct spu_state *csa)
+{
+	/* Clear reserved bit before vfree. */
+	unsigned char *p;
+	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		ClearPageReserved(vmalloc_to_page(p));
+
+	vfree(csa->lscsa);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
new file mode 100644
index 0000000..d549aa7
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -0,0 +1,101 @@
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+/**
+ * sys_spu_run - run code loaded into an SPU
+ *
+ * @unpc:    next program counter for the SPU
+ * @ustatus: status of the SPU
+ *
+ * This system call transfers the control of execution of a
+ * user space thread to an SPU. It will return when the
+ * SPU has finished executing or when it hits an error
+ * condition and it will be interrupted if a signal needs
+ * to be delivered to a handler in user space.
+ *
+ * The next program counter is set to the passed value
+ * before the SPU starts fetching code and the user space
+ * pointer gets updated with the new value when returning
+ * from kernel space.
+ *
+ * The status value returned from spu_run reflects the
+ * value of the spu_status register after the SPU has stopped.
+ *
+ */
+long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus)
+{
+	long ret;
+	struct spufs_inode_info *i;
+	u32 npc, status;
+
+	ret = -EFAULT;
+	if (get_user(npc, unpc) || get_user(status, ustatus))
+		goto out;
+
+	/* check if this file was created by spu_create */
+	ret = -EINVAL;
+	if (filp->f_op != &spufs_context_fops)
+		goto out;
+
+	i = SPUFS_I(filp->f_dentry->d_inode);
+	ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
+
+	if (put_user(npc, unpc) || put_user(status, ustatus))
+		ret = -EFAULT;
+out:
+	return ret;
+}
+
+#ifndef MODULE
+asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
+{
+	int fput_needed;
+	struct file *filp;
+	long ret;
+
+	ret = -EBADF;
+	filp = fget_light(fd, &fput_needed);
+	if (filp) {
+		ret = do_spu_run(filp, unpc, ustatus);
+		fput_light(filp, fput_needed);
+	}
+
+	return ret;
+}
+#endif
+
+asmlinkage long sys_spu_create(const char __user *pathname,
+					unsigned int flags, mode_t mode)
+{
+	char *tmp;
+	int ret;
+
+	tmp = getname(pathname);
+	ret = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		struct nameidata nd;
+
+		ret = path_lookup(tmp, LOOKUP_PARENT|
+				LOOKUP_OPEN|LOOKUP_CREATE, &nd);
+		if (!ret) {
+			ret = spufs_create_thread(&nd, flags, mode);
+			path_release(&nd);
+		}
+		putname(tmp);
+	}
+
+	return ret;
+}
+
+struct spufs_calls spufs_calls = {
+	.create_thread = sys_spu_create,
+	.spu_run = do_spu_run,
+	.owner = THIS_MODULE,
+};
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index dda5f2c..4ec8ba7 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -49,7 +49,6 @@
 #include <asm/hydra.h>
 #include <asm/sections.h>
 #include <asm/time.h>
-#include <asm/btext.h>
 #include <asm/i8259.h>
 #include <asm/mpic.h>
 #include <asm/rtas.h>
@@ -58,7 +57,6 @@
 #include "chrp.h"
 
 void rtas_indicator_progress(char *, unsigned short);
-void btext_progress(char *, unsigned short);
 
 int _chrp_type;
 EXPORT_SYMBOL(_chrp_type);
@@ -264,11 +262,6 @@
 		ppc_md.set_rtc_time	= rtas_set_rtc_time;
 	}
 
-#ifdef CONFIG_BOOTX_TEXT
-	if (ppc_md.progress == NULL && boot_text_mapped)
-		ppc_md.progress = btext_progress;
-#endif
-
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* this is fine for chrp */
 	initrd_below_start_ok = 1;
@@ -522,12 +515,3 @@
 	smp_ops = &chrp_smp_ops;
 #endif /* CONFIG_SMP */
 }
-
-#ifdef CONFIG_BOOTX_TEXT
-void
-btext_progress(char *s, unsigned short hex)
-{
-	btext_drawstring(s);
-	btext_drawstring("\n");
-}
-#endif /* CONFIG_BOOTX_TEXT */
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index a58daa1..42e978e 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -35,161 +35,138 @@
 #include <linux/irq.h>
 #include <linux/spinlock.h>
 
+#include <asm/paca.h>
 #include <asm/iseries/hv_types.h>
 #include <asm/iseries/hv_lp_event.h>
 #include <asm/iseries/hv_call_xm.h>
+#include <asm/iseries/it_lp_queue.h>
 
 #include "irq.h"
 #include "call_pci.h"
 
-static long Pci_Interrupt_Count;
-static long Pci_Event_Count;
+#if defined(CONFIG_SMP)
+extern void iSeries_smp_message_recv(struct pt_regs *);
+#endif
 
-enum XmPciLpEvent_Subtype {
-	XmPciLpEvent_BusCreated		= 0,	// PHB has been created
-	XmPciLpEvent_BusError		= 1,	// PHB has failed
-	XmPciLpEvent_BusFailed		= 2,	// Msg to Secondary, Primary failed bus
-	XmPciLpEvent_NodeFailed		= 4,	// Multi-adapter bridge has failed
-	XmPciLpEvent_NodeRecovered	= 5,	// Multi-adapter bridge has recovered
-	XmPciLpEvent_BusRecovered	= 12,	// PHB has been recovered
-	XmPciLpEvent_UnQuiesceBus	= 18,	// Secondary bus unqiescing
-	XmPciLpEvent_BridgeError	= 21,	// Bridge Error
-	XmPciLpEvent_SlotInterrupt	= 22	// Slot interrupt
+enum pci_event_type {
+	pe_bus_created		= 0,	/* PHB has been created */
+	pe_bus_error		= 1,	/* PHB has failed */
+	pe_bus_failed		= 2,	/* Msg to Secondary, Primary failed bus */
+	pe_node_failed		= 4,	/* Multi-adapter bridge has failed */
+	pe_node_recovered	= 5,	/* Multi-adapter bridge has recovered */
+	pe_bus_recovered	= 12,	/* PHB has been recovered */
+	pe_unquiese_bus		= 18,	/* Secondary bus unqiescing */
+	pe_bridge_error		= 21,	/* Bridge Error */
+	pe_slot_interrupt	= 22	/* Slot interrupt */
 };
 
-struct XmPciLpEvent_BusInterrupt {
-	HvBusNumber	busNumber;
-	HvSubBusNumber	subBusNumber;
-};
-
-struct XmPciLpEvent_NodeInterrupt {
-	HvBusNumber	busNumber;
-	HvSubBusNumber	subBusNumber;
-	HvAgentId	deviceId;
-};
-
-struct XmPciLpEvent {
-	struct HvLpEvent hvLpEvent;
-
+struct pci_event {
+	struct HvLpEvent event;
 	union {
-		u64 alignData;			// Align on an 8-byte boundary
-
+		u64 __align;		/* Align on an 8-byte boundary */
 		struct {
 			u32		fisr;
-			HvBusNumber	busNumber;
-			HvSubBusNumber	subBusNumber;
-			HvAgentId	deviceId;
-		} slotInterrupt;
-
-		struct XmPciLpEvent_BusInterrupt busFailed;
-		struct XmPciLpEvent_BusInterrupt busRecovered;
-		struct XmPciLpEvent_BusInterrupt busCreated;
-
-		struct XmPciLpEvent_NodeInterrupt nodeFailed;
-		struct XmPciLpEvent_NodeInterrupt nodeRecovered;
-
-	} eventData;
-
+			HvBusNumber	bus_number;
+			HvSubBusNumber	sub_bus_number;
+			HvAgentId	dev_id;
+		} slot;
+		struct {
+			HvBusNumber	bus_number;
+			HvSubBusNumber	sub_bus_number;
+		} bus;
+		struct {
+			HvBusNumber	bus_number;
+			HvSubBusNumber	sub_bus_number;
+			HvAgentId	dev_id;
+		} node;
+	} data;
 };
 
-static void intReceived(struct XmPciLpEvent *eventParm,
-		struct pt_regs *regsParm)
+static DEFINE_SPINLOCK(pending_irqs_lock);
+static int num_pending_irqs;
+static int pending_irqs[NR_IRQS];
+
+static void int_received(struct pci_event *event, struct pt_regs *regs)
 {
 	int irq;
-#ifdef CONFIG_IRQSTACKS
-	struct thread_info *curtp, *irqtp;
-#endif
 
-	++Pci_Interrupt_Count;
-
-	switch (eventParm->hvLpEvent.xSubtype) {
-	case XmPciLpEvent_SlotInterrupt:
-		irq = eventParm->hvLpEvent.xCorrelationToken;
-		/* Dispatch the interrupt handlers for this irq */
-#ifdef CONFIG_IRQSTACKS
-		/* Switch to the irq stack to handle this */
-		curtp = current_thread_info();
-		irqtp = hardirq_ctx[smp_processor_id()];
-		if (curtp != irqtp) {
-			irqtp->task = curtp->task;
-			irqtp->flags = 0;
-			call___do_IRQ(irq, regsParm, irqtp);
-			irqtp->task = NULL;
-			if (irqtp->flags)
-				set_bits(irqtp->flags, &curtp->flags);
-		} else
-#endif
-			__do_IRQ(irq, regsParm);
-		HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
-			eventParm->eventData.slotInterrupt.subBusNumber,
-			eventParm->eventData.slotInterrupt.deviceId);
+	switch (event->event.xSubtype) {
+	case pe_slot_interrupt:
+		irq = event->event.xCorrelationToken;
+		if (irq < NR_IRQS) {
+			spin_lock(&pending_irqs_lock);
+			pending_irqs[irq]++;
+			num_pending_irqs++;
+			spin_unlock(&pending_irqs_lock);
+		} else {
+			printk(KERN_WARNING "int_received: bad irq number %d\n",
+					irq);
+			HvCallPci_eoi(event->data.slot.bus_number,
+					event->data.slot.sub_bus_number,
+					event->data.slot.dev_id);
+		}
 		break;
 		/* Ignore error recovery events for now */
-	case XmPciLpEvent_BusCreated:
-		printk(KERN_INFO "intReceived: system bus %d created\n",
-			eventParm->eventData.busCreated.busNumber);
+	case pe_bus_created:
+		printk(KERN_INFO "int_received: system bus %d created\n",
+			event->data.bus.bus_number);
 		break;
-	case XmPciLpEvent_BusError:
-	case XmPciLpEvent_BusFailed:
-		printk(KERN_INFO "intReceived: system bus %d failed\n",
-			eventParm->eventData.busFailed.busNumber);
+	case pe_bus_error:
+	case pe_bus_failed:
+		printk(KERN_INFO "int_received: system bus %d failed\n",
+			event->data.bus.bus_number);
 		break;
-	case XmPciLpEvent_BusRecovered:
-	case XmPciLpEvent_UnQuiesceBus:
-		printk(KERN_INFO "intReceived: system bus %d recovered\n",
-			eventParm->eventData.busRecovered.busNumber);
+	case pe_bus_recovered:
+	case pe_unquiese_bus:
+		printk(KERN_INFO "int_received: system bus %d recovered\n",
+			event->data.bus.bus_number);
 		break;
-	case XmPciLpEvent_NodeFailed:
-	case XmPciLpEvent_BridgeError:
+	case pe_node_failed:
+	case pe_bridge_error:
 		printk(KERN_INFO
-			"intReceived: multi-adapter bridge %d/%d/%d failed\n",
-			eventParm->eventData.nodeFailed.busNumber,
-			eventParm->eventData.nodeFailed.subBusNumber,
-			eventParm->eventData.nodeFailed.deviceId);
+			"int_received: multi-adapter bridge %d/%d/%d failed\n",
+			event->data.node.bus_number,
+			event->data.node.sub_bus_number,
+			event->data.node.dev_id);
 		break;
-	case XmPciLpEvent_NodeRecovered:
+	case pe_node_recovered:
 		printk(KERN_INFO
-			"intReceived: multi-adapter bridge %d/%d/%d recovered\n",
-			eventParm->eventData.nodeRecovered.busNumber,
-			eventParm->eventData.nodeRecovered.subBusNumber,
-			eventParm->eventData.nodeRecovered.deviceId);
+			"int_received: multi-adapter bridge %d/%d/%d recovered\n",
+			event->data.node.bus_number,
+			event->data.node.sub_bus_number,
+			event->data.node.dev_id);
 		break;
 	default:
 		printk(KERN_ERR
-			"intReceived: unrecognized event subtype 0x%x\n",
-			eventParm->hvLpEvent.xSubtype);
+			"int_received: unrecognized event subtype 0x%x\n",
+			event->event.xSubtype);
 		break;
 	}
 }
 
-static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
-		struct pt_regs *regsParm)
+static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs)
 {
-#ifdef CONFIG_PCI
-	++Pci_Event_Count;
-
-	if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) {
-		switch (eventParm->xFlags.xFunction) {
+	if (event && (event->xType == HvLpEvent_Type_PciIo)) {
+		switch (event->xFlags.xFunction) {
 		case HvLpEvent_Function_Int:
-			intReceived((struct XmPciLpEvent *)eventParm, regsParm);
+			int_received((struct pci_event *)event, regs);
 			break;
 		case HvLpEvent_Function_Ack:
 			printk(KERN_ERR
-				"XmPciLpEvent_handler: unexpected ack received\n");
+				"pci_event_handler: unexpected ack received\n");
 			break;
 		default:
 			printk(KERN_ERR
-				"XmPciLpEvent_handler: unexpected event function %d\n",
-				(int)eventParm->xFlags.xFunction);
+				"pci_event_handler: unexpected event function %d\n",
+				(int)event->xFlags.xFunction);
 			break;
 		}
-	} else if (eventParm)
+	} else if (event)
 		printk(KERN_ERR
-			"XmPciLpEvent_handler: Unrecognized PCI event type 0x%x\n",
-			(int)eventParm->xType);
+			"pci_event_handler: Unrecognized PCI event type 0x%x\n",
+			(int)event->xType);
 	else
-		printk(KERN_ERR "XmPciLpEvent_handler: NULL event received\n");
-#endif
+		printk(KERN_ERR "pci_event_handler: NULL event received\n");
 }
 
 /*
@@ -199,20 +176,21 @@
 void __init iSeries_init_IRQ(void)
 {
 	/* Register PCI event handler and open an event path */
-	int xRc;
+	int ret;
 
-	xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
-			&XmPciLpEvent_handler);
-	if (xRc == 0) {
-		xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
-		if (xRc != 0)
-			printk(KERN_ERR "iSeries_init_IRQ: open event path "
-					"failed with rc 0x%x\n", xRc);
+	ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
+			&pci_event_handler);
+	if (ret == 0) {
+		ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
+		if (ret != 0)
+			printk(KERN_ERR "iseries_init_IRQ: open event path "
+					"failed with rc 0x%x\n", ret);
 	} else
-		printk(KERN_ERR "iSeries_init_IRQ: register handler "
-				"failed with rc 0x%x\n", xRc);
+		printk(KERN_ERR "iseries_init_IRQ: register handler "
+				"failed with rc 0x%x\n", ret);
 }
 
+#define REAL_IRQ_TO_SUBBUS(irq)	(((irq) >> 14) & 0xff)
 #define REAL_IRQ_TO_BUS(irq)	((((irq) >> 6) & 0xff) + 1)
 #define REAL_IRQ_TO_IDSEL(irq)	((((irq) >> 3) & 7) + 1)
 #define REAL_IRQ_TO_FUNC(irq)	((irq) & 7)
@@ -221,40 +199,40 @@
  * This will be called by device drivers (via enable_IRQ)
  * to enable INTA in the bridge interrupt status register.
  */
-static void iSeries_enable_IRQ(unsigned int irq)
+static void iseries_enable_IRQ(unsigned int irq)
 {
-	u32 bus, deviceId, function, mask;
-	const u32 subBus = 0;
+	u32 bus, dev_id, function, mask;
+	const u32 sub_bus = 0;
 	unsigned int rirq = virt_irq_to_real_map[irq];
 
 	/* The IRQ has already been locked by the caller */
 	bus = REAL_IRQ_TO_BUS(rirq);
 	function = REAL_IRQ_TO_FUNC(rirq);
-	deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
 
 	/* Unmask secondary INTA */
 	mask = 0x80000000;
-	HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
+	HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask);
 }
 
-/* This is called by iSeries_activate_IRQs */
-static unsigned int iSeries_startup_IRQ(unsigned int irq)
+/* This is called by iseries_activate_IRQs */
+static unsigned int iseries_startup_IRQ(unsigned int irq)
 {
-	u32 bus, deviceId, function, mask;
-	const u32 subBus = 0;
+	u32 bus, dev_id, function, mask;
+	const u32 sub_bus = 0;
 	unsigned int rirq = virt_irq_to_real_map[irq];
 
 	bus = REAL_IRQ_TO_BUS(rirq);
 	function = REAL_IRQ_TO_FUNC(rirq);
-	deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
 
 	/* Link the IRQ number to the bridge */
-	HvCallXm_connectBusUnit(bus, subBus, deviceId, irq);
+	HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq);
 
 	/* Unmask bridge interrupts in the FISR */
 	mask = 0x01010000 << function;
-	HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
-	iSeries_enable_IRQ(irq);
+	HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
+	iseries_enable_IRQ(irq);
 	return 0;
 }
 
@@ -279,78 +257,115 @@
 }
 
 /*  this is not called anywhere currently */
-static void iSeries_shutdown_IRQ(unsigned int irq)
+static void iseries_shutdown_IRQ(unsigned int irq)
 {
-	u32 bus, deviceId, function, mask;
-	const u32 subBus = 0;
+	u32 bus, dev_id, function, mask;
+	const u32 sub_bus = 0;
 	unsigned int rirq = virt_irq_to_real_map[irq];
 
 	/* irq should be locked by the caller */
 	bus = REAL_IRQ_TO_BUS(rirq);
 	function = REAL_IRQ_TO_FUNC(rirq);
-	deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
 
 	/* Invalidate the IRQ number in the bridge */
-	HvCallXm_connectBusUnit(bus, subBus, deviceId, 0);
+	HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0);
 
 	/* Mask bridge interrupts in the FISR */
 	mask = 0x01010000 << function;
-	HvCallPci_maskFisr(bus, subBus, deviceId, mask);
+	HvCallPci_maskFisr(bus, sub_bus, dev_id, mask);
 }
 
 /*
  * This will be called by device drivers (via disable_IRQ)
  * to disable INTA in the bridge interrupt status register.
  */
-static void iSeries_disable_IRQ(unsigned int irq)
+static void iseries_disable_IRQ(unsigned int irq)
 {
-	u32 bus, deviceId, function, mask;
-	const u32 subBus = 0;
+	u32 bus, dev_id, function, mask;
+	const u32 sub_bus = 0;
 	unsigned int rirq = virt_irq_to_real_map[irq];
 
 	/* The IRQ has already been locked by the caller */
 	bus = REAL_IRQ_TO_BUS(rirq);
 	function = REAL_IRQ_TO_FUNC(rirq);
-	deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
 
 	/* Mask secondary INTA   */
 	mask = 0x80000000;
-	HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
+	HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
 }
 
-/*
- * This does nothing because there is not enough information
- * provided to do the EOI HvCall.  This is done by XmPciLpEvent.c
- */
-static void iSeries_end_IRQ(unsigned int irq)
+static void iseries_end_IRQ(unsigned int irq)
 {
+	unsigned int rirq = virt_irq_to_real_map[irq];
+
+	HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
+		(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
 }
 
 static hw_irq_controller iSeries_IRQ_handler = {
 	.typename = "iSeries irq controller",
-	.startup = iSeries_startup_IRQ,
-	.shutdown = iSeries_shutdown_IRQ,
-	.enable = iSeries_enable_IRQ,
-	.disable = iSeries_disable_IRQ,
-	.end = iSeries_end_IRQ
+	.startup = iseries_startup_IRQ,
+	.shutdown = iseries_shutdown_IRQ,
+	.enable = iseries_enable_IRQ,
+	.disable = iseries_disable_IRQ,
+	.end = iseries_end_IRQ
 };
 
 /*
  * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
  * It calculates the irq value for the slot.
- * Note that subBusNumber is always 0 (at the moment at least).
+ * Note that sub_bus is always 0 (at the moment at least).
  */
-int __init iSeries_allocate_IRQ(HvBusNumber busNumber,
-		HvSubBusNumber subBusNumber, HvAgentId deviceId)
+int __init iSeries_allocate_IRQ(HvBusNumber bus,
+		HvSubBusNumber sub_bus, HvAgentId dev_id)
 {
 	int virtirq;
 	unsigned int realirq;
-	u8 idsel = (deviceId >> 4);
-	u8 function = deviceId & 7;
+	u8 idsel = (dev_id >> 4);
+	u8 function = dev_id & 7;
 
-	realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function;
+	realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
+		+ function;
 	virtirq = virt_irq_create_mapping(realirq);
 
 	irq_desc[virtirq].handler = &iSeries_IRQ_handler;
 	return virtirq;
 }
+
+/*
+ * Get the next pending IRQ.
+ */
+int iSeries_get_irq(struct pt_regs *regs)
+{
+	struct paca_struct *lpaca;
+	/* -2 means ignore this interrupt */
+	int irq = -2;
+
+	lpaca = get_paca();
+#ifdef CONFIG_SMP
+	if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
+		lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
+		iSeries_smp_message_recv(regs);
+	}
+#endif /* CONFIG_SMP */
+	if (hvlpevent_is_pending())
+		process_hvlpevents(regs);
+
+	if (num_pending_irqs) {
+		spin_lock(&pending_irqs_lock);
+		for (irq = 0; irq < NR_IRQS; irq++) {
+			if (pending_irqs[irq]) {
+				pending_irqs[irq]--;
+				num_pending_irqs--;
+				break;
+			}
+		}
+		spin_unlock(&pending_irqs_lock);
+		if (irq >= NR_IRQS)
+			irq = -2;
+	}
+
+	return irq;
+}
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
index 5f643f1..b9c801b 100644
--- a/arch/powerpc/platforms/iseries/irq.h
+++ b/arch/powerpc/platforms/iseries/irq.h
@@ -4,5 +4,6 @@
 extern void iSeries_init_IRQ(void);
 extern int  iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
 extern void iSeries_activate_IRQs(void);
+extern int iSeries_get_irq(struct pt_regs *);
 
 #endif /* _ISERIES_IRQ_H */
diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c
index bb8c915..ea72385 100644
--- a/arch/powerpc/platforms/iseries/lpardata.c
+++ b/arch/powerpc/platforms/iseries/lpardata.c
@@ -225,3 +225,10 @@
 		0,0
 	}
 };
+
+struct ItLpRegSave iseries_reg_save[] = {
+	[0 ... (NR_CPUS-1)] = {
+		.xDesc = 0xd397d9e2,	/* "LpRS" */
+		.xSize = sizeof(struct ItLpRegSave),
+	},
+};
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index da26639..ad5ef805 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -571,16 +571,6 @@
 
 /*
  * Document me.
- * and Implement me.
- */
-static int iSeries_get_irq(struct pt_regs *regs)
-{
-	/* -2 means ignore this interrupt */
-	return -2;
-}
-
-/*
- * Document me.
  */
 static void iSeries_restart(char *cmd)
 {
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 7ece898..dd73e38 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -51,6 +51,7 @@
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/kexec.h>
 #include <asm/pci-bridge.h>
 #include <asm/iommu.h>
 #include <asm/machdep.h>
@@ -191,24 +192,10 @@
 	 */
 	hpte_init_native();
 
-	/* Find the serial port */
-	generic_find_legacy_serial_ports(&physport, &default_speed);
-
-	DBG("phys port addr: %lx\n", (long)physport);
-
-	if (physport) {
-		void *comport;
-		/* Map the uart for udbg. */
-		comport = (void *)ioremap(physport, 16);
-		udbg_init_uart(comport, default_speed);
-
-		DBG("Hello World !\n");
-	}
-
 	/* Setup interrupt mapping options */
 	ppc64_interrupt_controller = IC_OPEN_PIC;
 
-	iommu_init_early_u3();
+	iommu_init_early_dart();
 
 	DBG(" <- maple_init_early\n");
 }
@@ -270,7 +257,7 @@
 	 * occupies having to be broken up so the DART itself is not
 	 * part of the cacheable linar mapping
 	 */
-	alloc_u3_dart_table();
+	alloc_dart_table();
 
 	return 1;
 }
@@ -292,4 +279,9 @@
       	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= maple_progress,
 	.idle_loop		= native_idle,
+#ifdef CONFIG_KEXEC
+	.machine_kexec		= default_machine_kexec,
+	.machine_kexec_prepare	= default_machine_kexec_prepare,
+	.machine_crash_shutdown	= default_machine_crash_shutdown,
+#endif
 };
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile
index c9df44f..78093d7 100644
--- a/arch/powerpc/platforms/powermac/Makefile
+++ b/arch/powerpc/platforms/powermac/Makefile
@@ -1,9 +1,14 @@
+CFLAGS_bootx_init.o  		+= -fPIC
+
 obj-y				+= pic.o setup.o time.o feature.o pci.o \
-				   sleep.o low_i2c.o cache.o
+				   sleep.o low_i2c.o cache.o pfunc_core.o \
+				   pfunc_base.o
 obj-$(CONFIG_PMAC_BACKLIGHT)	+= backlight.o
 obj-$(CONFIG_CPU_FREQ_PMAC)	+= cpufreq_32.o
 obj-$(CONFIG_CPU_FREQ_PMAC64)	+= cpufreq_64.o
 obj-$(CONFIG_NVRAM)		+= nvram.o
 # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
 obj-$(CONFIG_PPC64)		+= nvram.o
+obj-$(CONFIG_PPC32)		+= bootx_init.o
 obj-$(CONFIG_SMP)		+= smp.o
+obj-$(CONFIG_PPC_MERGE)		+= udbg_scc.o udbg_adb.o
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
new file mode 100644
index 0000000..fa8b4d7
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -0,0 +1,547 @@
+/*
+ *  Early boot support code for BootX bootloader
+ *
+ *  Copyright (C) 2005 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/bootx.h>
+#include <asm/bootinfo.h>
+#include <asm/btext.h>
+#include <asm/io.h>
+
+#undef DEBUG
+#define SET_BOOT_BAT
+
+#ifdef DEBUG
+#define DBG(fmt...) do { bootx_printf(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
+
+static unsigned long __initdata bootx_dt_strbase;
+static unsigned long __initdata bootx_dt_strend;
+static unsigned long __initdata bootx_node_chosen;
+static boot_infos_t * __initdata bootx_info;
+static char __initdata bootx_disp_path[256];
+
+/* Is boot-info compatible ? */
+#define BOOT_INFO_IS_COMPATIBLE(bi) \
+	((bi)->compatible_version <= BOOT_INFO_VERSION)
+#define BOOT_INFO_IS_V2_COMPATIBLE(bi)	((bi)->version >= 2)
+#define BOOT_INFO_IS_V4_COMPATIBLE(bi)	((bi)->version >= 4)
+
+#ifdef CONFIG_BOOTX_TEXT
+static void __init bootx_printf(const char *format, ...)
+{
+	const char *p, *q, *s;
+	va_list args;
+	unsigned long v;
+
+	va_start(args, format);
+	for (p = format; *p != 0; p = q) {
+		for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)
+			;
+		if (q > p)
+			btext_drawtext(p, q - p);
+		if (*q == 0)
+			break;
+		if (*q == '\n') {
+			++q;
+			btext_flushline();
+			btext_drawstring("\r\n");
+			btext_flushline();
+			continue;
+		}
+		++q;
+		if (*q == 0)
+			break;
+		switch (*q) {
+		case 's':
+			++q;
+			s = va_arg(args, const char *);
+			if (s == NULL)
+				s = "<NULL>";
+			btext_drawstring(s);
+			break;
+		case 'x':
+			++q;
+			v = va_arg(args, unsigned long);
+			btext_drawhex(v);
+			break;
+		}
+	}
+}
+#else /* CONFIG_BOOTX_TEXT */
+static void __init bootx_printf(const char *format, ...) {}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static void * __init bootx_early_getprop(unsigned long base,
+					 unsigned long node,
+					 char *prop)
+{
+	struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+	u32 *ppp = &np->properties;
+
+	while(*ppp) {
+		struct bootx_dt_prop *pp =
+			(struct bootx_dt_prop *)(base + *ppp);
+
+		if (strcmp((char *)((unsigned long)pp->name + base),
+			   prop) == 0) {
+			return (void *)((unsigned long)pp->value + base);
+		}
+		ppp = &pp->next;
+	}
+	return NULL;
+}
+
+#define dt_push_token(token, mem) \
+	do { \
+		*(mem) = _ALIGN_UP(*(mem),4); \
+		*((u32 *)*(mem)) = token; \
+		*(mem) += 4; \
+	} while(0)
+
+static unsigned long __init bootx_dt_find_string(char *str)
+{
+	char *s, *os;
+
+	s = os = (char *)bootx_dt_strbase;
+	s += 4;
+	while (s <  (char *)bootx_dt_strend) {
+		if (strcmp(s, str) == 0)
+			return s - os;
+		s += strlen(s) + 1;
+	}
+	return 0;
+}
+
+static void __init bootx_dt_add_prop(char *name, void *data, int size,
+				  unsigned long *mem_end)
+{
+	unsigned long soff = bootx_dt_find_string(name);
+	if (data == NULL)
+		size = 0;
+	if (soff == 0) {
+		bootx_printf("WARNING: Can't find string index for <%s>\n",
+			     name);
+		return;
+	}
+	if (size > 0x20000) {
+		bootx_printf("WARNING: ignoring large property ");
+		bootx_printf("%s length 0x%x\n", name, size);
+		return;
+	}
+	dt_push_token(OF_DT_PROP, mem_end);
+	dt_push_token(size, mem_end);
+	dt_push_token(soff, mem_end);
+
+	/* push property content */
+	if (size && data) {
+		memcpy((void *)*mem_end, data, size);
+		*mem_end = _ALIGN_UP(*mem_end + size, 4);
+	}
+}
+
+static void __init bootx_add_chosen_props(unsigned long base,
+					  unsigned long *mem_end)
+{
+	u32 val = _MACH_Pmac;
+
+	bootx_dt_add_prop("linux,platform", &val, 4, mem_end);
+
+	if (bootx_info->kernelParamsOffset) {
+		char *args = (char *)((unsigned long)bootx_info) +
+			bootx_info->kernelParamsOffset;
+		bootx_dt_add_prop("bootargs", args, strlen(args) + 1, mem_end);
+	}
+	if (bootx_info->ramDisk) {
+		val = ((unsigned long)bootx_info) + bootx_info->ramDisk;
+		bootx_dt_add_prop("linux,initrd-start", &val, 4, mem_end);
+		val += bootx_info->ramDiskSize;
+		bootx_dt_add_prop("linux,initrd-end", &val, 4, mem_end);
+	}
+	if (strlen(bootx_disp_path))
+		bootx_dt_add_prop("linux,stdout-path", bootx_disp_path,
+				  strlen(bootx_disp_path) + 1, mem_end);
+}
+
+static void __init bootx_add_display_props(unsigned long base,
+					   unsigned long *mem_end)
+{
+	bootx_dt_add_prop("linux,boot-display", NULL, 0, mem_end);
+	bootx_dt_add_prop("linux,opened", NULL, 0, mem_end);
+}
+
+static void __init bootx_dt_add_string(char *s, unsigned long *mem_end)
+{
+	unsigned int l = strlen(s) + 1;
+	memcpy((void *)*mem_end, s, l);
+	bootx_dt_strend = *mem_end = *mem_end + l;
+}
+
+static void __init bootx_scan_dt_build_strings(unsigned long base,
+					       unsigned long node,
+					       unsigned long *mem_end)
+{
+	struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+	u32 *cpp, *ppp = &np->properties;
+	unsigned long soff;
+	char *namep;
+
+	/* Keep refs to known nodes */
+	namep = np->full_name ? (char *)(base + np->full_name) : NULL;
+       	if (namep == NULL) {
+		bootx_printf("Node without a full name !\n");
+		namep = "";
+	}
+	DBG("* strings: %s\n", namep);
+
+	if (!strcmp(namep, "/chosen")) {
+		DBG(" detected /chosen ! adding properties names !\n");
+		bootx_dt_add_string("linux,platform", mem_end);
+		bootx_dt_add_string("linux,stdout-path", mem_end);
+		bootx_dt_add_string("linux,initrd-start", mem_end);
+		bootx_dt_add_string("linux,initrd-end", mem_end);
+		bootx_dt_add_string("bootargs", mem_end);
+		bootx_node_chosen = node;
+	}
+	if (node == bootx_info->dispDeviceRegEntryOffset) {
+		DBG(" detected display ! adding properties names !\n");
+		bootx_dt_add_string("linux,boot-display", mem_end);
+		bootx_dt_add_string("linux,opened", mem_end);
+		strncpy(bootx_disp_path, namep, 255);
+	}
+
+	/* get and store all property names */
+	while (*ppp) {
+		struct bootx_dt_prop *pp =
+			(struct bootx_dt_prop *)(base + *ppp);
+
+		namep = pp->name ? (char *)(base + pp->name) : NULL;
+ 		if (namep == NULL || strcmp(namep, "name") == 0)
+ 			goto next;
+		/* get/create string entry */
+		soff = bootx_dt_find_string(namep);
+		if (soff == 0)
+			bootx_dt_add_string(namep, mem_end);
+	next:
+		ppp = &pp->next;
+	}
+
+	/* do all our children */
+	cpp = &np->child;
+	while(*cpp) {
+		np = (struct bootx_dt_node *)(base + *cpp);
+		bootx_scan_dt_build_strings(base, *cpp, mem_end);
+		cpp = &np->sibling;
+	}
+}
+
+static void __init bootx_scan_dt_build_struct(unsigned long base,
+					      unsigned long node,
+					      unsigned long *mem_end)
+{
+	struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+	u32 *cpp, *ppp = &np->properties;
+	char *namep, *p, *ep, *lp;
+	int l;
+
+	dt_push_token(OF_DT_BEGIN_NODE, mem_end);
+
+	/* get the node's full name */
+	namep = np->full_name ? (char *)(base + np->full_name) : NULL;
+	if (namep == NULL)
+		namep = "";
+	l = strlen(namep);
+
+	DBG("* struct: %s\n", namep);
+
+	/* Fixup an Apple bug where they have bogus \0 chars in the
+	 * middle of the path in some properties, and extract
+	 * the unit name (everything after the last '/').
+	 */
+	memcpy((void *)*mem_end, namep, l + 1);
+	namep = (char *)*mem_end;
+	for (lp = p = namep, ep = namep + l; p < ep; p++) {
+		if (*p == '/')
+			lp = namep;
+		else if (*p != 0)
+			*lp++ = *p;
+	}
+	*lp = 0;
+	*mem_end = _ALIGN_UP((unsigned long)lp + 1, 4);
+
+	/* get and store all properties */
+	while (*ppp) {
+		struct bootx_dt_prop *pp =
+			(struct bootx_dt_prop *)(base + *ppp);
+
+		namep = pp->name ? (char *)(base + pp->name) : NULL;
+		/* Skip "name" */
+ 		if (namep == NULL || !strcmp(namep, "name"))
+ 			goto next;
+		/* Skip "bootargs" in /chosen too as we replace it */
+		if (node == bootx_node_chosen && !strcmp(namep, "bootargs"))
+			goto next;
+
+		/* push property head */
+		bootx_dt_add_prop(namep,
+				  pp->value ? (void *)(base + pp->value): NULL,
+				  pp->length, mem_end);
+	next:
+		ppp = &pp->next;
+	}
+
+	if (node == bootx_node_chosen)
+		bootx_add_chosen_props(base, mem_end);
+	if (node == bootx_info->dispDeviceRegEntryOffset)
+		bootx_add_display_props(base, mem_end);
+
+	/* do all our children */
+	cpp = &np->child;
+	while(*cpp) {
+		np = (struct bootx_dt_node *)(base + *cpp);
+		bootx_scan_dt_build_struct(base, *cpp, mem_end);
+		cpp = &np->sibling;
+	}
+
+	dt_push_token(OF_DT_END_NODE, mem_end);
+}
+
+static unsigned long __init bootx_flatten_dt(unsigned long start)
+{
+	boot_infos_t *bi = bootx_info;
+	unsigned long mem_start, mem_end;
+	struct boot_param_header *hdr;
+	unsigned long base;
+	u64 *rsvmap;
+
+	/* Start using memory after the big blob passed by BootX, get
+	 * some space for the header
+	 */
+	mem_start = mem_end = _ALIGN_UP(((unsigned long)bi) + start, 4);
+	DBG("Boot params header at: %x\n", mem_start);
+	hdr = (struct boot_param_header *)mem_start;
+	mem_end += sizeof(struct boot_param_header);
+	rsvmap = (u64 *)(_ALIGN_UP(mem_end, 8));
+	hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - mem_start;
+	mem_end = ((unsigned long)rsvmap) + 8 * sizeof(u64);
+
+	/* Get base of tree */
+	base = ((unsigned long)bi) + bi->deviceTreeOffset;
+
+	/* Build string array */
+	DBG("Building string array at: %x\n", mem_end);
+	DBG("Device Tree Base=%x\n", base);
+	bootx_dt_strbase = mem_end;
+	mem_end += 4;
+	bootx_dt_strend = mem_end;
+	bootx_scan_dt_build_strings(base, 4, &mem_end);
+	hdr->off_dt_strings = bootx_dt_strbase - mem_start;
+	hdr->dt_strings_size = bootx_dt_strend - bootx_dt_strbase;
+
+	/* Build structure */
+	mem_end = _ALIGN(mem_end, 16);
+	DBG("Building device tree structure at: %x\n", mem_end);
+	hdr->off_dt_struct = mem_end - mem_start;
+	bootx_scan_dt_build_struct(base, 4, &mem_end);
+	dt_push_token(OF_DT_END, &mem_end);
+
+	/* Finish header */
+	hdr->boot_cpuid_phys = 0;
+	hdr->magic = OF_DT_HEADER;
+	hdr->totalsize = mem_end - mem_start;
+	hdr->version = OF_DT_VERSION;
+	/* Version 16 is not backward compatible */
+	hdr->last_comp_version = 0x10;
+
+	/* Reserve the whole thing and copy the reserve map in, we
+	 * also bump mem_reserve_cnt to cause further reservations to
+	 * fail since it's too late.
+	 */
+	mem_end = _ALIGN(mem_end, PAGE_SIZE);
+	DBG("End of boot params: %x\n", mem_end);
+	rsvmap[0] = mem_start;
+	rsvmap[1] = mem_end;
+	rsvmap[2] = 0;
+	rsvmap[3] = 0;
+
+	return (unsigned long)hdr;
+}
+
+
+#ifdef CONFIG_BOOTX_TEXT
+static void __init btext_welcome(boot_infos_t *bi)
+{
+	unsigned long flags;
+	unsigned long pvr;
+
+	bootx_printf("Welcome to Linux, kernel " UTS_RELEASE "\n");
+	bootx_printf("\nlinked at        : 0x%x", KERNELBASE);
+	bootx_printf("\nframe buffer at  : 0x%x", bi->dispDeviceBase);
+	bootx_printf(" (phys), 0x%x", bi->logicalDisplayBase);
+	bootx_printf(" (log)");
+	bootx_printf("\nklimit           : 0x%x",(unsigned long)klimit);
+	bootx_printf("\nboot_info at     : 0x%x", bi);
+	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+	bootx_printf("\nMSR              : 0x%x", flags);
+	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+	bootx_printf("\nPVR              : 0x%x", pvr);
+	pvr >>= 16;
+	if (pvr > 1) {
+	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+	    bootx_printf("\nHID0             : 0x%x", flags);
+	}
+	if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
+	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+	    bootx_printf("\nICTC             : 0x%x", flags);
+	}
+#ifdef DEBUG
+	bootx_printf("\n\n");
+	bootx_printf("bi->deviceTreeOffset   : 0x%x\n",
+		     bi->deviceTreeOffset);
+	bootx_printf("bi->deviceTreeSize     : 0x%x\n",
+		     bi->deviceTreeSize);
+#endif
+	bootx_printf("\n\n");
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+void __init bootx_init(unsigned long r3, unsigned long r4)
+{
+	boot_infos_t *bi = (boot_infos_t *) r4;
+	unsigned long hdr;
+	unsigned long space;
+	unsigned long ptr, x;
+	char *model;
+	unsigned long offset = reloc_offset();
+
+	reloc_got2(offset);
+
+	bootx_info = bi;
+
+	/* We haven't cleared any bss at this point, make sure
+	 * what we need is initialized
+	 */
+	bootx_dt_strbase = bootx_dt_strend = 0;
+	bootx_node_chosen = 0;
+	bootx_disp_path[0] = 0;
+
+	if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
+		bi->logicalDisplayBase = bi->dispDeviceBase;
+
+#ifdef CONFIG_BOOTX_TEXT
+	btext_setup_display(bi->dispDeviceRect[2] - bi->dispDeviceRect[0],
+			    bi->dispDeviceRect[3] - bi->dispDeviceRect[1],
+			    bi->dispDeviceDepth, bi->dispDeviceRowBytes,
+			    (unsigned long)bi->logicalDisplayBase);
+	btext_clearscreen();
+	btext_flushscreen();
+#endif /* CONFIG_BOOTX_TEXT */
+
+	/*
+	 * Test if boot-info is compatible.  Done only in config
+	 * CONFIG_BOOTX_TEXT since there is nothing much we can do
+	 * with an incompatible version, except display a message
+	 * and eventually hang the processor...
+	 *
+	 * I'll try to keep enough of boot-info compatible in the
+	 * future to always allow display of this message;
+	 */
+	if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
+		bootx_printf(" !!! WARNING - Incompatible version"
+			     " of BootX !!!\n\n\n");
+		for (;;)
+			;
+	}
+	if (bi->architecture != BOOT_ARCH_PCI) {
+		bootx_printf(" !!! WARNING - Usupported machine"
+			     " architecture !\n");
+		for (;;)
+			;
+	}
+
+#ifdef CONFIG_BOOTX_TEXT
+	btext_welcome(bi);
+#endif
+	/* New BootX enters kernel with MMU off, i/os are not allowed
+	 * here. This hack will have been done by the boostrap anyway.
+	 */
+	if (bi->version < 4) {
+		/*
+		 * XXX If this is an iMac, turn off the USB controller.
+		 */
+		model = (char *) bootx_early_getprop(r4 + bi->deviceTreeOffset,
+						     4, "model");
+		if (model
+		    && (strcmp(model, "iMac,1") == 0
+			|| strcmp(model, "PowerMac1,1") == 0)) {
+			bootx_printf("iMac,1 detected, shutting down USB \n");
+			out_le32((unsigned *)0x80880008, 1);	/* XXX */
+		}
+	}
+
+	/* Get a pointer that points above the device tree, args, ramdisk,
+	 * etc... to use for generating the flattened tree
+	 */
+	if (bi->version < 5) {
+		space = bi->deviceTreeOffset + bi->deviceTreeSize;
+		if (bi->ramDisk)
+			space = bi->ramDisk + bi->ramDiskSize;
+	} else
+		space = bi->totalParamsSize;
+
+	bootx_printf("Total space used by parameters & ramdisk: %x \n", space);
+
+	/* New BootX will have flushed all TLBs and enters kernel with
+	 * MMU switched OFF, so this should not be useful anymore.
+	 */
+	if (bi->version < 4) {
+		bootx_printf("Touching pages...\n");
+
+		/*
+		 * Touch each page to make sure the PTEs for them
+		 * are in the hash table - the aim is to try to avoid
+		 * getting DSI exceptions while copying the kernel image.
+		 */
+		for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
+		     ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
+			x = *(volatile unsigned long *)ptr;
+	}
+
+	/* Ok, now we need to generate a flattened device-tree to pass
+	 * to the kernel
+	 */
+	bootx_printf("Preparing boot params...\n");
+
+	hdr = bootx_flatten_dt(space);
+
+#ifdef CONFIG_BOOTX_TEXT
+#ifdef SET_BOOT_BAT
+	bootx_printf("Preparing BAT...\n");
+	btext_prepare_BAT();
+#else
+	btext_unmap();
+#endif
+#endif
+
+	reloc_got2(-offset);
+
+	__start(hdr, KERNELBASE + offset, 0);
+}
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 3915034..a4b50c4 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -28,6 +28,7 @@
 #include <asm/cputable.h>
 #include <asm/time.h>
 #include <asm/smu.h>
+#include <asm/pmac_pfunc.h>
 
 #undef DEBUG
 
@@ -85,6 +86,10 @@
 static int g5_pmode_max;
 static int g5_pmode_cur;
 
+static void (*g5_switch_volt)(int speed_mode);
+static int (*g5_switch_freq)(int speed_mode);
+static int (*g5_query_freq)(void);
+
 static DECLARE_MUTEX(g5_switch_mutex);
 
 
@@ -92,9 +97,11 @@
 static int g5_fvt_count;			/* number of op. points */
 static int g5_fvt_cur;				/* current op. point */
 
-/* ----------------- real hardware interface */
+/*
+ * SMU based voltage switching for Neo2 platforms
+ */
 
-static void g5_switch_volt(int speed_mode)
+static void g5_smu_switch_volt(int speed_mode)
 {
 	struct smu_simple_cmd	cmd;
 
@@ -105,26 +112,57 @@
 	wait_for_completion(&comp);
 }
 
-static int g5_switch_freq(int speed_mode)
+/*
+ * Platform function based voltage/vdnap switching for Neo2
+ */
+
+static struct pmf_function *pfunc_set_vdnap0;
+static struct pmf_function *pfunc_vdnap0_complete;
+
+static void g5_vdnap_switch_volt(int speed_mode)
 {
-	struct cpufreq_freqs freqs;
+	struct pmf_args args;
+	u32 slew, done = 0;
+	unsigned long timeout;
+
+	slew = (speed_mode == CPUFREQ_LOW) ? 1 : 0;
+	args.count = 1;
+	args.u[0].p = &slew;
+
+	pmf_call_one(pfunc_set_vdnap0, &args);
+
+	/* It's an irq GPIO so we should be able to just block here,
+	 * I'll do that later after I've properly tested the IRQ code for
+	 * platform functions
+	 */
+	timeout = jiffies + HZ/10;
+	while(!time_after(jiffies, timeout)) {
+		args.count = 1;
+		args.u[0].p = &done;
+		pmf_call_one(pfunc_vdnap0_complete, &args);
+		if (done)
+			break;
+		msleep(1);
+	}
+	if (done == 0)
+		printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
+}
+
+
+/*
+ * SCOM based frequency switching for 970FX rev3
+ */
+static int g5_scom_switch_freq(int speed_mode)
+{
+	unsigned long flags;
 	int to;
 
-	if (g5_pmode_cur == speed_mode)
-		return 0;
-
-	down(&g5_switch_mutex);
-
-	freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
-	freqs.new = g5_cpu_freqs[speed_mode].frequency;
-	freqs.cpu = 0;
-
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
 	/* If frequency is going up, first ramp up the voltage */
 	if (speed_mode < g5_pmode_cur)
 		g5_switch_volt(speed_mode);
 
+	local_irq_save(flags);
+
 	/* Clear PCR high */
 	scom970_write(SCOM_PCR, 0);
 	/* Clear PCR low */
@@ -147,6 +185,8 @@
 		udelay(100);
 	}
 
+	local_irq_restore(flags);
+
 	/* If frequency is going down, last ramp the voltage */
 	if (speed_mode > g5_pmode_cur)
 		g5_switch_volt(speed_mode);
@@ -154,14 +194,10 @@
 	g5_pmode_cur = speed_mode;
 	ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
 
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-	up(&g5_switch_mutex);
-
 	return 0;
 }
 
-static int g5_query_freq(void)
+static int g5_scom_query_freq(void)
 {
 	unsigned long psr = scom970_read(SCOM_PSR);
 	int i;
@@ -173,7 +209,104 @@
 	return i;
 }
 
-/* ----------------- cpufreq bookkeeping */
+/*
+ * Platform function based voltage switching for PowerMac7,2 & 7,3
+ */
+
+static struct pmf_function *pfunc_cpu0_volt_high;
+static struct pmf_function *pfunc_cpu0_volt_low;
+static struct pmf_function *pfunc_cpu1_volt_high;
+static struct pmf_function *pfunc_cpu1_volt_low;
+
+static void g5_pfunc_switch_volt(int speed_mode)
+{
+	if (speed_mode == CPUFREQ_HIGH) {
+		if (pfunc_cpu0_volt_high)
+			pmf_call_one(pfunc_cpu0_volt_high, NULL);
+		if (pfunc_cpu1_volt_high)
+			pmf_call_one(pfunc_cpu1_volt_high, NULL);
+	} else {
+		if (pfunc_cpu0_volt_low)
+			pmf_call_one(pfunc_cpu0_volt_low, NULL);
+		if (pfunc_cpu1_volt_low)
+			pmf_call_one(pfunc_cpu1_volt_low, NULL);
+	}
+	msleep(10); /* should be faster , to fix */
+}
+
+/*
+ * Platform function based frequency switching for PowerMac7,2 & 7,3
+ */
+
+static struct pmf_function *pfunc_cpu_setfreq_high;
+static struct pmf_function *pfunc_cpu_setfreq_low;
+static struct pmf_function *pfunc_cpu_getfreq;
+static struct pmf_function *pfunc_slewing_done;;
+
+static int g5_pfunc_switch_freq(int speed_mode)
+{
+	struct pmf_args args;
+	u32 done = 0;
+	unsigned long timeout;
+
+	/* If frequency is going up, first ramp up the voltage */
+	if (speed_mode < g5_pmode_cur)
+		g5_switch_volt(speed_mode);
+
+	/* Do it */
+	if (speed_mode == CPUFREQ_HIGH)
+		pmf_call_one(pfunc_cpu_setfreq_high, NULL);
+	else
+		pmf_call_one(pfunc_cpu_setfreq_low, NULL);
+
+	/* It's an irq GPIO so we should be able to just block here,
+	 * I'll do that later after I've properly tested the IRQ code for
+	 * platform functions
+	 */
+	timeout = jiffies + HZ/10;
+	while(!time_after(jiffies, timeout)) {
+		args.count = 1;
+		args.u[0].p = &done;
+		pmf_call_one(pfunc_slewing_done, &args);
+		if (done)
+			break;
+		msleep(1);
+	}
+	if (done == 0)
+		printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
+
+	/* If frequency is going down, last ramp the voltage */
+	if (speed_mode > g5_pmode_cur)
+		g5_switch_volt(speed_mode);
+
+	g5_pmode_cur = speed_mode;
+	ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
+
+	return 0;
+}
+
+static int g5_pfunc_query_freq(void)
+{
+	struct pmf_args args;
+	u32 val = 0;
+
+	args.count = 1;
+	args.u[0].p = &val;
+	pmf_call_one(pfunc_cpu_getfreq, &args);
+	return val ? CPUFREQ_HIGH : CPUFREQ_LOW;
+}
+
+/*
+ * Fake voltage switching for platforms with missing support
+ */
+
+static void g5_dummy_switch_volt(int speed_mode)
+{
+}
+
+/*
+ * Common interface to the cpufreq core
+ */
 
 static int g5_cpufreq_verify(struct cpufreq_policy *policy)
 {
@@ -183,13 +316,30 @@
 static int g5_cpufreq_target(struct cpufreq_policy *policy,
 	unsigned int target_freq, unsigned int relation)
 {
-	unsigned int    newstate = 0;
+	unsigned int newstate = 0;
+	struct cpufreq_freqs freqs;
+	int rc;
 
 	if (cpufreq_frequency_table_target(policy, g5_cpu_freqs,
 			target_freq, relation, &newstate))
 		return -EINVAL;
 
-	return g5_switch_freq(newstate);
+	if (g5_pmode_cur == newstate)
+		return 0;
+
+	down(&g5_switch_mutex);
+
+	freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
+	freqs.new = g5_cpu_freqs[newstate].frequency;
+	freqs.cpu = 0;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	rc = g5_switch_freq(newstate);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	up(&g5_switch_mutex);
+
+	return rc;
 }
 
 static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
@@ -205,6 +355,7 @@
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
+	policy->cpus = cpu_possible_map;
 	cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
 
 	return cpufreq_frequency_table_cpuinfo(policy,
@@ -224,19 +375,39 @@
 };
 
 
-static int __init g5_cpufreq_init(void)
+static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
 {
 	struct device_node *cpunode;
 	unsigned int psize, ssize;
-	struct smu_sdbp_header *shdr;
 	unsigned long max_freq;
-	u32 *valp;
+	char *freq_method, *volt_method;
+	u32 *valp, pvr_hi;
+	int use_volts_vdnap = 0;
+	int use_volts_smu = 0;
 	int rc = -ENODEV;
 
-	/* Look for CPU and SMU nodes */
-	cpunode = of_find_node_by_type(NULL, "cpu");
-	if (!cpunode) {
-		DBG("No CPU node !\n");
+	/* Check supported platforms */
+	if (machine_is_compatible("PowerMac8,1") ||
+	    machine_is_compatible("PowerMac8,2") ||
+	    machine_is_compatible("PowerMac9,1"))
+		use_volts_smu = 1;
+	else if (machine_is_compatible("PowerMac11,2"))
+		use_volts_vdnap = 1;
+	else
+		return -ENODEV;
+
+	/* Get first CPU node */
+	for (cpunode = NULL;
+	     (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
+		u32 *reg =
+			(u32 *)get_property(cpunode, "reg", NULL);
+		if (reg == NULL || (*reg) != 0)
+			continue;
+		if (!strcmp(cpunode->type, "cpu"))
+			break;
+	}
+	if (cpunode == NULL) {
+		printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
 		return -ENODEV;
 	}
 
@@ -246,8 +417,9 @@
 		DBG("No cpu-version property !\n");
 		goto bail_noprops;
 	}
-	if (((*valp) >> 16) != 0x3c) {
-		DBG("Wrong CPU version: %08x\n", *valp);
+	pvr_hi = (*valp) >> 16;
+	if (pvr_hi != 0x3c && pvr_hi != 0x44) {
+		printk(KERN_ERR "cpufreq: Unsupported CPU version\n");
 		goto bail_noprops;
 	}
 
@@ -259,18 +431,50 @@
 	}
 	g5_pmode_max = psize / sizeof(u32) - 1;
 
-	/* Look for the FVT table */
-	shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
-	if (!shdr)
-		goto bail_noprops;
-	g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
-	ssize = (shdr->len * sizeof(u32)) - sizeof(struct smu_sdbp_header);
-	g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
-	g5_fvt_cur = 0;
+	if (use_volts_smu) {
+		struct smu_sdbp_header *shdr;
 
-	/* Sanity checking */
-	if (g5_fvt_count < 1 || g5_pmode_max < 1)
-		goto bail_noprops;
+		/* Look for the FVT table */
+		shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+		if (!shdr)
+			goto bail_noprops;
+		g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
+		ssize = (shdr->len * sizeof(u32)) -
+			sizeof(struct smu_sdbp_header);
+		g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
+		g5_fvt_cur = 0;
+
+		/* Sanity checking */
+		if (g5_fvt_count < 1 || g5_pmode_max < 1)
+			goto bail_noprops;
+
+		g5_switch_volt = g5_smu_switch_volt;
+		volt_method = "SMU";
+	} else if (use_volts_vdnap) {
+		struct device_node *root;
+
+		root = of_find_node_by_path("/");
+		if (root == NULL) {
+			printk(KERN_ERR "cpufreq: Can't find root of "
+			       "device tree\n");
+			goto bail_noprops;
+		}
+		pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0");
+		pfunc_vdnap0_complete =
+			pmf_find_function(root, "slewing-done");
+		if (pfunc_set_vdnap0 == NULL ||
+		    pfunc_vdnap0_complete == NULL) {
+			printk(KERN_ERR "cpufreq: Can't find required "
+			       "platform function\n");
+			goto bail_noprops;
+		}
+
+		g5_switch_volt = g5_vdnap_switch_volt;
+		volt_method = "GPIO";
+	} else {
+		g5_switch_volt = g5_dummy_switch_volt;
+		volt_method = "none";
+	}
 
 	/*
 	 * From what I see, clock-frequency is always the maximal frequency.
@@ -286,19 +490,23 @@
 	g5_cpu_freqs[0].frequency = max_freq;
 	g5_cpu_freqs[1].frequency = max_freq/2;
 
-	/* Check current frequency */
-	g5_pmode_cur = g5_query_freq();
-	if (g5_pmode_cur > 1)
-		/* We don't support anything but 1:1 and 1:2, fixup ... */
-		g5_pmode_cur = 1;
+	/* Set callbacks */
+	g5_switch_freq = g5_scom_switch_freq;
+	g5_query_freq = g5_scom_query_freq;
+	freq_method = "SCOM";
 
 	/* Force apply current frequency to make sure everything is in
 	 * sync (voltage is right for example). Firmware may leave us with
 	 * a strange setting ...
 	 */
-	g5_switch_freq(g5_pmode_cur);
+	g5_switch_volt(CPUFREQ_HIGH);
+	msleep(10);
+	g5_pmode_cur = -1;
+	g5_switch_freq(g5_query_freq());
 
 	printk(KERN_INFO "Registering G5 CPU frequency driver\n");
+	printk(KERN_INFO "Frequency method: %s, Voltage method: %s\n",
+	       freq_method, volt_method);
 	printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
 		g5_cpu_freqs[1].frequency/1000,
 		g5_cpu_freqs[0].frequency/1000,
@@ -317,6 +525,200 @@
 	return rc;
 }
 
+static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
+{
+	struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
+	u8 *eeprom = NULL;
+	u32 *valp;
+	u64 max_freq, min_freq, ih, il;
+	int has_volt = 1, rc = 0;
+
+	/* Get first CPU node */
+	for (cpunode = NULL;
+	     (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
+		if (!strcmp(cpunode->type, "cpu"))
+			break;
+	}
+	if (cpunode == NULL) {
+		printk(KERN_ERR "cpufreq: Can't find any CPU node\n");
+		return -ENODEV;
+	}
+
+	/* Lookup the cpuid eeprom node */
+        cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
+	if (cpuid != NULL)
+		eeprom = (u8 *)get_property(cpuid, "cpuid", NULL);
+	if (eeprom == NULL) {
+		printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
+		rc = -ENODEV;
+		goto bail;
+	}
+
+	/* Lookup the i2c hwclock */
+	for (hwclock = NULL;
+	     (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
+		char *loc = get_property(hwclock, "hwctrl-location", NULL);
+		if (loc == NULL)
+			continue;
+		if (strcmp(loc, "CPU CLOCK"))
+			continue;
+		if (!get_property(hwclock, "platform-get-frequency", NULL))
+			continue;
+		break;
+	}
+	if (hwclock == NULL) {
+		printk(KERN_ERR "cpufreq: Can't find i2c clock chip !\n");
+		rc = -ENODEV;
+		goto bail;
+	}
+
+	DBG("cpufreq: i2c clock chip found: %s\n", hwclock->full_name);
+
+	/* Now get all the platform functions */
+	pfunc_cpu_getfreq =
+		pmf_find_function(hwclock, "get-frequency");
+	pfunc_cpu_setfreq_high =
+		pmf_find_function(hwclock, "set-frequency-high");
+	pfunc_cpu_setfreq_low =
+		pmf_find_function(hwclock, "set-frequency-low");
+	pfunc_slewing_done =
+		pmf_find_function(hwclock, "slewing-done");
+	pfunc_cpu0_volt_high =
+		pmf_find_function(hwclock, "set-voltage-high-0");
+	pfunc_cpu0_volt_low =
+		pmf_find_function(hwclock, "set-voltage-low-0");
+	pfunc_cpu1_volt_high =
+		pmf_find_function(hwclock, "set-voltage-high-1");
+	pfunc_cpu1_volt_low =
+		pmf_find_function(hwclock, "set-voltage-low-1");
+
+	/* Check we have minimum requirements */
+	if (pfunc_cpu_getfreq == NULL || pfunc_cpu_setfreq_high == NULL ||
+	    pfunc_cpu_setfreq_low == NULL || pfunc_slewing_done == NULL) {
+		printk(KERN_ERR "cpufreq: Can't find platform functions !\n");
+		rc = -ENODEV;
+		goto bail;
+	}
+
+	/* Check that we have complete sets */
+	if (pfunc_cpu0_volt_high == NULL || pfunc_cpu0_volt_low == NULL) {
+		pmf_put_function(pfunc_cpu0_volt_high);
+		pmf_put_function(pfunc_cpu0_volt_low);
+		pfunc_cpu0_volt_high = pfunc_cpu0_volt_low = NULL;
+		has_volt = 0;
+	}
+	if (!has_volt ||
+	    pfunc_cpu1_volt_high == NULL || pfunc_cpu1_volt_low == NULL) {
+		pmf_put_function(pfunc_cpu1_volt_high);
+		pmf_put_function(pfunc_cpu1_volt_low);
+		pfunc_cpu1_volt_high = pfunc_cpu1_volt_low = NULL;
+	}
+
+	/* Note: The device tree also contains a "platform-set-values"
+	 * function for which I haven't quite figured out the usage. It
+	 * might have to be called on init and/or wakeup, I'm not too sure
+	 * but things seem to work fine without it so far ...
+	 */
+
+	/* Get max frequency from device-tree */
+	valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
+	if (!valp) {
+		printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
+		rc = -ENODEV;
+		goto bail;
+	}
+
+	max_freq = (*valp)/1000;
+
+	/* Now calculate reduced frequency by using the cpuid input freq
+	 * ratio. This requires 64 bits math unless we are willing to lose
+	 * some precision
+	 */
+	ih = *((u32 *)(eeprom + 0x10));
+	il = *((u32 *)(eeprom + 0x20));
+	min_freq = 0;
+	if (ih != 0 && il != 0)
+		min_freq = (max_freq * il) / ih;
+
+	/* Sanity check */
+	if (min_freq >= max_freq || min_freq < 1000) {
+		printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n");
+		rc = -ENODEV;
+		goto bail;
+	}
+	g5_cpu_freqs[0].frequency = max_freq;
+	g5_cpu_freqs[1].frequency = min_freq;
+
+	/* Set callbacks */
+	g5_switch_volt = g5_pfunc_switch_volt;
+	g5_switch_freq = g5_pfunc_switch_freq;
+	g5_query_freq = g5_pfunc_query_freq;
+
+	/* Force apply current frequency to make sure everything is in
+	 * sync (voltage is right for example). Firmware may leave us with
+	 * a strange setting ...
+	 */
+	g5_switch_volt(CPUFREQ_HIGH);
+	msleep(10);
+	g5_pmode_cur = -1;
+	g5_switch_freq(g5_query_freq());
+
+	printk(KERN_INFO "Registering G5 CPU frequency driver\n");
+	printk(KERN_INFO "Frequency method: i2c/pfunc, "
+	       "Voltage method: %s\n", has_volt ? "i2c/pfunc" : "none");
+	printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
+		g5_cpu_freqs[1].frequency/1000,
+		g5_cpu_freqs[0].frequency/1000,
+		g5_cpu_freqs[g5_pmode_cur].frequency/1000);
+
+	rc = cpufreq_register_driver(&g5_cpufreq_driver);
+ bail:
+	if (rc != 0) {
+		pmf_put_function(pfunc_cpu_getfreq);
+		pmf_put_function(pfunc_cpu_setfreq_high);
+		pmf_put_function(pfunc_cpu_setfreq_low);
+		pmf_put_function(pfunc_slewing_done);
+		pmf_put_function(pfunc_cpu0_volt_high);
+		pmf_put_function(pfunc_cpu0_volt_low);
+		pmf_put_function(pfunc_cpu1_volt_high);
+		pmf_put_function(pfunc_cpu1_volt_low);
+	}
+	of_node_put(hwclock);
+	of_node_put(cpuid);
+	of_node_put(cpunode);
+
+	return rc;
+}
+
+static int __init g5_rm31_cpufreq_init(struct device_node *cpus)
+{
+	/* NYI */
+	return 0;
+}
+
+static int __init g5_cpufreq_init(void)
+{
+	struct device_node *cpus;
+	int rc;
+
+	cpus = of_find_node_by_path("/cpus");
+	if (cpus == NULL) {
+		DBG("No /cpus node !\n");
+		return -ENODEV;
+	}
+
+	if (machine_is_compatible("PowerMac7,2") ||
+	    machine_is_compatible("PowerMac7,3"))
+		rc = g5_pm72_cpufreq_init(cpus);
+	else if (machine_is_compatible("RackMac3,1"))
+		rc = g5_rm31_cpufreq_init(cpus);
+	else
+		rc = g5_neo2_cpufreq_init(cpus);
+
+	of_node_put(cpus);
+	return rc;
+}
+
 module_init(g5_cpufreq_init);
 
 
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index f6e22da..558dd06 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -58,12 +58,11 @@
 extern int powersave_nap;
 extern struct device_node *k2_skiplist[2];
 
-
 /*
  * We use a single global lock to protect accesses. Each driver has
  * to take care of its own locking
  */
-static DEFINE_SPINLOCK(feature_lock);
+DEFINE_SPINLOCK(feature_lock);
 
 #define LOCK(flags)	spin_lock_irqsave(&feature_lock, flags);
 #define UNLOCK(flags)	spin_unlock_irqrestore(&feature_lock, flags);
@@ -101,26 +100,17 @@
 	"Keylargo",
 	"Pangea",
 	"Intrepid",
-	"K2"
+	"K2",
+	"Shasta",
 };
 
 
+struct device_node *uninorth_node;
+u32 __iomem *uninorth_base;
 
-/*
- * Uninorth reg. access. Note that Uni-N regs are big endian
- */
-
-#define UN_REG(r)	(uninorth_base + ((r) >> 2))
-#define UN_IN(r)	(in_be32(UN_REG(r)))
-#define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
-#define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
-#define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
-
-static struct device_node *uninorth_node;
-static u32 __iomem *uninorth_base;
 static u32 uninorth_rev;
-static int uninorth_u3;
-static void __iomem *u3_ht;
+static int uninorth_maj;
+static void __iomem *u3_ht_base;
 
 /*
  * For each motherboard family, we have a table of functions pointers
@@ -1399,8 +1389,15 @@
 static long g5_mpic_enable(struct device_node *node, long param, long value)
 {
 	unsigned long flags;
+	struct device_node *parent = of_get_parent(node);
+	int is_u3;
 
-	if (node->parent == NULL || strcmp(node->parent->name, "u3"))
+	if (parent == NULL)
+		return 0;
+	is_u3 = strcmp(parent->name, "u3") == 0 ||
+		strcmp(parent->name, "u4") == 0;
+	of_node_put(parent);
+	if (!is_u3)
 		return 0;
 
 	LOCK(flags);
@@ -1445,20 +1442,53 @@
 	/* Very crude implementation for now */
 	struct macio_chip *macio = &macio_chips[0];
 	unsigned long flags;
+	int cell;
+	u32 fcrs[3][3] = {
+		{ 0,
+		  K2_FCR1_I2S0_CELL_ENABLE |
+		  K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE,
+		  KL3_I2S0_CLK18_ENABLE
+		},
+		{ KL0_SCC_A_INTF_ENABLE,
+		  K2_FCR1_I2S1_CELL_ENABLE |
+		  K2_FCR1_I2S1_CLK_ENABLE_BIT | K2_FCR1_I2S1_ENABLE,
+		  KL3_I2S1_CLK18_ENABLE
+		},
+		{ KL0_SCC_B_INTF_ENABLE,
+		  SH_FCR1_I2S2_CELL_ENABLE |
+		  SH_FCR1_I2S2_CLK_ENABLE_BIT | SH_FCR1_I2S2_ENABLE,
+		  SH_FCR3_I2S2_CLK18_ENABLE
+		},
+	};
 
-	if (value == 0)
-		return 0; /* don't disable yet */
+	if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
+		return -ENODEV;
+	if (strncmp(node->name, "i2s-", 4))
+		return -ENODEV;
+	cell = node->name[4] - 'a';
+	switch(cell) {
+	case 0:
+	case 1:
+		break;
+	case 2:
+		if (macio->type == macio_shasta)
+			break;
+	default:
+		return -ENODEV;
+	}
 
 	LOCK(flags);
-	MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE |
-		  KL3_I2S0_CLK18_ENABLE);
+	if (value) {
+		MACIO_BIC(KEYLARGO_FCR0, fcrs[cell][0]);
+		MACIO_BIS(KEYLARGO_FCR1, fcrs[cell][1]);
+		MACIO_BIS(KEYLARGO_FCR3, fcrs[cell][2]);
+	} else {
+		MACIO_BIC(KEYLARGO_FCR3, fcrs[cell][2]);
+		MACIO_BIC(KEYLARGO_FCR1, fcrs[cell][1]);
+		MACIO_BIS(KEYLARGO_FCR0, fcrs[cell][0]);
+	}
 	udelay(10);
-	MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE |
-		  K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE);
-	udelay(10);
-	MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET);
 	UNLOCK(flags);
-	udelay(10);
 
 	return 0;
 }
@@ -1473,7 +1503,7 @@
 	struct device_node *np;
 
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo2)
+	if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
 		return -ENODEV;
 
 	np = find_path_device("/cpus");
@@ -1512,14 +1542,17 @@
  */
 void g5_phy_disable_cpu1(void)
 {
-	UN_OUT(U3_API_PHY_CONFIG_1, 0);
+	if (uninorth_maj == 3)
+		UN_OUT(U3_API_PHY_CONFIG_1, 0);
 }
 #endif /* CONFIG_POWER4 */
 
 #ifndef CONFIG_POWER4
 
-static void
-keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
+
+#ifdef CONFIG_PM
+
+static void keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
 {
 	u32 temp;
 
@@ -1572,8 +1605,7 @@
 	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
 }
 
-static void
-pangea_shutdown(struct macio_chip *macio, int sleep_mode)
+static void pangea_shutdown(struct macio_chip *macio, int sleep_mode)
 {
 	u32 temp;
 
@@ -1606,8 +1638,7 @@
 	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
 }
 
-static void
-intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
+static void intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
 {
 	u32 temp;
 
@@ -1635,124 +1666,6 @@
 }
 
 
-void pmac_tweak_clock_spreading(int enable)
-{
-	struct macio_chip *macio = &macio_chips[0];
-
-	/* Hack for doing clock spreading on some machines PowerBooks and
-	 * iBooks. This implements the "platform-do-clockspreading" OF
-	 * property as decoded manually on various models. For safety, we also
-	 * check the product ID in the device-tree in cases we'll whack the i2c
-	 * chip to make reasonably sure we won't set wrong values in there
-	 *
-	 * Of course, ultimately, we have to implement a real parser for
-	 * the platform-do-* stuff...
-	 */
-
-	if (macio->type == macio_intrepid) {
-		struct device_node *clock =
-			of_find_node_by_path("/uni-n@f8000000/hw-clock");
-		if (clock && get_property(clock, "platform-do-clockspreading",
-					  NULL)) {
-			printk(KERN_INFO "%sabling clock spreading on Intrepid"
-			       " ASIC\n", enable ? "En" : "Dis");
-			if (enable)
-				UN_OUT(UNI_N_CLOCK_SPREADING, 2);
-			else
-				UN_OUT(UNI_N_CLOCK_SPREADING, 0);
-			mdelay(40);
-		}
-		of_node_put(clock);
-	}
-
-	while (machine_is_compatible("PowerBook5,2") ||
-	       machine_is_compatible("PowerBook5,3") ||
-	       machine_is_compatible("PowerBook6,2") ||
-	       machine_is_compatible("PowerBook6,3")) {
-		struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
-		struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
-		u8 buffer[9];
-		u32 *productID;
-		int i, rc, changed = 0;
-
-		if (dt == NULL)
-			break;
-		productID = (u32 *)get_property(dt, "pid#", NULL);
-		if (productID == NULL)
-			break;
-		while(ui2c) {
-			struct device_node *p = of_get_parent(ui2c);
-			if (p && !strcmp(p->name, "uni-n"))
-				break;
-			ui2c = of_find_node_by_type(ui2c, "i2c");
-		}
-		if (ui2c == NULL)
-			break;
-		DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
-		rc = pmac_low_i2c_open(ui2c, 1);
-		if (rc != 0)
-			break;
-		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-		DBG("read result: %d,", rc);
-		if (rc != 0) {
-			pmac_low_i2c_close(ui2c);
-			break;
-		}
-		for (i=0; i<9; i++)
-			DBG(" %02x", buffer[i]);
-		DBG("\n");
-
-		switch(*productID) {
-		case 0x1182:	/* AlBook 12" rev 2 */
-		case 0x1183:	/* iBook G4 12" */
-			buffer[0] = (buffer[0] & 0x8f) | 0x70;
-			buffer[2] = (buffer[2] & 0x7f) | 0x00;
-			buffer[5] = (buffer[5] & 0x80) | 0x31;
-			buffer[6] = (buffer[6] & 0x40) | 0xb0;
-			buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
-			buffer[8] = (buffer[8] & 0x00) | 0x30;
-			changed = 1;
-			break;
-		case 0x3142:	/* AlBook 15" (ATI M10) */
-		case 0x3143:	/* AlBook 17" (ATI M10) */
-			buffer[0] = (buffer[0] & 0xaf) | 0x50;
-			buffer[2] = (buffer[2] & 0x7f) | 0x00;
-			buffer[5] = (buffer[5] & 0x80) | 0x31;
-			buffer[6] = (buffer[6] & 0x40) | 0xb0;
-			buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
-			buffer[8] = (buffer[8] & 0x00) | 0x30;
-			changed = 1;
-			break;
-		default:
-			DBG("i2c-hwclock: Machine model not handled\n");
-			break;
-		}
-		if (!changed) {
-			pmac_low_i2c_close(ui2c);
-			break;
-		}
-		printk(KERN_INFO "%sabling clock spreading on i2c clock chip\n",
-		       enable ? "En" : "Dis");
-
-		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
-		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
-		DBG("write result: %d,", rc);
-		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-		DBG("read result: %d,", rc);
-		if (rc != 0) {
-			pmac_low_i2c_close(ui2c);
-			break;
-		}
-		for (i=0; i<9; i++)
-			DBG(" %02x", buffer[i]);
-		pmac_low_i2c_close(ui2c);
-		break;
-	}
-}
-
-
 static int
 core99_sleep(void)
 {
@@ -1909,6 +1822,8 @@
 	return 0;
 }
 
+#endif /* CONFIG_PM */
+
 static long
 core99_sleep_state(struct device_node *node, long param, long value)
 {
@@ -1930,10 +1845,13 @@
 	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
 		return -EPERM;
 
+#ifdef CONFIG_PM
 	if (value == 1)
 		return core99_sleep();
 	else if (value == 0)
 		return core99_wake_up();
+
+#endif /* CONFIG_PM */
 	return 0;
 }
 
@@ -2057,7 +1975,9 @@
 	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
 	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
 	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
+#ifdef CONFIG_PM
 	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
+#endif
 #ifdef CONFIG_SMP
 	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
 #endif /* CONFIG_SMP */
@@ -2427,6 +2347,14 @@
 		PMAC_TYPE_POWERMAC_G5_U3L,	g5_features,
 		0,
 	},
+	{	"PowerMac11,2",			"PowerMac G5 Dual Core",
+		PMAC_TYPE_POWERMAC_G5_U3L,	g5_features,
+		0,
+	},
+	{	"PowerMac12,1",			"iMac G5 (iSight)",
+		PMAC_TYPE_POWERMAC_G5_U3L,	g5_features,
+		0,
+	},
 	{       "RackMac3,1",                   "XServe G5",
 		PMAC_TYPE_XSERVE_G5,		g5_features,
 		0,
@@ -2539,6 +2467,11 @@
 		pmac_mb.model_name = "Unknown K2-based";
 		pmac_mb.features = g5_features;
 		break;
+	case macio_shasta:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_SHASTA;
+		pmac_mb.model_name = "Unknown Shasta-based";
+		pmac_mb.features = g5_features;
+		break;
 #endif /* CONFIG_POWER4 */
 	default:
 		return -ENODEV;
@@ -2607,6 +2540,8 @@
  */
 static void __init probe_uninorth(void)
 {
+	u32 *addrp;
+	phys_addr_t address;
 	unsigned long actrl;
 
 	/* Locate core99 Uni-N */
@@ -2614,22 +2549,31 @@
 	/* Locate G5 u3 */
 	if (uninorth_node == NULL) {
 		uninorth_node = of_find_node_by_name(NULL, "u3");
-		uninorth_u3 = 1;
+		uninorth_maj = 3;
 	}
-	if (uninorth_node && uninorth_node->n_addrs > 0) {
-		unsigned long address = uninorth_node->addrs[0].address;
-		uninorth_base = ioremap(address, 0x40000);
-		uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
-		if (uninorth_u3)
-			u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
-	} else
-		uninorth_node = NULL;
-
-	if (!uninorth_node)
+	/* Locate G5 u4 */
+	if (uninorth_node == NULL) {
+		uninorth_node = of_find_node_by_name(NULL, "u4");
+		uninorth_maj = 4;
+	}
+	if (uninorth_node == NULL)
 		return;
 
-	printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
-	       uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
+	addrp = (u32 *)get_property(uninorth_node, "reg", NULL);
+	if (addrp == NULL)
+		return;
+	address = of_translate_address(uninorth_node, addrp);
+	if (address == 0)
+		return;
+	uninorth_base = ioremap(address, 0x40000);
+	uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+	if (uninorth_maj == 3 || uninorth_maj == 4)
+		u3_ht_base = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
+
+	printk(KERN_INFO "Found %s memory controller & host bridge"
+	       " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" :
+	       uninorth_maj == 4 ? "U4" : "UniNorth",
+	       (unsigned int)address, uninorth_rev);
 	printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
 
 	/* Set the arbitrer QAck delay according to what Apple does
@@ -2637,7 +2581,8 @@
 	if (uninorth_rev < 0x11) {
 		actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
 		actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
-			UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+			UNI_N_ARB_CTRL_QACK_DELAY) <<
+			UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
 		UN_OUT(UNI_N_ARB_CTRL, actrl);
 	}
 
@@ -2645,7 +2590,8 @@
 	 * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
 	 * memory timeout
 	 */
-	if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
+	if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) ||
+	    uninorth_rev == 0xc0)
 		UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
 }
 
@@ -2653,18 +2599,17 @@
 {
 	struct device_node*	node;
 	int			i;
-	volatile u32 __iomem *	base;
-	u32*			revp;
+	volatile u32 __iomem	*base;
+	u32			*addrp, *revp;
+	phys_addr_t		addr;
+	u64			size;
 
-	node = find_devices(name);
-	if (!node || !node->n_addrs)
-		return;
-	if (compat)
-		do {
-			if (device_is_compatible(node, compat))
-				break;
-			node = node->next;
-		} while (node);
+	for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {
+		if (!compat)
+			break;
+		if (device_is_compatible(node, compat))
+			break;
+	}
 	if (!node)
 		return;
 	for(i=0; i<MAX_MACIO_CHIPS; i++) {
@@ -2673,22 +2618,38 @@
 		if (macio_chips[i].of_node == node)
 			return;
 	}
+
 	if (i >= MAX_MACIO_CHIPS) {
 		printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
 		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
 		return;
 	}
-	base = ioremap(node->addrs[0].address, node->addrs[0].size);
-	if (!base) {
-		printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
+	addrp = of_get_pci_address(node, 0, &size, NULL);
+	if (addrp == NULL) {
+		printk(KERN_ERR "pmac_feature: %s: can't find base !\n",
+		       node->full_name);
 		return;
 	}
-	if (type == macio_keylargo) {
+	addr = of_translate_address(node, addrp);
+	if (addr == 0) {
+		printk(KERN_ERR "pmac_feature: %s, can't translate base !\n",
+		       node->full_name);
+		return;
+	}
+	base = ioremap(addr, (unsigned long)size);
+	if (!base) {
+		printk(KERN_ERR "pmac_feature: %s, can't map mac-io chip !\n",
+		       node->full_name);
+		return;
+	}
+	if (type == macio_keylargo || type == macio_keylargo2) {
 		u32 *did = (u32 *)get_property(node, "device-id", NULL);
 		if (*did == 0x00000025)
 			type = macio_pangea;
 		if (*did == 0x0000003e)
 			type = macio_intrepid;
+		if (*did == 0x0000004f)
+			type = macio_shasta;
 	}
 	macio_chips[i].of_node	= node;
 	macio_chips[i].type	= type;
@@ -2787,7 +2748,8 @@
 	}
 
 #ifdef CONFIG_POWER4
-	if (macio_chips[0].type == macio_keylargo2) {
+	if (macio_chips[0].type == macio_keylargo2 ||
+	    macio_chips[0].type == macio_shasta) {
 #ifndef CONFIG_SMP
 		/* On SMP machines running UP, we have the second CPU eating
 		 * bus cycles. We need to take it off the bus. This is done
@@ -2896,12 +2858,6 @@
 		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
 	}
 
-	/* Some machine models need the clock chip to be properly setup for
-	 * clock spreading now. This should be a platform function but we
-	 * don't do these at the moment
-	 */
-	pmac_tweak_clock_spreading(1);
-
 #endif /* CONFIG_POWER4 */
 
 	/* On all machines, switch modem & serial ports off */
@@ -2929,9 +2885,6 @@
 		return;
 	}
 
-	/* Setup low-level i2c stuffs */
-	pmac_init_low_i2c();
-
 	/* Probe machine type */
 	if (probe_motherboard())
 		printk(KERN_WARNING "Unknown PowerMac !\n");
@@ -2942,26 +2895,6 @@
 	set_initial_features();
 }
 
-int __init pmac_feature_late_init(void)
-{
-#if 0
-	struct device_node *np;
-
-	/* Request some resources late */
-	if (uninorth_node)
-		request_OF_resource(uninorth_node, 0, NULL);
-	np = find_devices("hammerhead");
-	if (np)
-		request_OF_resource(np, 0, NULL);
-	np = find_devices("interrupt-controller");
-	if (np)
-		request_OF_resource(np, 0, NULL);
-#endif
-	return 0;
-}
-
-device_initcall(pmac_feature_late_init);
-
 #if 0
 static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
 {
@@ -2984,9 +2917,9 @@
 	u8	px_bus, px_devfn;
 	struct pci_controller *px_hose;
 
-	(void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
-	ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
-	ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
+	(void)in_be32(u3_ht_base + U3_HT_LINK_COMMAND);
+	ucfg = cfg = in_be32(u3_ht_base + U3_HT_LINK_CONFIG);
+	ufreq = freq = in_be32(u3_ht_base + U3_HT_LINK_FREQ);
 	dump_HT_speeds("U3 HyperTransport", cfg, freq);
 
 	pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index f3f39e8..535c802 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -1,22 +1,34 @@
 /*
- *  arch/ppc/platforms/pmac_low_i2c.c
+ * arch/powerpc/platforms/powermac/low_i2c.c
  *
- *  Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *  Copyright (C) 2003-2005 Ben. Herrenschmidt (benh@kernel.crashing.org)
  *
  *  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 file contains some low-level i2c access routines that
- *  need to be used by various bits of the PowerMac platform code
- *  at times where the real asynchronous & interrupt driven driver
- *  cannot be used. The API borrows some semantics from the darwin
- *  driver in order to ease the implementation of the platform
- *  properties parser
+ * The linux i2c layer isn't completely suitable for our needs for various
+ * reasons ranging from too late initialisation to semantics not perfectly
+ * matching some requirements of the apple platform functions etc...
+ *
+ * This file thus provides a simple low level unified i2c interface for
+ * powermac that covers the various types of i2c busses used in Apple machines.
+ * For now, keywest, PMU and SMU, though we could add Cuda, or other bit
+ * banging busses found on older chipstes in earlier machines if we ever need
+ * one of them.
+ *
+ * The drivers in this file are synchronous/blocking. In addition, the
+ * keywest one is fairly slow due to the use of msleep instead of interrupts
+ * as the interrupt is currently used by i2c-keywest. In the long run, we
+ * might want to get rid of those high-level interfaces to linux i2c layer
+ * either completely (converting all drivers) or replacing them all with a
+ * single stub driver on top of this one. Once done, the interrupt will be
+ * available for our use.
  */
 
 #undef DEBUG
+#undef DEBUG_LOW
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -25,66 +37,91 @@
 #include <linux/module.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/timer.h>
 #include <asm/keylargo.h>
 #include <asm/uninorth.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
+#include <asm/smu.h>
+#include <asm/pmac_pfunc.h>
 #include <asm/pmac_low_i2c.h>
 
-#define MAX_LOW_I2C_HOST	4
-
 #ifdef DEBUG
 #define DBG(x...) do {\
-		printk(KERN_DEBUG "KW:" x);	\
+		printk(KERN_DEBUG "low_i2c:" x);	\
 	} while(0)
 #else
 #define DBG(x...)
 #endif
 
-struct low_i2c_host;
+#ifdef DEBUG_LOW
+#define DBG_LOW(x...) do {\
+		printk(KERN_DEBUG "low_i2c:" x);	\
+	} while(0)
+#else
+#define DBG_LOW(x...)
+#endif
 
-typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
 
-struct low_i2c_host
+static int pmac_i2c_force_poll = 1;
+
+/*
+ * A bus structure. Each bus in the system has such a structure associated.
+ */
+struct pmac_i2c_bus
 {
-	struct device_node	*np;		/* OF device node */
-	struct semaphore	mutex;		/* Access mutex for use by i2c-keywest */
-	low_i2c_func_t		func;		/* Access function */
-	unsigned int		is_open : 1;	/* Poor man's access control */
-	int			mode;		/* Current mode */
-	int			channel;	/* Current channel */
-	int			num_channels;	/* Number of channels */
-	void __iomem		*base;		/* For keywest-i2c, base address */
-	int			bsteps;		/* And register stepping */
-	int			speed;		/* And speed */
+	struct list_head	link;
+	struct device_node	*controller;
+	struct device_node	*busnode;
+	int			type;
+	int			flags;
+	struct i2c_adapter	*adapter;
+	void			*hostdata;
+	int			channel;	/* some hosts have multiple */
+	int			mode;		/* current mode */
+	struct semaphore	sem;
+	int			opened;
+	int			polled;		/* open mode */
+	struct platform_device	*platform_dev;
+
+	/* ops */
+	int (*open)(struct pmac_i2c_bus *bus);
+	void (*close)(struct pmac_i2c_bus *bus);
+	int (*xfer)(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+		    u32 subaddr, u8 *data, int len);
 };
 
-static struct low_i2c_host	low_i2c_hosts[MAX_LOW_I2C_HOST];
+static LIST_HEAD(pmac_i2c_busses);
 
-/* No locking is necessary on allocation, we are running way before
- * anything can race with us
+/*
+ * Keywest implementation
  */
-static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
+
+struct pmac_i2c_host_kw
 {
-	int i;
+	struct semaphore	mutex;		/* Access mutex for use by
+						 * i2c-keywest */
+	void __iomem		*base;		/* register base address */
+	int			bsteps;		/* register stepping */
+	int			speed;		/* speed */
+	int			irq;
+	u8			*data;
+	unsigned		len;
+	int			state;
+	int			rw;
+	int			polled;
+	int			result;
+	struct completion	complete;
+	spinlock_t		lock;
+	struct timer_list	timeout_timer;
+};
 
-	for (i = 0; i < MAX_LOW_I2C_HOST; i++)
-		if (low_i2c_hosts[i].np == np)
-			return &low_i2c_hosts[i];
-	return NULL;
-}
-
-/*
- *
- * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
- *
- */
-
-/*
- * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
- * should be moved somewhere in include/asm-ppc/
- */
 /* Register indices */
 typedef enum {
 	reg_mode = 0,
@@ -97,6 +134,8 @@
 	reg_data
 } reg_t;
 
+/* The Tumbler audio equalizer can be really slow sometimes */
+#define KW_POLL_TIMEOUT		(2*HZ)
 
 /* Mode register */
 #define KW_I2C_MODE_100KHZ	0x00
@@ -140,8 +179,9 @@
 };
 
 #define WRONG_STATE(name) do {\
-		printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
-		       name, __kw_state_names[state], isr); \
+		printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s " \
+		       "(isr: %02x)\n",	\
+		       name, __kw_state_names[host->state], isr); \
 	} while(0)
 
 static const char *__kw_state_names[] = {
@@ -153,120 +193,137 @@
 	"state_dead"
 };
 
-static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
+static inline u8 __kw_read_reg(struct pmac_i2c_host_kw *host, reg_t reg)
 {
 	return readb(host->base + (((unsigned int)reg) << host->bsteps));
 }
 
-static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
+static inline void __kw_write_reg(struct pmac_i2c_host_kw *host,
+				  reg_t reg, u8 val)
 {
 	writeb(val, host->base + (((unsigned)reg) << host->bsteps));
 	(void)__kw_read_reg(host, reg_subaddr);
 }
 
-#define kw_write_reg(reg, val)	__kw_write_reg(host, reg, val) 
-#define kw_read_reg(reg)	__kw_read_reg(host, reg) 
+#define kw_write_reg(reg, val)	__kw_write_reg(host, reg, val)
+#define kw_read_reg(reg)	__kw_read_reg(host, reg)
 
-
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8 kw_wait_interrupt(struct low_i2c_host* host)
+static u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host)
 {
 	int i, j;
 	u8 isr;
 	
-	for (i = 0; i < 100000; i++) {
+	for (i = 0; i < 1000; i++) {
 		isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
 		if (isr != 0)
 			return isr;
 
 		/* This code is used with the timebase frozen, we cannot rely
-		 * on udelay ! For now, just use a bogus loop
+		 * on udelay nor schedule when in polled mode !
+		 * For now, just use a bogus loop....
 		 */
-		for (j = 1; j < 10000; j++)
-			mb();
+		if (host->polled) {
+			for (j = 1; j < 100000; j++)
+				mb();
+		} else
+			msleep(1);
 	}
 	return isr;
 }
 
-static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
+static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
 {
 	u8 ack;
 
-	DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr);
+	DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n",
+		__kw_state_names[host->state], isr);
+
+	if (host->state == state_idle) {
+		printk(KERN_WARNING "low_i2c: Keywest got an out of state"
+		       " interrupt, ignoring\n");
+		kw_write_reg(reg_isr, isr);
+		return;
+	}
 
 	if (isr == 0) {
-		if (state != state_stop) {
-			DBG("KW: Timeout !\n");
-			*rc = -EIO;
+		if (host->state != state_stop) {
+			DBG_LOW("KW: Timeout !\n");
+			host->result = -EIO;
 			goto stop;
 		}
-		if (state == state_stop) {
+		if (host->state == state_stop) {
 			ack = kw_read_reg(reg_status);
-			if (!(ack & KW_I2C_STAT_BUSY)) {
-				state = state_idle;
-				kw_write_reg(reg_ier, 0x00);
-			}
+			if (ack & KW_I2C_STAT_BUSY)
+				kw_write_reg(reg_status, 0);
+			host->state = state_idle;
+			kw_write_reg(reg_ier, 0x00);
+			if (!host->polled)
+				complete(&host->complete);
 		}
-		return state;
+		return;
 	}
 
 	if (isr & KW_I2C_IRQ_ADDR) {
 		ack = kw_read_reg(reg_status);
-		if (state != state_addr) {
+		if (host->state != state_addr) {
 			kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
 			WRONG_STATE("KW_I2C_IRQ_ADDR"); 
-			*rc = -EIO;
+			host->result = -EIO;
 			goto stop;
 		}
-		if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {			
-			*rc = -ENODEV;
-			DBG("KW: NAK on address\n");
-			return state_stop;		     
+		if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+			host->result = -ENODEV;
+			DBG_LOW("KW: NAK on address\n");
+			host->state = state_stop;
+			return;
 		} else {
-			if (rw) {
-				state = state_read;
-				if (*len > 1)
-					kw_write_reg(reg_control, KW_I2C_CTL_AAK);
+			if (host->len == 0) {
+				kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+				goto stop;
+			}
+			if (host->rw) {
+				host->state = state_read;
+				if (host->len > 1)
+					kw_write_reg(reg_control,
+						     KW_I2C_CTL_AAK);
 			} else {
-				state = state_write;
-				kw_write_reg(reg_data, **data);
-				(*data)++; (*len)--;
+				host->state = state_write;
+				kw_write_reg(reg_data, *(host->data++));
+				host->len--;
 			}
 		}
 		kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
 	}
 
 	if (isr & KW_I2C_IRQ_DATA) {
-		if (state == state_read) {
-			**data = kw_read_reg(reg_data);
-			(*data)++; (*len)--;
+		if (host->state == state_read) {
+			*(host->data++) = kw_read_reg(reg_data);
+			host->len--;
 			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
-			if ((*len) == 0)
-				state = state_stop;
-			else if ((*len) == 1)
+			if (host->len == 0)
+				host->state = state_stop;
+			else if (host->len == 1)
 				kw_write_reg(reg_control, 0);
-		} else if (state == state_write) {
+		} else if (host->state == state_write) {
 			ack = kw_read_reg(reg_status);
 			if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-				DBG("KW: nack on data write\n");
-				*rc = -EIO;
+				DBG_LOW("KW: nack on data write\n");
+				host->result = -EIO;
 				goto stop;
-			} else if (*len) {
-				kw_write_reg(reg_data, **data);
-				(*data)++; (*len)--;
+			} else if (host->len) {
+				kw_write_reg(reg_data, *(host->data++));
+				host->len--;
 			} else {
 				kw_write_reg(reg_control, KW_I2C_CTL_STOP);
-				state = state_stop;
-				*rc = 0;
+				host->state = state_stop;
+				host->result = 0;
 			}
 			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
 		} else {
 			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
 			WRONG_STATE("KW_I2C_IRQ_DATA"); 
-			if (state != state_stop) {
-				*rc = -EIO;
+			if (host->state != state_stop) {
+				host->result = -EIO;
 				goto stop;
 			}
 		}
@@ -274,98 +331,194 @@
 
 	if (isr & KW_I2C_IRQ_STOP) {
 		kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
-		if (state != state_stop) {
+		if (host->state != state_stop) {
 			WRONG_STATE("KW_I2C_IRQ_STOP");
-			*rc = -EIO;
+			host->result = -EIO;
 		}
-		return state_idle;
+		host->state = state_idle;
+		if (!host->polled)
+			complete(&host->complete);
 	}
 
 	if (isr & KW_I2C_IRQ_START)
 		kw_write_reg(reg_isr, KW_I2C_IRQ_START);
 
-	return state;
-
+	return;
  stop:
 	kw_write_reg(reg_control, KW_I2C_CTL_STOP);	
-	return state_stop;
+	host->state = state_stop;
+	return;
 }
 
-static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
+/* Interrupt handler */
+static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct pmac_i2c_host_kw *host = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	del_timer(&host->timeout_timer);
+	kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
+	if (host->state != state_idle) {
+		host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+		add_timer(&host->timeout_timer);
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void kw_i2c_timeout(unsigned long data)
+{
+	struct pmac_i2c_host_kw *host = (struct pmac_i2c_host_kw *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
+	if (host->state != state_idle) {
+		host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+		add_timer(&host->timeout_timer);
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int kw_i2c_open(struct pmac_i2c_bus *bus)
+{
+	struct pmac_i2c_host_kw *host = bus->hostdata;
+	down(&host->mutex);
+	return 0;
+}
+
+static void kw_i2c_close(struct pmac_i2c_bus *bus)
+{
+	struct pmac_i2c_host_kw *host = bus->hostdata;
+	up(&host->mutex);
+}
+
+static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+		       u32 subaddr, u8 *data, int len)
+{
+	struct pmac_i2c_host_kw *host = bus->hostdata;
 	u8 mode_reg = host->speed;
-	int state = state_addr;
-	int rc = 0;
+	int use_irq = host->irq != NO_IRQ && !bus->polled;
 
 	/* Setup mode & subaddress if any */
-	switch(host->mode) {
-	case pmac_low_i2c_mode_dumb:
-		printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
+	switch(bus->mode) {
+	case pmac_i2c_mode_dumb:
 		return -EINVAL;
-	case pmac_low_i2c_mode_std:
+	case pmac_i2c_mode_std:
 		mode_reg |= KW_I2C_MODE_STANDARD;
+		if (subsize != 0)
+			return -EINVAL;
 		break;
-	case pmac_low_i2c_mode_stdsub:
+	case pmac_i2c_mode_stdsub:
 		mode_reg |= KW_I2C_MODE_STANDARDSUB;
+		if (subsize != 1)
+			return -EINVAL;
 		break;
-	case pmac_low_i2c_mode_combined:
+	case pmac_i2c_mode_combined:
 		mode_reg |= KW_I2C_MODE_COMBINED;
+		if (subsize != 1)
+			return -EINVAL;
 		break;
 	}
 
 	/* Setup channel & clear pending irqs */
 	kw_write_reg(reg_isr, kw_read_reg(reg_isr));
-	kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
+	kw_write_reg(reg_mode, mode_reg | (bus->channel << 4));
 	kw_write_reg(reg_status, 0);
 
-	/* Set up address and r/w bit */
-	kw_write_reg(reg_addr, addr);
+	/* Set up address and r/w bit, strip possible stale bus number from
+	 * address top bits
+	 */
+	kw_write_reg(reg_addr, addrdir & 0xff);
 
 	/* Set up the sub address */
 	if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
 	    || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
 		kw_write_reg(reg_subaddr, subaddr);
 
-	/* Start sending address & disable interrupt*/
-	kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
-	kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
+	/* Prepare for async operations */
+	host->data = data;
+	host->len = len;
+	host->state = state_addr;
+	host->result = 0;
+	host->rw = (addrdir & 1);
+	host->polled = bus->polled;
 
-	/* State machine, to turn into an interrupt handler */
-	while(state != state_idle) {
-		u8 isr = kw_wait_interrupt(host);
-		state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
+	/* Enable interrupt if not using polled mode and interrupt is
+	 * available
+	 */
+	if (use_irq) {
+		/* Clear completion */
+		INIT_COMPLETION(host->complete);
+		/* Ack stale interrupts */
+		kw_write_reg(reg_isr, kw_read_reg(reg_isr));
+		/* Arm timeout */
+		host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+		add_timer(&host->timeout_timer);
+		/* Enable emission */
+		kw_write_reg(reg_ier, KW_I2C_IRQ_MASK);
 	}
 
-	return rc;
+	/* Start sending address */
+	kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
+
+	/* Wait for completion */
+	if (use_irq)
+		wait_for_completion(&host->complete);
+	else {
+		while(host->state != state_idle) {
+			unsigned long flags;
+
+			u8 isr = kw_i2c_wait_interrupt(host);
+			spin_lock_irqsave(&host->lock, flags);
+			kw_i2c_handle_interrupt(host, isr);
+			spin_unlock_irqrestore(&host->lock, flags);
+		}
+	}
+
+	/* Disable emission */
+	kw_write_reg(reg_ier, 0);
+
+	return host->result;
 }
 
-static void keywest_low_i2c_add(struct device_node *np)
+static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
 {
-	struct low_i2c_host	*host = find_low_i2c_host(NULL);
-	u32			*psteps, *prate, steps, aoffset = 0;
-	struct device_node	*parent;
+	struct pmac_i2c_host_kw *host;
+	u32			*psteps, *prate, *addrp, steps;
 
+	host = kzalloc(sizeof(struct pmac_i2c_host_kw), GFP_KERNEL);
 	if (host == NULL) {
 		printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
 		       np->full_name);
-		return;
+		return NULL;
 	}
-	memset(host, 0, sizeof(*host));
 
+	/* Apple is kind enough to provide a valid AAPL,address property
+	 * on all i2c keywest nodes so far ... we would have to fallback
+	 * to macio parsing if that wasn't the case
+	 */
+	addrp = (u32 *)get_property(np, "AAPL,address", NULL);
+	if (addrp == NULL) {
+		printk(KERN_ERR "low_i2c: Can't find address for %s\n",
+		       np->full_name);
+		kfree(host);
+		return NULL;
+	}
 	init_MUTEX(&host->mutex);
-	host->np = of_node_get(np);	
+	init_completion(&host->complete);
+	spin_lock_init(&host->lock);
+	init_timer(&host->timeout_timer);
+	host->timeout_timer.function = kw_i2c_timeout;
+	host->timeout_timer.data = (unsigned long)host;
+
 	psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
 	steps = psteps ? (*psteps) : 0x10;
 	for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
 		steps >>= 1;
-	parent = of_get_parent(np);
-	host->num_channels = 1;
-	if (parent && parent->name[0] == 'u') {
-		host->num_channels = 2;
-		aoffset = 3;
-	}
 	/* Select interface rate */
-	host->speed = KW_I2C_MODE_100KHZ;
+	host->speed = KW_I2C_MODE_25KHZ;
 	prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
 	if (prate) switch(*prate) {
 	case 100:
@@ -378,146 +531,981 @@
 		host->speed = KW_I2C_MODE_25KHZ;
 		break;
 	}	
+	if (np->n_intrs > 0)
+		host->irq = np->intrs[0].line;
+	else
+		host->irq = NO_IRQ;
 
-	host->mode = pmac_low_i2c_mode_std;
-	host->base = ioremap(np->addrs[0].address + aoffset,
-						np->addrs[0].size);
-	host->func = keywest_low_i2c_func;
+	host->base = ioremap((*addrp), 0x1000);
+	if (host->base == NULL) {
+		printk(KERN_ERR "low_i2c: Can't map registers for %s\n",
+		       np->full_name);
+		kfree(host);
+		return NULL;
+	}
+
+	/* Make sure IRA is disabled */
+	kw_write_reg(reg_ier, 0);
+
+	/* Request chip interrupt */
+	if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host))
+		host->irq = NO_IRQ;
+
+	printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
+	       *addrp, host->irq, np->full_name);
+
+	return host;
 }
 
+
+static void __init kw_i2c_add(struct pmac_i2c_host_kw *host,
+			      struct device_node *controller,
+			      struct device_node *busnode,
+			      int channel)
+{
+	struct pmac_i2c_bus *bus;
+
+	bus = kzalloc(sizeof(struct pmac_i2c_bus), GFP_KERNEL);
+	if (bus == NULL)
+		return;
+
+	bus->controller = of_node_get(controller);
+	bus->busnode = of_node_get(busnode);
+	bus->type = pmac_i2c_bus_keywest;
+	bus->hostdata = host;
+	bus->channel = channel;
+	bus->mode = pmac_i2c_mode_std;
+	bus->open = kw_i2c_open;
+	bus->close = kw_i2c_close;
+	bus->xfer = kw_i2c_xfer;
+	init_MUTEX(&bus->sem);
+	if (controller == busnode)
+		bus->flags = pmac_i2c_multibus;
+	list_add(&bus->link, &pmac_i2c_busses);
+
+	printk(KERN_INFO " channel %d bus %s\n", channel,
+	       (controller == busnode) ? "<multibus>" : busnode->full_name);
+}
+
+static void __init kw_i2c_probe(void)
+{
+	struct device_node *np, *child, *parent;
+
+	/* Probe keywest-i2c busses */
+	for (np = NULL;
+	     (np = of_find_compatible_node(np, "i2c","keywest-i2c")) != NULL;){
+		struct pmac_i2c_host_kw *host;
+		int multibus, chans, i;
+
+		/* Found one, init a host structure */
+		host = kw_i2c_host_init(np);
+		if (host == NULL)
+			continue;
+
+		/* Now check if we have a multibus setup (old style) or if we
+		 * have proper bus nodes. Note that the "new" way (proper bus
+		 * nodes) might cause us to not create some busses that are
+		 * kept hidden in the device-tree. In the future, we might
+		 * want to work around that by creating busses without a node
+		 * but not for now
+		 */
+		child = of_get_next_child(np, NULL);
+		multibus = !child || strcmp(child->name, "i2c-bus");
+		of_node_put(child);
+
+		/* For a multibus setup, we get the bus count based on the
+		 * parent type
+		 */
+		if (multibus) {
+			parent = of_get_parent(np);
+			if (parent == NULL)
+				continue;
+			chans = parent->name[0] == 'u' ? 2 : 1;
+			for (i = 0; i < chans; i++)
+				kw_i2c_add(host, np, np, i);
+		} else {
+			for (child = NULL;
+			     (child = of_get_next_child(np, child)) != NULL;) {
+				u32 *reg =
+					(u32 *)get_property(child, "reg", NULL);
+				if (reg == NULL)
+					continue;
+				kw_i2c_add(host, np, child, *reg);
+			}
+		}
+	}
+}
+
+
 /*
  *
  * PMU implementation
  *
  */
 
-
 #ifdef CONFIG_ADB_PMU
 
-static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
+/*
+ * i2c command block to the PMU
+ */
+struct pmu_i2c_hdr {
+	u8	bus;
+	u8	mode;
+	u8	bus2;
+	u8	address;
+	u8	sub_addr;
+	u8	comb_addr;
+	u8	count;
+	u8	data[];
+};
+
+static void pmu_i2c_complete(struct adb_request *req)
 {
-	// TODO
-	return -ENODEV;
+	complete(req->arg);
 }
 
-static void pmu_low_i2c_add(struct device_node *np)
+static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+			u32 subaddr, u8 *data, int len)
 {
-	struct low_i2c_host	*host = find_low_i2c_host(NULL);
+	struct adb_request *req = bus->hostdata;
+	struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req->data[1];
+	struct completion comp;
+	int read = addrdir & 1;
+	int retry;
+	int rc = 0;
 
-	if (host == NULL) {
-		printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
-		       np->full_name);
+	/* For now, limit ourselves to 16 bytes transfers */
+	if (len > 16)
+		return -EINVAL;
+
+	init_completion(&comp);
+
+	for (retry = 0; retry < 16; retry++) {
+		memset(req, 0, sizeof(struct adb_request));
+		hdr->bus = bus->channel;
+		hdr->count = len;
+
+		switch(bus->mode) {
+		case pmac_i2c_mode_std:
+			if (subsize != 0)
+				return -EINVAL;
+			hdr->address = addrdir;
+			hdr->mode = PMU_I2C_MODE_SIMPLE;
+			break;
+		case pmac_i2c_mode_stdsub:
+		case pmac_i2c_mode_combined:
+			if (subsize != 1)
+				return -EINVAL;
+			hdr->address = addrdir & 0xfe;
+			hdr->comb_addr = addrdir;
+			hdr->sub_addr = subaddr;
+			if (bus->mode == pmac_i2c_mode_stdsub)
+				hdr->mode = PMU_I2C_MODE_STDSUB;
+			else
+				hdr->mode = PMU_I2C_MODE_COMBINED;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		INIT_COMPLETION(comp);
+		req->data[0] = PMU_I2C_CMD;
+		req->reply[0] = 0xff;
+		req->nbytes = sizeof(struct pmu_i2c_hdr) + 1;
+		req->done = pmu_i2c_complete;
+		req->arg = &comp;
+		if (!read && len) {
+			memcpy(hdr->data, data, len);
+			req->nbytes += len;
+		}
+		rc = pmu_queue_request(req);
+		if (rc)
+			return rc;
+		wait_for_completion(&comp);
+		if (req->reply[0] == PMU_I2C_STATUS_OK)
+			break;
+		msleep(15);
+	}
+	if (req->reply[0] != PMU_I2C_STATUS_OK)
+		return -EIO;
+
+	for (retry = 0; retry < 16; retry++) {
+		memset(req, 0, sizeof(struct adb_request));
+
+		/* I know that looks like a lot, slow as hell, but darwin
+		 * does it so let's be on the safe side for now
+		 */
+		msleep(15);
+
+		hdr->bus = PMU_I2C_BUS_STATUS;
+
+		INIT_COMPLETION(comp);
+		req->data[0] = PMU_I2C_CMD;
+		req->reply[0] = 0xff;
+		req->nbytes = 2;
+		req->done = pmu_i2c_complete;
+		req->arg = &comp;
+		rc = pmu_queue_request(req);
+		if (rc)
+			return rc;
+		wait_for_completion(&comp);
+
+		if (req->reply[0] == PMU_I2C_STATUS_OK && !read)
+			return 0;
+		if (req->reply[0] == PMU_I2C_STATUS_DATAREAD && read) {
+			int rlen = req->reply_len - 1;
+
+			if (rlen != len) {
+				printk(KERN_WARNING "low_i2c: PMU returned %d"
+				       " bytes, expected %d !\n", rlen, len);
+				return -EIO;
+			}
+			if (len)
+				memcpy(data, &req->reply[1], len);
+			return 0;
+		}
+	}
+	return -EIO;
+}
+
+static void __init pmu_i2c_probe(void)
+{
+	struct pmac_i2c_bus *bus;
+	struct device_node *busnode;
+	int channel, sz;
+
+	if (!pmu_present())
 		return;
-	}
-	memset(host, 0, sizeof(*host));
 
-	init_MUTEX(&host->mutex);
-	host->np = of_node_get(np);	
-	host->num_channels = 3;
-	host->mode = pmac_low_i2c_mode_std;
-	host->func = pmu_low_i2c_func;
+	/* There might or might not be a "pmu-i2c" node, we use that
+	 * or via-pmu itself, whatever we find. I haven't seen a machine
+	 * with separate bus nodes, so we assume a multibus setup
+	 */
+	busnode = of_find_node_by_name(NULL, "pmu-i2c");
+	if (busnode == NULL)
+		busnode = of_find_node_by_name(NULL, "via-pmu");
+	if (busnode == NULL)
+		return;
+
+	printk(KERN_INFO "PMU i2c %s\n", busnode->full_name);
+
+	/*
+	 * We add bus 1 and 2 only for now, bus 0 is "special"
+	 */
+	for (channel = 1; channel <= 2; channel++) {
+		sz = sizeof(struct pmac_i2c_bus) + sizeof(struct adb_request);
+		bus = kzalloc(sz, GFP_KERNEL);
+		if (bus == NULL)
+			return;
+
+		bus->controller = busnode;
+		bus->busnode = busnode;
+		bus->type = pmac_i2c_bus_pmu;
+		bus->channel = channel;
+		bus->mode = pmac_i2c_mode_std;
+		bus->hostdata = bus + 1;
+		bus->xfer = pmu_i2c_xfer;
+		init_MUTEX(&bus->sem);
+		bus->flags = pmac_i2c_multibus;
+		list_add(&bus->link, &pmac_i2c_busses);
+
+		printk(KERN_INFO " channel %d bus <multibus>\n", channel);
+	}
 }
 
 #endif /* CONFIG_ADB_PMU */
 
-void __init pmac_init_low_i2c(void)
+
+/*
+ *
+ * SMU implementation
+ *
+ */
+
+#ifdef CONFIG_PMAC_SMU
+
+static void smu_i2c_complete(struct smu_i2c_cmd *cmd, void *misc)
 {
-	struct device_node *np;
-
-	/* Probe keywest-i2c busses */
-	np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
-	while(np) {
-		keywest_low_i2c_add(np);
-		np = of_find_compatible_node(np, "i2c", "keywest-i2c");
-	}
-
-#ifdef CONFIG_ADB_PMU
-	/* Probe PMU busses */
-	np = of_find_node_by_name(NULL, "via-pmu");
-	if (np)
-		pmu_low_i2c_add(np);
-#endif /* CONFIG_ADB_PMU */
-
-	/* TODO: Add CUDA support as well */
+	complete(misc);
 }
 
+static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+			u32 subaddr, u8 *data, int len)
+{
+	struct smu_i2c_cmd *cmd = bus->hostdata;
+	struct completion comp;
+	int read = addrdir & 1;
+	int rc = 0;
+
+	if ((read && len > SMU_I2C_READ_MAX) ||
+	    ((!read) && len > SMU_I2C_WRITE_MAX))
+		return -EINVAL;
+
+	memset(cmd, 0, sizeof(struct smu_i2c_cmd));
+	cmd->info.bus = bus->channel;
+	cmd->info.devaddr = addrdir;
+	cmd->info.datalen = len;
+
+	switch(bus->mode) {
+	case pmac_i2c_mode_std:
+		if (subsize != 0)
+			return -EINVAL;
+		cmd->info.type = SMU_I2C_TRANSFER_SIMPLE;
+		break;
+	case pmac_i2c_mode_stdsub:
+	case pmac_i2c_mode_combined:
+		if (subsize > 3 || subsize < 1)
+			return -EINVAL;
+		cmd->info.sublen = subsize;
+		/* that's big-endian only but heh ! */
+		memcpy(&cmd->info.subaddr, ((char *)&subaddr) + (4 - subsize),
+		       subsize);
+		if (bus->mode == pmac_i2c_mode_stdsub)
+			cmd->info.type = SMU_I2C_TRANSFER_STDSUB;
+		else
+			cmd->info.type = SMU_I2C_TRANSFER_COMBINED;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (!read && len)
+		memcpy(cmd->info.data, data, len);
+
+	init_completion(&comp);
+	cmd->done = smu_i2c_complete;
+	cmd->misc = &comp;
+	rc = smu_queue_i2c(cmd);
+	if (rc < 0)
+		return rc;
+	wait_for_completion(&comp);
+	rc = cmd->status;
+
+	if (read && len)
+		memcpy(data, cmd->info.data, len);
+	return rc < 0 ? rc : 0;
+}
+
+static void __init smu_i2c_probe(void)
+{
+	struct device_node *controller, *busnode;
+	struct pmac_i2c_bus *bus;
+	u32 *reg;
+	int sz;
+
+	if (!smu_present())
+		return;
+
+	controller = of_find_node_by_name(NULL, "smu-i2c-control");
+	if (controller == NULL)
+		controller = of_find_node_by_name(NULL, "smu");
+	if (controller == NULL)
+		return;
+
+	printk(KERN_INFO "SMU i2c %s\n", controller->full_name);
+
+	/* Look for childs, note that they might not be of the right
+	 * type as older device trees mix i2c busses and other thigns
+	 * at the same level
+	 */
+	for (busnode = NULL;
+	     (busnode = of_get_next_child(controller, busnode)) != NULL;) {
+		if (strcmp(busnode->type, "i2c") &&
+		    strcmp(busnode->type, "i2c-bus"))
+			continue;
+		reg = (u32 *)get_property(busnode, "reg", NULL);
+		if (reg == NULL)
+			continue;
+
+		sz = sizeof(struct pmac_i2c_bus) + sizeof(struct smu_i2c_cmd);
+		bus = kzalloc(sz, GFP_KERNEL);
+		if (bus == NULL)
+			return;
+
+		bus->controller = controller;
+		bus->busnode = of_node_get(busnode);
+		bus->type = pmac_i2c_bus_smu;
+		bus->channel = *reg;
+		bus->mode = pmac_i2c_mode_std;
+		bus->hostdata = bus + 1;
+		bus->xfer = smu_i2c_xfer;
+		init_MUTEX(&bus->sem);
+		bus->flags = 0;
+		list_add(&bus->link, &pmac_i2c_busses);
+
+		printk(KERN_INFO " channel %x bus %s\n",
+		       bus->channel, busnode->full_name);
+	}
+}
+
+#endif /* CONFIG_PMAC_SMU */
+
+/*
+ *
+ * Core code
+ *
+ */
+
+
+struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node)
+{
+	struct device_node *p = of_node_get(node);
+	struct device_node *prev = NULL;
+	struct pmac_i2c_bus *bus;
+
+	while(p) {
+		list_for_each_entry(bus, &pmac_i2c_busses, link) {
+			if (p == bus->busnode) {
+				if (prev && bus->flags & pmac_i2c_multibus) {
+					u32 *reg;
+					reg = (u32 *)get_property(prev, "reg",
+								  NULL);
+					if (!reg)
+						continue;
+					if (((*reg) >> 8) != bus->channel)
+						continue;
+				}
+				of_node_put(p);
+				of_node_put(prev);
+				return bus;
+			}
+		}
+		of_node_put(prev);
+		prev = p;
+		p = of_get_parent(p);
+	}
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
+
+u8 pmac_i2c_get_dev_addr(struct device_node *device)
+{
+	u32 *reg = (u32 *)get_property(device, "reg", NULL);
+
+	if (reg == NULL)
+		return 0;
+
+	return (*reg) & 0xff;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_dev_addr);
+
+struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus)
+{
+	return bus->controller;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_controller);
+
+struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus)
+{
+	return bus->busnode;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_bus_node);
+
+int pmac_i2c_get_type(struct pmac_i2c_bus *bus)
+{
+	return bus->type;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_type);
+
+int pmac_i2c_get_flags(struct pmac_i2c_bus *bus)
+{
+	return bus->flags;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_flags);
+
+int pmac_i2c_get_channel(struct pmac_i2c_bus *bus)
+{
+	return bus->channel;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_channel);
+
+
+void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
+			     struct i2c_adapter *adapter)
+{
+	WARN_ON(bus->adapter != NULL);
+	bus->adapter = adapter;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_attach_adapter);
+
+void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
+			     struct i2c_adapter *adapter)
+{
+	WARN_ON(bus->adapter != adapter);
+	bus->adapter = NULL;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_detach_adapter);
+
+struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus)
+{
+	return bus->adapter;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter);
+
+struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter)
+{
+	struct pmac_i2c_bus *bus;
+
+	list_for_each_entry(bus, &pmac_i2c_busses, link)
+		if (bus->adapter == adapter)
+			return bus;
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_adapter_to_bus);
+
+extern int pmac_i2c_match_adapter(struct device_node *dev,
+				  struct i2c_adapter *adapter)
+{
+	struct pmac_i2c_bus *bus = pmac_i2c_find_bus(dev);
+
+	if (bus == NULL)
+		return 0;
+	return (bus->adapter == adapter);
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_match_adapter);
+
 int pmac_low_i2c_lock(struct device_node *np)
 {
-	struct low_i2c_host *host = find_low_i2c_host(np);
+	struct pmac_i2c_bus *bus, *found = NULL;
 
-	if (!host)
+	list_for_each_entry(bus, &pmac_i2c_busses, link) {
+		if (np == bus->controller) {
+			found = bus;
+			break;
+		}
+	}
+	if (!found)
 		return -ENODEV;
-	down(&host->mutex);
-	return 0;
+	return pmac_i2c_open(bus, 0);
 }
-EXPORT_SYMBOL(pmac_low_i2c_lock);
+EXPORT_SYMBOL_GPL(pmac_low_i2c_lock);
 
 int pmac_low_i2c_unlock(struct device_node *np)
 {
-	struct low_i2c_host *host = find_low_i2c_host(np);
+	struct pmac_i2c_bus *bus, *found = NULL;
 
-	if (!host)
+	list_for_each_entry(bus, &pmac_i2c_busses, link) {
+		if (np == bus->controller) {
+			found = bus;
+			break;
+		}
+	}
+	if (!found)
 		return -ENODEV;
-	up(&host->mutex);
+	pmac_i2c_close(bus);
 	return 0;
 }
-EXPORT_SYMBOL(pmac_low_i2c_unlock);
+EXPORT_SYMBOL_GPL(pmac_low_i2c_unlock);
 
 
-int pmac_low_i2c_open(struct device_node *np, int channel)
+int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled)
 {
-	struct low_i2c_host *host = find_low_i2c_host(np);
+	int rc;
 
-	if (!host)
-		return -ENODEV;
+	down(&bus->sem);
+	bus->polled = polled || pmac_i2c_force_poll;
+	bus->opened = 1;
+	bus->mode = pmac_i2c_mode_std;
+	if (bus->open && (rc = bus->open(bus)) != 0) {
+		bus->opened = 0;
+		up(&bus->sem);
+		return rc;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_open);
 
-	if (channel >= host->num_channels)
+void pmac_i2c_close(struct pmac_i2c_bus *bus)
+{
+	WARN_ON(!bus->opened);
+	if (bus->close)
+		bus->close(bus);
+	bus->opened = 0;
+	up(&bus->sem);
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_close);
+
+int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode)
+{
+	WARN_ON(!bus->opened);
+
+	/* Report me if you see the error below as there might be a new
+	 * "combined4" mode that I need to implement for the SMU bus
+	 */
+	if (mode < pmac_i2c_mode_dumb || mode > pmac_i2c_mode_combined) {
+		printk(KERN_ERR "low_i2c: Invalid mode %d requested on"
+		       " bus %s !\n", mode, bus->busnode->full_name);
+		return -EINVAL;
+	}
+	bus->mode = mode;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_setmode);
+
+int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+		  u32 subaddr, u8 *data, int len)
+{
+	int rc;
+
+	WARN_ON(!bus->opened);
+
+	DBG("xfer() chan=%d, addrdir=0x%x, mode=%d, subsize=%d, subaddr=0x%x,"
+	    " %d bytes, bus %s\n", bus->channel, addrdir, bus->mode, subsize,
+	    subaddr, len, bus->busnode->full_name);
+
+	rc = bus->xfer(bus, addrdir, subsize, subaddr, data, len);
+
+#ifdef DEBUG
+	if (rc)
+		DBG("xfer error %d\n", rc);
+#endif
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_xfer);
+
+/* some quirks for platform function decoding */
+enum {
+	pmac_i2c_quirk_invmask = 0x00000001u,
+};
+
+static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
+					      int quirks))
+{
+	struct pmac_i2c_bus *bus;
+	struct device_node *np;
+	static struct whitelist_ent {
+		char *name;
+		char *compatible;
+		int quirks;
+	} whitelist[] = {
+		/* XXX Study device-tree's & apple drivers are get the quirks
+		 * right !
+		 */
+		{ "i2c-hwclock", NULL, pmac_i2c_quirk_invmask },
+		{ "i2c-cpu-voltage", NULL, 0},
+		{  "temp-monitor", NULL, 0 },
+		{  "supply-monitor", NULL, 0 },
+		{ NULL, NULL, 0 },
+	};
+
+	/* Only some devices need to have platform functions instanciated
+	 * here. For now, we have a table. Others, like 9554 i2c GPIOs used
+	 * on Xserve, if we ever do a driver for them, will use their own
+	 * platform function instance
+	 */
+	list_for_each_entry(bus, &pmac_i2c_busses, link) {
+		for (np = NULL;
+		     (np = of_get_next_child(bus->busnode, np)) != NULL;) {
+			struct whitelist_ent *p;
+			/* If multibus, check if device is on that bus */
+			if (bus->flags & pmac_i2c_multibus)
+				if (bus != pmac_i2c_find_bus(np))
+					continue;
+			for (p = whitelist; p->name != NULL; p++) {
+				if (strcmp(np->name, p->name))
+					continue;
+				if (p->compatible &&
+				    !device_is_compatible(np, p->compatible))
+					continue;
+				callback(np, p->quirks);
+				break;
+			}
+		}
+	}
+}
+
+#define MAX_I2C_DATA	64
+
+struct pmac_i2c_pf_inst
+{
+	struct pmac_i2c_bus	*bus;
+	u8			addr;
+	u8			buffer[MAX_I2C_DATA];
+	u8			scratch[MAX_I2C_DATA];
+	int			bytes;
+	int			quirks;
+};
+
+static void* pmac_i2c_do_begin(struct pmf_function *func, struct pmf_args *args)
+{
+	struct pmac_i2c_pf_inst *inst;
+	struct pmac_i2c_bus	*bus;
+
+	bus = pmac_i2c_find_bus(func->node);
+	if (bus == NULL) {
+		printk(KERN_ERR "low_i2c: Can't find bus for %s (pfunc)\n",
+		       func->node->full_name);
+		return NULL;
+	}
+	if (pmac_i2c_open(bus, 0)) {
+		printk(KERN_ERR "low_i2c: Can't open i2c bus for %s (pfunc)\n",
+		       func->node->full_name);
+		return NULL;
+	}
+
+	/* XXX might need GFP_ATOMIC when called during the suspend process,
+	 * but then, there are already lots of issues with suspending when
+	 * near OOM that need to be resolved, the allocator itself should
+	 * probably make GFP_NOIO implicit during suspend
+	 */
+	inst = kzalloc(sizeof(struct pmac_i2c_pf_inst), GFP_KERNEL);
+	if (inst == NULL) {
+		pmac_i2c_close(bus);
+		return NULL;
+	}
+	inst->bus = bus;
+	inst->addr = pmac_i2c_get_dev_addr(func->node);
+	inst->quirks = (int)(long)func->driver_data;
+	return inst;
+}
+
+static void pmac_i2c_do_end(struct pmf_function *func, void *instdata)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+
+	if (inst == NULL)
+		return;
+	pmac_i2c_close(inst->bus);
+	if (inst)
+		kfree(inst);
+}
+
+static int pmac_i2c_do_read(PMF_STD_ARGS, u32 len)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+
+	inst->bytes = len;
+	return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 0, 0,
+			     inst->buffer, len);
+}
+
+static int pmac_i2c_do_write(PMF_STD_ARGS, u32 len, const u8 *data)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+
+	return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0,
+			     (u8 *)data, len);
+}
+
+/* This function is used to do the masking & OR'ing for the "rmw" type
+ * callbacks. Ze should apply the mask and OR in the values in the
+ * buffer before writing back. The problem is that it seems that
+ * various darwin drivers implement the mask/or differently, thus
+ * we need to check the quirks first
+ */
+static void pmac_i2c_do_apply_rmw(struct pmac_i2c_pf_inst *inst,
+				  u32 len, const u8 *mask, const u8 *val)
+{
+	int i;
+
+	if (inst->quirks & pmac_i2c_quirk_invmask) {
+		for (i = 0; i < len; i ++)
+			inst->scratch[i] = (inst->buffer[i] & mask[i]) | val[i];
+	} else {
+		for (i = 0; i < len; i ++)
+			inst->scratch[i] = (inst->buffer[i] & ~mask[i])
+				| (val[i] & mask[i]);
+	}
+}
+
+static int pmac_i2c_do_rmw(PMF_STD_ARGS, u32 masklen, u32 valuelen,
+			   u32 totallen, const u8 *maskdata,
+			   const u8 *valuedata)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+
+	if (masklen > inst->bytes || valuelen > inst->bytes ||
+	    totallen > inst->bytes || valuelen > masklen)
 		return -EINVAL;
 
-	down(&host->mutex);
-	host->is_open = 1;
-	host->channel = channel;
+	pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata);
+
+	return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0,
+			     inst->scratch, totallen);
+}
+
+static int pmac_i2c_do_read_sub(PMF_STD_ARGS, u8 subaddr, u32 len)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+
+	inst->bytes = len;
+	return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 1, subaddr,
+			     inst->buffer, len);
+}
+
+static int pmac_i2c_do_write_sub(PMF_STD_ARGS, u8 subaddr, u32 len,
+				     const u8 *data)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+
+	return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1,
+			     subaddr, (u8 *)data, len);
+}
+
+static int pmac_i2c_do_set_mode(PMF_STD_ARGS, int mode)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+
+	return pmac_i2c_setmode(inst->bus, mode);
+}
+
+static int pmac_i2c_do_rmw_sub(PMF_STD_ARGS, u8 subaddr, u32 masklen,
+			       u32 valuelen, u32 totallen, const u8 *maskdata,
+			       const u8 *valuedata)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+
+	if (masklen > inst->bytes || valuelen > inst->bytes ||
+	    totallen > inst->bytes || valuelen > masklen)
+		return -EINVAL;
+
+	pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata);
+
+	return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1,
+			     subaddr, inst->scratch, totallen);
+}
+
+static int pmac_i2c_do_mask_and_comp(PMF_STD_ARGS, u32 len,
+				     const u8 *maskdata,
+				     const u8 *valuedata)
+{
+	struct pmac_i2c_pf_inst *inst = instdata;
+	int i, match;
+
+	/* Get return value pointer, it's assumed to be a u32 */
+	if (!args || !args->count || !args->u[0].p)
+		return -EINVAL;
+
+	/* Check buffer */
+	if (len > inst->bytes)
+		return -EINVAL;
+
+	for (i = 0, match = 1; match && i < len; i ++)
+		if ((inst->buffer[i] & maskdata[i]) != valuedata[i])
+			match = 0;
+	*args->u[0].p = match;
+	return 0;
+}
+
+static int pmac_i2c_do_delay(PMF_STD_ARGS, u32 duration)
+{
+	msleep((duration + 999) / 1000);
+	return 0;
+}
+
+
+static struct pmf_handlers pmac_i2c_pfunc_handlers = {
+	.begin			= pmac_i2c_do_begin,
+	.end			= pmac_i2c_do_end,
+	.read_i2c		= pmac_i2c_do_read,
+	.write_i2c		= pmac_i2c_do_write,
+	.rmw_i2c		= pmac_i2c_do_rmw,
+	.read_i2c_sub		= pmac_i2c_do_read_sub,
+	.write_i2c_sub		= pmac_i2c_do_write_sub,
+	.rmw_i2c_sub		= pmac_i2c_do_rmw_sub,
+	.set_i2c_mode		= pmac_i2c_do_set_mode,
+	.mask_and_compare	= pmac_i2c_do_mask_and_comp,
+	.delay			= pmac_i2c_do_delay,
+};
+
+static void __init pmac_i2c_dev_create(struct device_node *np, int quirks)
+{
+	DBG("dev_create(%s)\n", np->full_name);
+
+	pmf_register_driver(np, &pmac_i2c_pfunc_handlers,
+			    (void *)(long)quirks);
+}
+
+static void __init pmac_i2c_dev_init(struct device_node *np, int quirks)
+{
+	DBG("dev_create(%s)\n", np->full_name);
+
+	pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+}
+
+static void pmac_i2c_dev_suspend(struct device_node *np, int quirks)
+{
+	DBG("dev_suspend(%s)\n", np->full_name);
+	pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_SLEEP, NULL);
+}
+
+static void pmac_i2c_dev_resume(struct device_node *np, int quirks)
+{
+	DBG("dev_resume(%s)\n", np->full_name);
+	pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_WAKE, NULL);
+}
+
+void pmac_pfunc_i2c_suspend(void)
+{
+	pmac_i2c_devscan(pmac_i2c_dev_suspend);
+}
+
+void pmac_pfunc_i2c_resume(void)
+{
+	pmac_i2c_devscan(pmac_i2c_dev_resume);
+}
+
+/*
+ * Initialize us: probe all i2c busses on the machine, instantiate
+ * busses and platform functions as needed.
+ */
+/* This is non-static as it might be called early by smp code */
+int __init pmac_i2c_init(void)
+{
+	static int i2c_inited;
+
+	if (i2c_inited)
+		return 0;
+	i2c_inited = 1;
+
+	/* Probe keywest-i2c busses */
+	kw_i2c_probe();
+
+#ifdef CONFIG_ADB_PMU
+	/* Probe PMU i2c busses */
+	pmu_i2c_probe();
+#endif
+
+#ifdef CONFIG_PMAC_SMU
+	/* Probe SMU i2c busses */
+	smu_i2c_probe();
+#endif
+
+	/* Now add plaform functions for some known devices */
+	pmac_i2c_devscan(pmac_i2c_dev_create);
 
 	return 0;
 }
-EXPORT_SYMBOL(pmac_low_i2c_open);
+arch_initcall(pmac_i2c_init);
 
-int pmac_low_i2c_close(struct device_node *np)
+/* Since pmac_i2c_init can be called too early for the platform device
+ * registration, we need to do it at a later time. In our case, subsys
+ * happens to fit well, though I agree it's a bit of a hack...
+ */
+static int __init pmac_i2c_create_platform_devices(void)
 {
-	struct low_i2c_host *host = find_low_i2c_host(np);
+	struct pmac_i2c_bus *bus;
+	int i = 0;
 
-	if (!host)
-		return -ENODEV;
+	/* In the case where we are initialized from smp_init(), we must
+	 * not use the timer (and thus the irq). It's safe from now on
+	 * though
+	 */
+	pmac_i2c_force_poll = 0;
 
-	host->is_open = 0;
-	up(&host->mutex);
+	/* Create platform devices */
+	list_for_each_entry(bus, &pmac_i2c_busses, link) {
+		bus->platform_dev =
+			platform_device_alloc("i2c-powermac", i++);
+		if (bus->platform_dev == NULL)
+			return -ENOMEM;
+		bus->platform_dev->dev.platform_data = bus;
+		platform_device_add(bus->platform_dev);
+	}
+
+	/* Now call platform "init" functions */
+	pmac_i2c_devscan(pmac_i2c_dev_init);
 
 	return 0;
 }
-EXPORT_SYMBOL(pmac_low_i2c_close);
-
-int pmac_low_i2c_setmode(struct device_node *np, int mode)
-{
-	struct low_i2c_host *host = find_low_i2c_host(np);
-
-	if (!host)
-		return -ENODEV;
-	WARN_ON(!host->is_open);
-	host->mode = mode;
-
-	return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_setmode);
-
-int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
-{
-	struct low_i2c_host *host = find_low_i2c_host(np);
-
-	if (!host)
-		return -ENODEV;
-	WARN_ON(!host->is_open);
-
-	return host->func(host, addrdir, subaddr, data, len);
-}
-EXPORT_SYMBOL(pmac_low_i2c_xfer);
-
+subsys_initcall(pmac_i2c_create_platform_devices);
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 4042e2f..3ebd045 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -514,7 +514,7 @@
 #endif
 }
 
-static int __init core99_nvram_setup(struct device_node *dp)
+static int __init core99_nvram_setup(struct device_node *dp, unsigned long addr)
 {
 	int i;
 	u32 gen_bank0, gen_bank1;
@@ -528,7 +528,7 @@
 		printk(KERN_ERR "nvram: can't allocate ram image\n");
 		return -ENOMEM;
 	}
-	nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+	nvram_data = ioremap(addr, NVRAM_SIZE*2);
 	nvram_naddrs = 1; /* Make sure we get the correct case */
 
 	DBG("nvram: Checking bank 0...\n");
@@ -549,6 +549,7 @@
 	ppc_md.nvram_write	= core99_nvram_write;
 	ppc_md.nvram_size	= core99_nvram_size;
 	ppc_md.nvram_sync	= core99_nvram_sync;
+	ppc_md.machine_shutdown	= core99_nvram_sync;
 	/* 
 	 * Maybe we could be smarter here though making an exclusive list
 	 * of known flash chips is a bit nasty as older OF didn't provide us
@@ -569,34 +570,48 @@
 int __init pmac_nvram_init(void)
 {
 	struct device_node *dp;
+	struct resource r1, r2;
+	unsigned int s1 = 0, s2 = 0;
 	int err = 0;
 
 	nvram_naddrs = 0;
 
-	dp = find_devices("nvram");
+	dp = of_find_node_by_name(NULL, "nvram");
 	if (dp == NULL) {
 		printk(KERN_ERR "Can't find NVRAM device\n");
 		return -ENODEV;
 	}
-	nvram_naddrs = dp->n_addrs;
+
+	/* Try to obtain an address */
+	if (of_address_to_resource(dp, 0, &r1) == 0) {
+		nvram_naddrs = 1;
+		s1 = (r1.end - r1.start) + 1;
+		if (of_address_to_resource(dp, 1, &r2) == 0) {
+			nvram_naddrs = 2;
+			s2 = (r2.end - r2.start) + 1;
+		}
+	}
+
 	is_core_99 = device_is_compatible(dp, "nvram,flash");
-	if (is_core_99)
-		err = core99_nvram_setup(dp);
+	if (is_core_99) {
+		err = core99_nvram_setup(dp, r1.start);
+		goto bail;
+	}
+
 #ifdef CONFIG_PPC32
-	else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
-		nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
-				     dp->addrs[0].size);
+	if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+		nvram_data = ioremap(r1.start, s1);
 		nvram_mult = 1;
 		ppc_md.nvram_read_val	= direct_nvram_read_byte;
 		ppc_md.nvram_write_val	= direct_nvram_write_byte;
 	} else if (nvram_naddrs == 1) {
-		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+		nvram_data = ioremap(r1.start, s1);
+		nvram_mult = (s1 + NVRAM_SIZE - 1) / NVRAM_SIZE;
 		ppc_md.nvram_read_val	= direct_nvram_read_byte;
 		ppc_md.nvram_write_val	= direct_nvram_write_byte;
 	} else if (nvram_naddrs == 2) {
-		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+		nvram_addr = ioremap(r1.start, s1);
+		nvram_data = ioremap(r2.start, s2);
 		ppc_md.nvram_read_val	= indirect_nvram_read_byte;
 		ppc_md.nvram_write_val	= indirect_nvram_write_byte;
 	} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
@@ -605,13 +620,15 @@
 		ppc_md.nvram_read_val	= pmu_nvram_read_byte;
 		ppc_md.nvram_write_val	= pmu_nvram_write_byte;
 #endif /* CONFIG_ADB_PMU */
-	}
-#endif
-	else {
+	} else {
 		printk(KERN_ERR "Incompatible type of NVRAM\n");
-		return -ENXIO;
+		err = -ENXIO;
 	}
-	lookup_partitions();
+#endif /* CONFIG_PPC32 */
+bail:
+	of_node_put(dp);
+	if (err == 0)
+		lookup_partitions();
 	return err;
 }
 
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 443be52..f671ed2 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1,7 +1,7 @@
 /*
  * Support for PCI bridges found on Power Macintoshes.
  *
- * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
+ * Copyright (C) 2003-2005 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
  * Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
  *
  * This program is free software; you can redistribute it and/or
@@ -25,7 +25,7 @@
 #include <asm/pmac_feature.h>
 #include <asm/grackle.h>
 #ifdef CONFIG_PPC64
-#include <asm/iommu.h>
+//#include <asm/iommu.h>
 #include <asm/ppc-pci.h>
 #endif
 
@@ -44,6 +44,7 @@
 static int has_uninorth;
 #ifdef CONFIG_PPC64
 static struct pci_controller *u3_agp;
+static struct pci_controller *u4_pcie;
 static struct pci_controller *u3_ht;
 #endif /* CONFIG_PPC64 */
 
@@ -97,11 +98,8 @@
 
 	/* Lookup the "bus-range" property for the hose */
 	bus_range = (int *) get_property(bridge, "bus-range", &len);
-	if (bus_range == NULL || len < 2 * sizeof(int)) {
-		printk(KERN_WARNING "Can't get bus-range for %s\n",
-			       bridge->full_name);
+	if (bus_range == NULL || len < 2 * sizeof(int))
 		return;
-	}
 	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
 }
 
@@ -128,14 +126,14 @@
  */
 
 #define MACRISC_CFA0(devfn, off)	\
-	((1 << (unsigned long)PCI_SLOT(dev_fn)) \
-	| (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
-	| (((unsigned long)(off)) & 0xFCUL))
+	((1 << (unsigned int)PCI_SLOT(dev_fn)) \
+	| (((unsigned int)PCI_FUNC(dev_fn)) << 8) \
+	| (((unsigned int)(off)) & 0xFCUL))
 
 #define MACRISC_CFA1(bus, devfn, off)	\
-	((((unsigned long)(bus)) << 16) \
-	|(((unsigned long)(devfn)) << 8) \
-	|(((unsigned long)(off)) & 0xFCUL) \
+	((((unsigned int)(bus)) << 16) \
+	|(((unsigned int)(devfn)) << 8) \
+	|(((unsigned int)(off)) & 0xFCUL) \
 	|1UL)
 
 static unsigned long macrisc_cfg_access(struct pci_controller* hose,
@@ -168,7 +166,8 @@
 	hose = pci_bus_to_host(bus);
 	if (hose == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-
+	if (offset >= 0x100)
+		return  PCIBIOS_BAD_REGISTER_NUMBER;
 	addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
 	if (!addr)
 		return PCIBIOS_DEVICE_NOT_FOUND;
@@ -199,7 +198,8 @@
 	hose = pci_bus_to_host(bus);
 	if (hose == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-
+	if (offset >= 0x100)
+		return  PCIBIOS_BAD_REGISTER_NUMBER;
 	addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
 	if (!addr)
 		return PCIBIOS_DEVICE_NOT_FOUND;
@@ -234,12 +234,13 @@
 /*
  * Verify that a specific (bus, dev_fn) exists on chaos
  */
-static int
-chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
+static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
 {
 	struct device_node *np;
 	u32 *vendor, *device;
 
+	if (offset >= 0x100)
+		return  PCIBIOS_BAD_REGISTER_NUMBER;
 	np = pci_busdev_to_OF_node(bus, devfn);
 	if (np == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
@@ -285,15 +286,13 @@
 };
 
 static void __init setup_chaos(struct pci_controller *hose,
-			       struct reg_property *addr)
+			       struct resource *addr)
 {
 	/* assume a `chaos' bridge */
 	hose->ops = &chaos_pci_ops;
-	hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+	hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+	hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
 }
-#else
-#define setup_chaos(hose, addr)
 #endif /* CONFIG_PPC32 */
 
 #ifdef CONFIG_PPC64
@@ -326,7 +325,7 @@
 	else
 		busdn = hose->arch_data;
 	for (dn = busdn->child; dn; dn = dn->sibling)
-		if (dn->data && PCI_DN(dn)->devfn == devfn)
+		if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn)
 			break;
 	if (dn == NULL)
 		return -1;
@@ -343,10 +342,10 @@
 }
 
 #define U3_HT_CFA0(devfn, off)		\
-		((((unsigned long)devfn) << 8) | offset)
+		((((unsigned int)devfn) << 8) | offset)
 #define U3_HT_CFA1(bus, devfn, off)	\
 		(U3_HT_CFA0(devfn, off) \
-		+ (((unsigned long)bus) << 16) \
+		+ (((unsigned int)bus) << 16) \
 		+ 0x01000000UL)
 
 static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
@@ -356,9 +355,11 @@
 		/* For now, we don't self probe U3 HT bridge */
 		if (PCI_SLOT(devfn) == 0)
 			return 0;
-		return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
+		return ((unsigned long)hose->cfg_data) +
+			U3_HT_CFA0(devfn, offset);
 	} else
-		return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset);
+		return ((unsigned long)hose->cfg_data) +
+			U3_HT_CFA1(bus, devfn, offset);
 }
 
 static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
@@ -370,7 +371,8 @@
 	hose = pci_bus_to_host(bus);
 	if (hose == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-
+	if (offset >= 0x100)
+		return  PCIBIOS_BAD_REGISTER_NUMBER;
 	addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
 	if (!addr)
 		return PCIBIOS_DEVICE_NOT_FOUND;
@@ -419,7 +421,8 @@
 	hose = pci_bus_to_host(bus);
 	if (hose == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-
+	if (offset >= 0x100)
+		return  PCIBIOS_BAD_REGISTER_NUMBER;
 	addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
 	if (!addr)
 		return PCIBIOS_DEVICE_NOT_FOUND;
@@ -459,6 +462,112 @@
 	u3_ht_read_config,
 	u3_ht_write_config
 };
+
+#define U4_PCIE_CFA0(devfn, off)	\
+	((1 << ((unsigned int)PCI_SLOT(dev_fn)))	\
+	 | (((unsigned int)PCI_FUNC(dev_fn)) << 8)	\
+	 | ((((unsigned int)(off)) >> 8) << 28) \
+	 | (((unsigned int)(off)) & 0xfcU))
+
+#define U4_PCIE_CFA1(bus, devfn, off)	\
+	((((unsigned int)(bus)) << 16) \
+	 |(((unsigned int)(devfn)) << 8)	\
+	 | ((((unsigned int)(off)) >> 8) << 28) \
+	 |(((unsigned int)(off)) & 0xfcU)	\
+	 |1UL)
+
+static unsigned long u4_pcie_cfg_access(struct pci_controller* hose,
+					u8 bus, u8 dev_fn, int offset)
+{
+	unsigned int caddr;
+
+	if (bus == hose->first_busno) {
+		caddr = U4_PCIE_CFA0(dev_fn, offset);
+	} else
+		caddr = U4_PCIE_CFA1(bus, dev_fn, offset);
+
+	/* Uninorth will return garbage if we don't read back the value ! */
+	do {
+		out_le32(hose->cfg_addr, caddr);
+	} while (in_le32(hose->cfg_addr) != caddr);
+
+	offset &= 0x03;
+	return ((unsigned long)hose->cfg_data) + offset;
+}
+
+static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
+			       int offset, int len, u32 *val)
+{
+	struct pci_controller *hose;
+	unsigned long addr;
+
+	hose = pci_bus_to_host(bus);
+	if (hose == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (offset >= 0x1000)
+		return  PCIBIOS_BAD_REGISTER_NUMBER;
+	addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *)addr);
+		break;
+	case 2:
+		*val = in_le16((u16 *)addr);
+		break;
+	default:
+		*val = in_le32((u32 *)addr);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
+				int offset, int len, u32 val)
+{
+	struct pci_controller *hose;
+	unsigned long addr;
+
+	hose = pci_bus_to_host(bus);
+	if (hose == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (offset >= 0x1000)
+		return  PCIBIOS_BAD_REGISTER_NUMBER;
+	addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	switch (len) {
+	case 1:
+		out_8((u8 *)addr, val);
+		(void) in_8((u8 *)addr);
+		break;
+	case 2:
+		out_le16((u16 *)addr, val);
+		(void) in_le16((u16 *)addr);
+		break;
+	default:
+		out_le32((u32 *)addr, val);
+		(void) in_le32((u32 *)addr);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u4_pcie_pci_ops =
+{
+	u4_pcie_read_config,
+	u4_pcie_write_config
+};
+
 #endif /* CONFIG_PPC64 */
 
 #ifdef CONFIG_PPC32
@@ -532,7 +641,8 @@
 	}
 	if (early_read_config_word(hose, bus, devfn,
 				   PCI_BRIDGE_CONTROL, &val) < 0) {
-		printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+		printk(KERN_ERR "init_p2pbridge: couldn't read bridge"
+		       " control\n");
 		return;
 	}
 	val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
@@ -576,36 +686,38 @@
 			continue;
 		early_read_config_dword(hose, bus, devfn, 0xe4, &data);
 		if (data & 1UL) {
-			printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n");
+			printk("Found NEC PD720100A USB2 chip with disabled"
+			       " EHCI, fixing up...\n");
 			data &= ~1UL;
 			early_write_config_dword(hose, bus, devfn, 0xe4, data);
-			early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE,
+			early_write_config_byte(hose, bus,
+						devfn | 2, PCI_INTERRUPT_LINE,
 				nec->intrs[0].line);
 		}
 	}
 }
 
 static void __init setup_bandit(struct pci_controller *hose,
-				struct reg_property *addr)
+				struct resource *addr)
 {
 	hose->ops = &macrisc_pci_ops;
-	hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+	hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+	hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
 	init_bandit(hose);
 }
 
 static int __init setup_uninorth(struct pci_controller *hose,
-				 struct reg_property *addr)
+				 struct resource *addr)
 {
 	pci_assign_all_buses = 1;
 	has_uninorth = 1;
 	hose->ops = &macrisc_pci_ops;
-	hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+	hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+	hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
 	/* We "know" that the bridge at f2000000 has the PCI slots. */
-	return addr->address == 0xf2000000;
+	return addr->start == 0xf2000000;
 }
-#endif
+#endif /* CONFIG_PPC32 */
 
 #ifdef CONFIG_PPC64
 static void __init setup_u3_agp(struct pci_controller* hose)
@@ -625,15 +737,36 @@
 	hose->ops = &macrisc_pci_ops;
 	hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
 	hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
-
 	u3_agp = hose;
 }
 
+static void __init setup_u4_pcie(struct pci_controller* hose)
+{
+	/* We currently only implement the "non-atomic" config space, to
+	 * be optimised later.
+	 */
+	hose->ops = &u4_pcie_pci_ops;
+	hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+	hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+	/* The bus contains a bridge from root -> device, we need to
+	 * make it visible on bus 0 so that we pick the right type
+	 * of config cycles. If we didn't, we would have to force all
+	 * config cycles to be type 1. So we override the "bus-range"
+	 * property here
+	 */
+	hose->first_busno = 0x00;
+	hose->last_busno = 0xff;
+	u4_pcie = hose;
+}
+
 static void __init setup_u3_ht(struct pci_controller* hose)
 {
 	struct device_node *np = (struct device_node *)hose->arch_data;
+	struct pci_controller *other = NULL;
 	int i, cur;
 
+
 	hose->ops = &u3_ht_pci_ops;
 
 	/* We hard code the address because of the different size of
@@ -667,11 +800,20 @@
 
 	u3_ht = hose;
 
-	if (u3_agp == NULL) {
-		DBG("U3 has no AGP, using full resource range\n");
+	if (u3_agp != NULL)
+		other = u3_agp;
+	else if (u4_pcie != NULL)
+		other = u4_pcie;
+
+	if (other == NULL) {
+		DBG("U3/4 has no AGP/PCIE, using full resource range\n");
 		return;
 	}
 
+	/* Fixup bus range vs. PCIE */
+	if (u4_pcie)
+		hose->last_busno = u4_pcie->first_busno - 1;
+
 	/* We "remove" the AGP resources from the resources allocated to HT,
 	 * that is we create "holes". However, that code does assumptions
 	 * that so far happen to be true (cross fingers...), typically that
@@ -679,7 +821,7 @@
 	 */
 	cur = 0;
 	for (i=0; i<3; i++) {
-		struct resource *res = &u3_agp->mem_resources[i];
+		struct resource *res = &other->mem_resources[i];
 		if (res->flags != IORESOURCE_MEM)
 			continue;
 		/* We don't care about "fine" resources */
@@ -722,7 +864,7 @@
 		hose->mem_resources[cur-1].end = res->start - 1;
 	}
 }
-#endif
+#endif /* CONFIG_PPC64 */
 
 /*
  * We assume that if we have a G3 powermac, we have one bridge called
@@ -733,24 +875,17 @@
 {
 	int len;
 	struct pci_controller *hose;
-#ifdef CONFIG_PPC32
-	struct reg_property *addr;
-#endif
+	struct resource rsrc;
 	char *disp_name;
 	int *bus_range;
-	int primary = 1;
+	int primary = 1, has_address = 0;
 
 	DBG("Adding PCI host bridge %s\n", dev->full_name);
 
-#ifdef CONFIG_PPC32
-	/* XXX fix this */
-	addr = (struct reg_property *) get_property(dev, "reg", &len);
-	if (addr == NULL || len < sizeof(*addr)) {
-		printk(KERN_WARNING "Can't use %s: no address\n",
-		       dev->full_name);
-		return -ENODEV;
-	}
-#endif
+	/* Fetch host bridge registers address */
+	has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+	/* Get bus range if any */
 	bus_range = (int *) get_property(dev, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		printk(KERN_WARNING "Can't get bus-range for %s, assume"
@@ -770,6 +905,8 @@
 	hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
 	disp_name = NULL;
+
+	/* 64 bits only bridges */
 #ifdef CONFIG_PPC64
 	if (device_is_compatible(dev, "u3-agp")) {
 		setup_u3_agp(hose);
@@ -779,28 +916,37 @@
 		setup_u3_ht(hose);
 		disp_name = "U3-HT";
 		primary = 1;
+	} else if (device_is_compatible(dev, "u4-pcie")) {
+		setup_u4_pcie(hose);
+		disp_name = "U4-PCIE";
+		primary = 0;
 	}
-	printk(KERN_INFO "Found %s PCI host bridge.  Firmware bus number: %d->%d\n",
-		disp_name, hose->first_busno, hose->last_busno);
-#else
+	printk(KERN_INFO "Found %s PCI host bridge.  Firmware bus number:"
+	       " %d->%d\n", disp_name, hose->first_busno, hose->last_busno);
+#endif /* CONFIG_PPC64 */
+
+	/* 32 bits only bridges */
+#ifdef CONFIG_PPC32
 	if (device_is_compatible(dev, "uni-north")) {
-		primary = setup_uninorth(hose, addr);
+		primary = setup_uninorth(hose, &rsrc);
 		disp_name = "UniNorth";
 	} else if (strcmp(dev->name, "pci") == 0) {
 		/* XXX assume this is a mpc106 (grackle) */
 		setup_grackle(hose);
 		disp_name = "Grackle (MPC106)";
 	} else if (strcmp(dev->name, "bandit") == 0) {
-		setup_bandit(hose, addr);
+		setup_bandit(hose, &rsrc);
 		disp_name = "Bandit";
 	} else if (strcmp(dev->name, "chaos") == 0) {
-		setup_chaos(hose, addr);
+		setup_chaos(hose, &rsrc);
 		disp_name = "Chaos";
 		primary = 0;
 	}
-	printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n",
-		disp_name, addr->address, hose->first_busno, hose->last_busno);
-#endif
+	printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. "
+	       "Firmware bus number: %d->%d\n",
+		disp_name, rsrc.start, hose->first_busno, hose->last_busno);
+#endif /* CONFIG_PPC32 */
+
 	DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
 		hose, hose->cfg_addr, hose->cfg_data);
 
@@ -814,8 +960,7 @@
 	return 0;
 }
 
-static void __init
-pcibios_fixup_OF_interrupts(void)
+static void __init pcibios_fixup_OF_interrupts(void)
 {
 	struct pci_dev* dev = NULL;
 
@@ -835,8 +980,7 @@
 	}
 }
 
-void __init
-pmac_pcibios_fixup(void)
+void __init pmac_pcibios_fixup(void)
 {
 	/* Fixup interrupts according to OF tree */
 	pcibios_fixup_OF_interrupts();
@@ -899,6 +1043,8 @@
 		pci_setup_phb_io(u3_ht, 1);
 	if (u3_agp)
 		pci_setup_phb_io(u3_agp, 0);
+	if (u4_pcie)
+		pci_setup_phb_io(u4_pcie, 0);
 
 	/*
 	 * On ppc64, fixup the IO resources on our host bridges as
@@ -911,7 +1057,8 @@
 
 	/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
 	 * assume there is no P2P bridge on the AGP bus, which should be a
-	 * safe assumptions hopefully.
+	 * safe assumptions for now. We should do something better in the
+	 * future though
 	 */
 	if (u3_agp) {
 		struct device_node *np = u3_agp->arch_data;
@@ -919,7 +1066,6 @@
 		for (np = np->child; np; np = np->sibling)
 			PCI_DN(np)->busno = 0xf0;
 	}
-
 	/* pmac_check_ht_link(); */
 
 	/* Tell pci.c to not use the common resource allocation mechanism */
@@ -1126,7 +1272,8 @@
  good:
 	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
 	if ((progif & 5) != 5) {
-		printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
+		printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n",
+		       pci_name(dev));
 		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
 		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
 		    (progif & 5) != 5)
@@ -1152,7 +1299,8 @@
 		for (i = 0; i < 6; i++) {
 			dev->resource[i].start = dev->resource[i].end = 0;
 			dev->resource[i].flags = 0;
-			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
+					       0);
 		}
 	} else {
 		pci_read_config_word(dev, PCI_COMMAND, &cmd);
@@ -1161,7 +1309,8 @@
 		for (i = 0; i < 5; i++) {
 			dev->resource[i].start = dev->resource[i].end = 0;
 			dev->resource[i].flags = 0;
-			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
+					       0);
 		}
 	}
 }
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
new file mode 100644
index 0000000..4ffd2a9
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -0,0 +1,405 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+
+#define DBG(fmt...)	printk(fmt)
+
+static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs)
+{
+	pmf_do_irq(data);
+
+	return IRQ_HANDLED;
+}
+
+static int macio_do_gpio_irq_enable(struct pmf_function *func)
+{
+	if (func->node->n_intrs < 1)
+		return -EINVAL;
+
+	return request_irq(func->node->intrs[0].line, macio_gpio_irq, 0,
+			   func->node->name, func);
+}
+
+static int macio_do_gpio_irq_disable(struct pmf_function *func)
+{
+	if (func->node->n_intrs < 1)
+		return -EINVAL;
+
+	free_irq(func->node->intrs[0].line, func);
+	return 0;
+}
+
+static int macio_do_gpio_write(PMF_STD_ARGS, u8 value, u8 mask)
+{
+	u8 __iomem *addr = (u8 __iomem *)func->driver_data;
+	unsigned long flags;
+	u8 tmp;
+
+	/* Check polarity */
+	if (args && args->count && !args->u[0].v)
+		value = ~value;
+
+	/* Toggle the GPIO */
+	spin_lock_irqsave(&feature_lock, flags);
+	tmp = readb(addr);
+	tmp = (tmp & ~mask) | (value & mask);
+	DBG("Do write 0x%02x to GPIO %s (%p)\n",
+	    tmp, func->node->full_name, addr);
+	writeb(tmp, addr);
+	spin_unlock_irqrestore(&feature_lock, flags);
+
+	return 0;
+}
+
+static int macio_do_gpio_read(PMF_STD_ARGS, u8 mask, int rshift, u8 xor)
+{
+	u8 __iomem *addr = (u8 __iomem *)func->driver_data;
+	u32 value;
+
+	/* Check if we have room for reply */
+	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+		return -EINVAL;
+
+	value = readb(addr);
+	*args->u[0].p = ((value & mask) >> rshift) ^ xor;
+
+	return 0;
+}
+
+static int macio_do_delay(PMF_STD_ARGS, u32 duration)
+{
+	/* assume we can sleep ! */
+	msleep((duration + 999) / 1000);
+	return 0;
+}
+
+static struct pmf_handlers macio_gpio_handlers = {
+	.irq_enable	= macio_do_gpio_irq_enable,
+	.irq_disable	= macio_do_gpio_irq_disable,
+	.write_gpio	= macio_do_gpio_write,
+	.read_gpio	= macio_do_gpio_read,
+	.delay		= macio_do_delay,
+};
+
+static void macio_gpio_init_one(struct macio_chip *macio)
+{
+	struct device_node *gparent, *gp;
+
+	/*
+	 * Find the "gpio" parent node
+	 */
+
+	for (gparent = NULL;
+	     (gparent = of_get_next_child(macio->of_node, gparent)) != NULL;)
+		if (strcmp(gparent->name, "gpio") == 0)
+			break;
+	if (gparent == NULL)
+		return;
+
+	DBG("Installing GPIO functions for macio %s\n",
+	    macio->of_node->full_name);
+
+	/*
+	 * Ok, got one, we dont need anything special to track them down, so
+	 * we just create them all
+	 */
+	for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) {
+		u32 *reg = (u32 *)get_property(gp, "reg", NULL);
+		unsigned long offset;
+		if (reg == NULL)
+			continue;
+		offset = *reg;
+		/* Deal with old style device-tree. We can safely hard code the
+		 * offset for now too even if it's a bit gross ...
+		 */
+		if (offset < 0x50)
+			offset += 0x50;
+		offset += (unsigned long)macio->base;
+		pmf_register_driver(gp, &macio_gpio_handlers, (void *)offset);
+	}
+
+	DBG("Calling initial GPIO functions for macio %s\n",
+	    macio->of_node->full_name);
+
+	/* And now we run all the init ones */
+	for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;)
+		pmf_do_functions(gp, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+
+	/* Note: We do not at this point implement the "at sleep" or "at wake"
+	 * functions. I yet to find any for GPIOs anyway
+	 */
+}
+
+static int macio_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
+{
+	struct macio_chip *macio = func->driver_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&feature_lock, flags);
+	MACIO_OUT32(offset, (MACIO_IN32(offset) & ~mask) | (value & mask));
+	spin_unlock_irqrestore(&feature_lock, flags);
+	return 0;
+}
+
+static int macio_do_read_reg32(PMF_STD_ARGS, u32 offset)
+{
+	struct macio_chip *macio = func->driver_data;
+
+	/* Check if we have room for reply */
+	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+		return -EINVAL;
+
+	*args->u[0].p = MACIO_IN32(offset);
+	return 0;
+}
+
+static int macio_do_write_reg8(PMF_STD_ARGS, u32 offset, u8 value, u8 mask)
+{
+	struct macio_chip *macio = func->driver_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&feature_lock, flags);
+	MACIO_OUT8(offset, (MACIO_IN8(offset) & ~mask) | (value & mask));
+	spin_unlock_irqrestore(&feature_lock, flags);
+	return 0;
+}
+
+static int macio_do_read_reg8(PMF_STD_ARGS, u32 offset)
+{
+	struct macio_chip *macio = func->driver_data;
+
+	/* Check if we have room for reply */
+	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+		return -EINVAL;
+
+	*((u8 *)(args->u[0].p)) = MACIO_IN8(offset);
+	return 0;
+}
+
+static int macio_do_read_reg32_msrx(PMF_STD_ARGS, u32 offset, u32 mask,
+				    u32 shift, u32 xor)
+{
+	struct macio_chip *macio = func->driver_data;
+
+	/* Check if we have room for reply */
+	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+		return -EINVAL;
+
+	*args->u[0].p = ((MACIO_IN32(offset) & mask) >> shift) ^ xor;
+	return 0;
+}
+
+static int macio_do_read_reg8_msrx(PMF_STD_ARGS, u32 offset, u32 mask,
+				   u32 shift, u32 xor)
+{
+	struct macio_chip *macio = func->driver_data;
+
+	/* Check if we have room for reply */
+	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+		return -EINVAL;
+
+	*((u8 *)(args->u[0].p)) = ((MACIO_IN8(offset) & mask) >> shift) ^ xor;
+	return 0;
+}
+
+static int macio_do_write_reg32_slm(PMF_STD_ARGS, u32 offset, u32 shift,
+				    u32 mask)
+{
+	struct macio_chip *macio = func->driver_data;
+	unsigned long flags;
+	u32 tmp, val;
+
+	/* Check args */
+	if (args == NULL || args->count == 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&feature_lock, flags);
+	tmp = MACIO_IN32(offset);
+	val = args->u[0].v << shift;
+	tmp = (tmp & ~mask) | (val & mask);
+	MACIO_OUT32(offset, tmp);
+	spin_unlock_irqrestore(&feature_lock, flags);
+	return 0;
+}
+
+static int macio_do_write_reg8_slm(PMF_STD_ARGS, u32 offset, u32 shift,
+				   u32 mask)
+{
+	struct macio_chip *macio = func->driver_data;
+	unsigned long flags;
+	u32 tmp, val;
+
+	/* Check args */
+	if (args == NULL || args->count == 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&feature_lock, flags);
+	tmp = MACIO_IN8(offset);
+	val = args->u[0].v << shift;
+	tmp = (tmp & ~mask) | (val & mask);
+	MACIO_OUT8(offset, tmp);
+	spin_unlock_irqrestore(&feature_lock, flags);
+	return 0;
+}
+
+static struct pmf_handlers macio_mmio_handlers = {
+	.write_reg32		= macio_do_write_reg32,
+	.read_reg32		= macio_do_read_reg32,
+	.write_reg8		= macio_do_write_reg8,
+	.read_reg32		= macio_do_read_reg8,
+	.read_reg32_msrx	= macio_do_read_reg32_msrx,
+	.read_reg8_msrx		= macio_do_read_reg8_msrx,
+	.write_reg32_slm	= macio_do_write_reg32_slm,
+	.write_reg8_slm		= macio_do_write_reg8_slm,
+	.delay			= macio_do_delay,
+};
+
+static void macio_mmio_init_one(struct macio_chip *macio)
+{
+	DBG("Installing MMIO functions for macio %s\n",
+	    macio->of_node->full_name);
+
+	pmf_register_driver(macio->of_node, &macio_mmio_handlers, macio);
+}
+
+static struct device_node *unin_hwclock;
+
+static int unin_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&feature_lock, flags);
+	/* This is fairly bogus in darwin, but it should work for our needs
+	 * implemeted that way:
+	 */
+	UN_OUT(offset, (UN_IN(offset) & ~mask) | (value & mask));
+	spin_unlock_irqrestore(&feature_lock, flags);
+	return 0;
+}
+
+
+static struct pmf_handlers unin_mmio_handlers = {
+	.write_reg32		= unin_do_write_reg32,
+	.delay			= macio_do_delay,
+};
+
+static void uninorth_install_pfunc(void)
+{
+	struct device_node *np;
+
+	DBG("Installing functions for UniN %s\n",
+	    uninorth_node->full_name);
+
+	/*
+	 * Install handlers for the bridge itself
+	 */
+	pmf_register_driver(uninorth_node, &unin_mmio_handlers, NULL);
+	pmf_do_functions(uninorth_node, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+
+
+	/*
+	 * Install handlers for the hwclock child if any
+	 */
+	for (np = NULL; (np = of_get_next_child(uninorth_node, np)) != NULL;)
+		if (strcmp(np->name, "hw-clock") == 0) {
+			unin_hwclock = np;
+			break;
+		}
+	if (unin_hwclock) {
+		DBG("Installing functions for UniN clock %s\n",
+		    unin_hwclock->full_name);
+		pmf_register_driver(unin_hwclock, &unin_mmio_handlers, NULL);
+		pmf_do_functions(unin_hwclock, NULL, 0, PMF_FLAGS_ON_INIT,
+				 NULL);
+	}
+}
+
+/* We export this as the SMP code might init us early */
+int __init pmac_pfunc_base_install(void)
+{
+	static int pfbase_inited;
+	int i;
+
+	if (pfbase_inited)
+		return 0;
+	pfbase_inited = 1;
+
+
+	DBG("Installing base platform functions...\n");
+
+	/*
+	 * Locate mac-io chips and install handlers
+	 */
+	for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+		if (macio_chips[i].of_node) {
+			macio_mmio_init_one(&macio_chips[i]);
+			macio_gpio_init_one(&macio_chips[i]);
+		}
+	}
+
+	/*
+	 * Install handlers for northbridge and direct mapped hwclock
+	 * if any. We do not implement the config space access callback
+	 * which is only ever used for functions that we do not call in
+	 * the current driver (enabling/disabling cells in U2, mostly used
+	 * to restore the PCI settings, we do that differently)
+	 */
+	if (uninorth_node && uninorth_base)
+		uninorth_install_pfunc();
+
+	DBG("All base functions installed\n");
+
+	return 0;
+}
+
+arch_initcall(pmac_pfunc_base_install);
+
+#ifdef CONFIG_PM
+
+/* Those can be called by pmac_feature. Ultimately, I should use a sysdev
+ * or a device, but for now, that's good enough until I sort out some
+ * ordering issues. Also, we do not bother with GPIOs, as so far I yet have
+ * to see a case where a GPIO function has the on-suspend or on-resume bit
+ */
+void pmac_pfunc_base_suspend(void)
+{
+	int i;
+
+	for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+		if (macio_chips[i].of_node)
+			pmf_do_functions(macio_chips[i].of_node, NULL, 0,
+					 PMF_FLAGS_ON_SLEEP, NULL);
+	}
+	if (uninorth_node)
+		pmf_do_functions(uninorth_node, NULL, 0,
+				 PMF_FLAGS_ON_SLEEP, NULL);
+	if (unin_hwclock)
+		pmf_do_functions(unin_hwclock, NULL, 0,
+				 PMF_FLAGS_ON_SLEEP, NULL);
+}
+
+void pmac_pfunc_base_resume(void)
+{
+	int i;
+
+	if (unin_hwclock)
+		pmf_do_functions(unin_hwclock, NULL, 0,
+				 PMF_FLAGS_ON_WAKE, NULL);
+	if (uninorth_node)
+		pmf_do_functions(uninorth_node, NULL, 0,
+				 PMF_FLAGS_ON_WAKE, NULL);
+	for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+		if (macio_chips[i].of_node)
+			pmf_do_functions(macio_chips[i].of_node, NULL, 0,
+					 PMF_FLAGS_ON_WAKE, NULL);
+	}
+}
+
+#endif /* CONFIG_PM */
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
new file mode 100644
index 0000000..c32c623
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -0,0 +1,989 @@
+/*
+ *
+ * FIXME: Properly make this race free with refcounting etc...
+ *
+ * FIXME: LOCKING !!!
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/semaphore.h>
+#include <asm/prom.h>
+#include <asm/pmac_pfunc.h>
+
+/* Debug */
+#define LOG_PARSE(fmt...)
+#define LOG_ERROR(fmt...)	printk(fmt)
+#define LOG_BLOB(t,b,c)
+#define DBG(fmt...)		printk(fmt)
+
+/* Command numbers */
+#define PMF_CMD_LIST			0
+#define PMF_CMD_WRITE_GPIO		1
+#define PMF_CMD_READ_GPIO		2
+#define PMF_CMD_WRITE_REG32		3
+#define PMF_CMD_READ_REG32		4
+#define PMF_CMD_WRITE_REG16		5
+#define PMF_CMD_READ_REG16		6
+#define PMF_CMD_WRITE_REG8		7
+#define PMF_CMD_READ_REG8		8
+#define PMF_CMD_DELAY			9
+#define PMF_CMD_WAIT_REG32		10
+#define PMF_CMD_WAIT_REG16		11
+#define PMF_CMD_WAIT_REG8		12
+#define PMF_CMD_READ_I2C		13
+#define PMF_CMD_WRITE_I2C		14
+#define PMF_CMD_RMW_I2C			15
+#define PMF_CMD_GEN_I2C			16
+#define PMF_CMD_SHIFT_BYTES_RIGHT	17
+#define PMF_CMD_SHIFT_BYTES_LEFT	18
+#define PMF_CMD_READ_CFG		19
+#define PMF_CMD_WRITE_CFG		20
+#define PMF_CMD_RMW_CFG			21
+#define PMF_CMD_READ_I2C_SUBADDR	22
+#define PMF_CMD_WRITE_I2C_SUBADDR	23
+#define PMF_CMD_SET_I2C_MODE		24
+#define PMF_CMD_RMW_I2C_SUBADDR		25
+#define PMF_CMD_READ_REG32_MASK_SHR_XOR	26
+#define PMF_CMD_READ_REG16_MASK_SHR_XOR	27
+#define PMF_CMD_READ_REG8_MASK_SHR_XOR	28
+#define PMF_CMD_WRITE_REG32_SHL_MASK	29
+#define PMF_CMD_WRITE_REG16_SHL_MASK	30
+#define PMF_CMD_WRITE_REG8_SHL_MASK	31
+#define PMF_CMD_MASK_AND_COMPARE	32
+#define PMF_CMD_COUNT			33
+
+/* This structure holds the state of the parser while walking through
+ * a function definition
+ */
+struct pmf_cmd {
+	const void		*cmdptr;
+	const void		*cmdend;
+	struct pmf_function	*func;
+	void			*instdata;
+	struct pmf_args		*args;
+	int			error;
+};
+
+#if 0
+/* Debug output */
+static void print_blob(const char *title, const void *blob, int bytes)
+{
+	printk("%s", title);
+	while(bytes--) {
+		printk("%02x ", *((u8 *)blob));
+		blob += 1;
+	}
+	printk("\n");
+}
+#endif
+
+/*
+ * Parser helpers
+ */
+
+static u32 pmf_next32(struct pmf_cmd *cmd)
+{
+	u32 value;
+	if ((cmd->cmdend - cmd->cmdptr) < 4) {
+		cmd->error = 1;
+		return 0;
+	}
+	value = *((u32 *)cmd->cmdptr);
+	cmd->cmdptr += 4;
+	return value;
+}
+
+static const void* pmf_next_blob(struct pmf_cmd *cmd, int count)
+{
+	const void *value;
+	if ((cmd->cmdend - cmd->cmdptr) < count) {
+		cmd->error = 1;
+		return NULL;
+	}
+	value = cmd->cmdptr;
+	cmd->cmdptr += count;
+	return value;
+}
+
+/*
+ * Individual command parsers
+ */
+
+#define PMF_PARSE_CALL(name, cmd, handlers, p...) \
+	do { \
+		if (cmd->error) \
+			return -ENXIO; \
+		if (handlers == NULL) \
+			return 0; \
+		if (handlers->name)				      \
+			return handlers->name(cmd->func, cmd->instdata, \
+					      cmd->args, p);	      \
+		return -1; \
+	} while(0) \
+
+
+static int pmf_parser_write_gpio(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u8 value = (u8)pmf_next32(cmd);
+	u8 mask = (u8)pmf_next32(cmd);
+
+	LOG_PARSE("pmf: write_gpio(value: %02x, mask: %02x)\n", value, mask);
+
+	PMF_PARSE_CALL(write_gpio, cmd, h, value, mask);
+}
+
+static int pmf_parser_read_gpio(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u8 mask = (u8)pmf_next32(cmd);
+	int rshift = (int)pmf_next32(cmd);
+	u8 xor = (u8)pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_gpio(mask: %02x, rshift: %d, xor: %02x)\n",
+		  mask, rshift, xor);
+
+	PMF_PARSE_CALL(read_gpio, cmd, h, mask, rshift, xor);
+}
+
+static int pmf_parser_write_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 value = pmf_next32(cmd);
+	u32 mask = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: write_reg32(offset: %08x, value: %08x, mask: %08x)\n",
+		  offset, value, mask);
+
+	PMF_PARSE_CALL(write_reg32, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_reg32(offset: %08x)\n", offset);
+
+	PMF_PARSE_CALL(read_reg32, cmd, h, offset);
+}
+
+
+static int pmf_parser_write_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u16 value = (u16)pmf_next32(cmd);
+	u16 mask = (u16)pmf_next32(cmd);
+
+	LOG_PARSE("pmf: write_reg16(offset: %08x, value: %04x, mask: %04x)\n",
+		  offset, value, mask);
+
+	PMF_PARSE_CALL(write_reg16, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_reg16(offset: %08x)\n", offset);
+
+	PMF_PARSE_CALL(read_reg16, cmd, h, offset);
+}
+
+
+static int pmf_parser_write_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u8 value = (u16)pmf_next32(cmd);
+	u8 mask = (u16)pmf_next32(cmd);
+
+	LOG_PARSE("pmf: write_reg8(offset: %08x, value: %02x, mask: %02x)\n",
+		  offset, value, mask);
+
+	PMF_PARSE_CALL(write_reg8, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_reg8(offset: %08x)\n", offset);
+
+	PMF_PARSE_CALL(read_reg8, cmd, h, offset);
+}
+
+static int pmf_parser_delay(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 duration = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: delay(duration: %d us)\n", duration);
+
+	PMF_PARSE_CALL(delay, cmd, h, duration);
+}
+
+static int pmf_parser_wait_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 value = pmf_next32(cmd);
+	u32 mask = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: wait_reg32(offset: %08x, comp_value: %08x,mask: %08x)\n",
+		  offset, value, mask);
+
+	PMF_PARSE_CALL(wait_reg32, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_wait_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u16 value = (u16)pmf_next32(cmd);
+	u16 mask = (u16)pmf_next32(cmd);
+
+	LOG_PARSE("pmf: wait_reg16(offset: %08x, comp_value: %04x,mask: %04x)\n",
+		  offset, value, mask);
+
+	PMF_PARSE_CALL(wait_reg16, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_wait_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u8 value = (u8)pmf_next32(cmd);
+	u8 mask = (u8)pmf_next32(cmd);
+
+	LOG_PARSE("pmf: wait_reg8(offset: %08x, comp_value: %02x,mask: %02x)\n",
+		  offset, value, mask);
+
+	PMF_PARSE_CALL(wait_reg8, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 bytes = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_i2c(bytes: %ud)\n", bytes);
+
+	PMF_PARSE_CALL(read_i2c, cmd, h, bytes);
+}
+
+static int pmf_parser_write_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 bytes = pmf_next32(cmd);
+	const void *blob = pmf_next_blob(cmd, bytes);
+
+	LOG_PARSE("pmf: write_i2c(bytes: %ud) ...\n", bytes);
+	LOG_BLOB("pmf:   data: \n", blob, bytes);
+
+	PMF_PARSE_CALL(write_i2c, cmd, h, bytes, blob);
+}
+
+
+static int pmf_parser_rmw_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 maskbytes = pmf_next32(cmd);
+	u32 valuesbytes = pmf_next32(cmd);
+	u32 totalbytes = pmf_next32(cmd);
+	const void *maskblob = pmf_next_blob(cmd, maskbytes);
+	const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+	LOG_PARSE("pmf: rmw_i2c(maskbytes: %ud, valuebytes: %ud, "
+		  "totalbytes: %d) ...\n",
+		  maskbytes, valuesbytes, totalbytes);
+	LOG_BLOB("pmf:   mask data: \n", maskblob, maskbytes);
+	LOG_BLOB("pmf:   values data: \n", valuesblob, valuesbytes);
+
+	PMF_PARSE_CALL(rmw_i2c, cmd, h, maskbytes, valuesbytes, totalbytes,
+		       maskblob, valuesblob);
+}
+
+static int pmf_parser_read_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 bytes = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_cfg(offset: %x, bytes: %ud)\n", offset, bytes);
+
+	PMF_PARSE_CALL(read_cfg, cmd, h, offset, bytes);
+}
+
+
+static int pmf_parser_write_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 bytes = pmf_next32(cmd);
+	const void *blob = pmf_next_blob(cmd, bytes);
+
+	LOG_PARSE("pmf: write_cfg(offset: %x, bytes: %ud)\n", offset, bytes);
+	LOG_BLOB("pmf:   data: \n", blob, bytes);
+
+	PMF_PARSE_CALL(write_cfg, cmd, h, offset, bytes, blob);
+}
+
+static int pmf_parser_rmw_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 maskbytes = pmf_next32(cmd);
+	u32 valuesbytes = pmf_next32(cmd);
+	u32 totalbytes = pmf_next32(cmd);
+	const void *maskblob = pmf_next_blob(cmd, maskbytes);
+	const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+	LOG_PARSE("pmf: rmw_cfg(maskbytes: %ud, valuebytes: %ud,"
+		  " totalbytes: %d) ...\n",
+		  maskbytes, valuesbytes, totalbytes);
+	LOG_BLOB("pmf:   mask data: \n", maskblob, maskbytes);
+	LOG_BLOB("pmf:   values data: \n", valuesblob, valuesbytes);
+
+	PMF_PARSE_CALL(rmw_cfg, cmd, h, offset, maskbytes, valuesbytes,
+		       totalbytes, maskblob, valuesblob);
+}
+
+
+static int pmf_parser_read_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u8 subaddr = (u8)pmf_next32(cmd);
+	u32 bytes = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_i2c_sub(subaddr: %x, bytes: %ud)\n",
+		  subaddr, bytes);
+
+	PMF_PARSE_CALL(read_i2c_sub, cmd, h, subaddr, bytes);
+}
+
+static int pmf_parser_write_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u8 subaddr = (u8)pmf_next32(cmd);
+	u32 bytes = pmf_next32(cmd);
+	const void *blob = pmf_next_blob(cmd, bytes);
+
+	LOG_PARSE("pmf: write_i2c_sub(subaddr: %x, bytes: %ud) ...\n",
+		  subaddr, bytes);
+	LOG_BLOB("pmf:   data: \n", blob, bytes);
+
+	PMF_PARSE_CALL(write_i2c_sub, cmd, h, subaddr, bytes, blob);
+}
+
+static int pmf_parser_set_i2c_mode(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u32 mode = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: set_i2c_mode(mode: %d)\n", mode);
+
+	PMF_PARSE_CALL(set_i2c_mode, cmd, h, mode);
+}
+
+
+static int pmf_parser_rmw_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+	u8 subaddr = (u8)pmf_next32(cmd);
+	u32 maskbytes = pmf_next32(cmd);
+	u32 valuesbytes = pmf_next32(cmd);
+	u32 totalbytes = pmf_next32(cmd);
+	const void *maskblob = pmf_next_blob(cmd, maskbytes);
+	const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+	LOG_PARSE("pmf: rmw_i2c_sub(subaddr: %x, maskbytes: %ud, valuebytes: %ud"
+		  ", totalbytes: %d) ...\n",
+		  subaddr, maskbytes, valuesbytes, totalbytes);
+	LOG_BLOB("pmf:   mask data: \n", maskblob, maskbytes);
+	LOG_BLOB("pmf:   values data: \n", valuesblob, valuesbytes);
+
+	PMF_PARSE_CALL(rmw_i2c_sub, cmd, h, subaddr, maskbytes, valuesbytes,
+		       totalbytes, maskblob, valuesblob);
+}
+
+static int pmf_parser_read_reg32_msrx(struct pmf_cmd *cmd,
+				      struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 mask = pmf_next32(cmd);
+	u32 shift = pmf_next32(cmd);
+	u32 xor = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_reg32_msrx(offset: %x, mask: %x, shift: %x,"
+		  " xor: %x\n", offset, mask, shift, xor);
+
+	PMF_PARSE_CALL(read_reg32_msrx, cmd, h, offset, mask, shift, xor);
+}
+
+static int pmf_parser_read_reg16_msrx(struct pmf_cmd *cmd,
+				      struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 mask = pmf_next32(cmd);
+	u32 shift = pmf_next32(cmd);
+	u32 xor = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_reg16_msrx(offset: %x, mask: %x, shift: %x,"
+		  " xor: %x\n", offset, mask, shift, xor);
+
+	PMF_PARSE_CALL(read_reg16_msrx, cmd, h, offset, mask, shift, xor);
+}
+static int pmf_parser_read_reg8_msrx(struct pmf_cmd *cmd,
+				     struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 mask = pmf_next32(cmd);
+	u32 shift = pmf_next32(cmd);
+	u32 xor = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: read_reg8_msrx(offset: %x, mask: %x, shift: %x,"
+		  " xor: %x\n", offset, mask, shift, xor);
+
+	PMF_PARSE_CALL(read_reg8_msrx, cmd, h, offset, mask, shift, xor);
+}
+
+static int pmf_parser_write_reg32_slm(struct pmf_cmd *cmd,
+				      struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 shift = pmf_next32(cmd);
+	u32 mask = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: write_reg32_slm(offset: %x, shift: %x, mask: %x\n",
+		  offset, shift, mask);
+
+	PMF_PARSE_CALL(write_reg32_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_write_reg16_slm(struct pmf_cmd *cmd,
+				      struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 shift = pmf_next32(cmd);
+	u32 mask = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: write_reg16_slm(offset: %x, shift: %x, mask: %x\n",
+		  offset, shift, mask);
+
+	PMF_PARSE_CALL(write_reg16_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_write_reg8_slm(struct pmf_cmd *cmd,
+				     struct pmf_handlers *h)
+{
+	u32 offset = pmf_next32(cmd);
+	u32 shift = pmf_next32(cmd);
+	u32 mask = pmf_next32(cmd);
+
+	LOG_PARSE("pmf: write_reg8_slm(offset: %x, shift: %x, mask: %x\n",
+		  offset, shift, mask);
+
+	PMF_PARSE_CALL(write_reg8_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_mask_and_compare(struct pmf_cmd *cmd,
+				       struct pmf_handlers *h)
+{
+	u32 bytes = pmf_next32(cmd);
+	const void *maskblob = pmf_next_blob(cmd, bytes);
+	const void *valuesblob = pmf_next_blob(cmd, bytes);
+
+	LOG_PARSE("pmf: mask_and_compare(length: %ud ...\n", bytes);
+	LOG_BLOB("pmf:   mask data: \n", maskblob, bytes);
+	LOG_BLOB("pmf:   values data: \n", valuesblob, bytes);
+
+	PMF_PARSE_CALL(mask_and_compare, cmd, h,
+		       bytes, maskblob, valuesblob);
+}
+
+
+typedef int (*pmf_cmd_parser_t)(struct pmf_cmd *cmd, struct pmf_handlers *h);
+
+static pmf_cmd_parser_t pmf_parsers[PMF_CMD_COUNT] =
+{
+	NULL,
+	pmf_parser_write_gpio,
+	pmf_parser_read_gpio,
+	pmf_parser_write_reg32,
+	pmf_parser_read_reg32,
+	pmf_parser_write_reg16,
+	pmf_parser_read_reg16,
+	pmf_parser_write_reg8,
+	pmf_parser_read_reg8,
+	pmf_parser_delay,
+	pmf_parser_wait_reg32,
+	pmf_parser_wait_reg16,
+	pmf_parser_wait_reg8,
+	pmf_parser_read_i2c,
+	pmf_parser_write_i2c,
+	pmf_parser_rmw_i2c,
+	NULL, /* Bogus command */
+	NULL, /* Shift bytes right: NYI */
+	NULL, /* Shift bytes left: NYI */
+	pmf_parser_read_cfg,
+	pmf_parser_write_cfg,
+	pmf_parser_rmw_cfg,
+	pmf_parser_read_i2c_sub,
+	pmf_parser_write_i2c_sub,
+	pmf_parser_set_i2c_mode,
+	pmf_parser_rmw_i2c_sub,
+	pmf_parser_read_reg32_msrx,
+	pmf_parser_read_reg16_msrx,
+	pmf_parser_read_reg8_msrx,
+	pmf_parser_write_reg32_slm,
+	pmf_parser_write_reg16_slm,
+	pmf_parser_write_reg8_slm,
+	pmf_parser_mask_and_compare,
+};
+
+struct pmf_device {
+	struct list_head	link;
+	struct device_node	*node;
+	struct pmf_handlers	*handlers;
+	struct list_head	functions;
+	struct kref		ref;
+};
+
+static LIST_HEAD(pmf_devices);
+static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED;
+
+static void pmf_release_device(struct kref *kref)
+{
+	struct pmf_device *dev = container_of(kref, struct pmf_device, ref);
+	kfree(dev);
+}
+
+static inline void pmf_put_device(struct pmf_device *dev)
+{
+	kref_put(&dev->ref, pmf_release_device);
+}
+
+static inline struct pmf_device *pmf_get_device(struct pmf_device *dev)
+{
+	kref_get(&dev->ref);
+	return dev;
+}
+
+static inline struct pmf_device *pmf_find_device(struct device_node *np)
+{
+	struct pmf_device *dev;
+
+	list_for_each_entry(dev, &pmf_devices, link) {
+		if (dev->node == np)
+			return pmf_get_device(dev);
+	}
+	return NULL;
+}
+
+static int pmf_parse_one(struct pmf_function *func,
+			 struct pmf_handlers *handlers,
+			 void *instdata, struct pmf_args *args)
+{
+	struct pmf_cmd cmd;
+	u32 ccode;
+	int count, rc;
+
+	cmd.cmdptr		= func->data;
+	cmd.cmdend		= func->data + func->length;
+	cmd.func       		= func;
+	cmd.instdata		= instdata;
+	cmd.args		= args;
+	cmd.error		= 0;
+
+	LOG_PARSE("pmf: func %s, %d bytes, %s...\n",
+		  func->name, func->length,
+		  handlers ? "executing" : "parsing");
+
+	/* One subcommand to parse for now */
+	count = 1;
+
+	while(count-- && cmd.cmdptr < cmd.cmdend) {
+		/* Get opcode */
+		ccode = pmf_next32(&cmd);
+		/* Check if we are hitting a command list, fetch new count */
+		if (ccode == 0) {
+			count = pmf_next32(&cmd) - 1;
+			ccode = pmf_next32(&cmd);
+		}
+		if (cmd.error) {
+			LOG_ERROR("pmf: parse error, not enough data\n");
+			return -ENXIO;
+		}
+		if (ccode >= PMF_CMD_COUNT) {
+			LOG_ERROR("pmf: command code %d unknown !\n", ccode);
+			return -ENXIO;
+		}
+		if (pmf_parsers[ccode] == NULL) {
+			LOG_ERROR("pmf: no parser for command %d !\n", ccode);
+			return -ENXIO;
+		}
+		rc = pmf_parsers[ccode](&cmd, handlers);
+		if (rc != 0) {
+			LOG_ERROR("pmf: parser for command %d returned"
+				  " error %d\n", ccode, rc);
+			return rc;
+		}
+	}
+
+	/* We are doing an initial parse pass, we need to adjust the size */
+	if (handlers == NULL)
+		func->length = cmd.cmdptr - func->data;
+
+	return 0;
+}
+
+static int pmf_add_function_prop(struct pmf_device *dev, void *driverdata,
+				 const char *name, u32 *data,
+				 unsigned int length)
+{
+	int count = 0;
+	struct pmf_function *func = NULL;
+
+	DBG("pmf: Adding functions for platform-do-%s\n", name);
+
+	while (length >= 12) {
+		/* Allocate a structure */
+		func = kzalloc(sizeof(struct pmf_function), GFP_KERNEL);
+		if (func == NULL)
+			goto bail;
+		kref_init(&func->ref);
+		INIT_LIST_HEAD(&func->irq_clients);
+		func->node = dev->node;
+		func->driver_data = driverdata;
+		func->name = name;
+		func->phandle = data[0];
+		func->flags = data[1];
+		data += 2;
+		length -= 8;
+		func->data = data;
+		func->length = length;
+		func->dev = dev;
+		DBG("pmf: idx %d: flags=%08x, phandle=%08x "
+		    " %d bytes remaining, parsing...\n",
+		    count+1, func->flags, func->phandle, length);
+		if (pmf_parse_one(func, NULL, NULL, NULL)) {
+			kfree(func);
+			goto bail;
+		}
+		length -= func->length;
+		data = (u32 *)(((u8 *)data) + func->length);
+		list_add(&func->link, &dev->functions);
+		pmf_get_device(dev);
+		count++;
+	}
+ bail:
+	DBG("pmf: Added %d functions\n", count);
+
+	return count;
+}
+
+static int pmf_add_functions(struct pmf_device *dev, void *driverdata)
+{
+	struct property *pp;
+#define PP_PREFIX "platform-do-"
+	const int plen = strlen(PP_PREFIX);
+	int count = 0;
+
+	for (pp = dev->node->properties; pp != 0; pp = pp->next) {
+		char *name;
+		if (strncmp(pp->name, PP_PREFIX, plen) != 0)
+			continue;
+		name = pp->name + plen;
+		if (strlen(name) && pp->length >= 12)
+			count += pmf_add_function_prop(dev, driverdata, name,
+						       (u32 *)pp->value,
+						       pp->length);
+	}
+	return count;
+}
+
+
+int pmf_register_driver(struct device_node *np,
+			struct pmf_handlers *handlers,
+			void *driverdata)
+{
+	struct pmf_device *dev;
+	unsigned long flags;
+	int rc = 0;
+
+	if (handlers == NULL)
+		return -EINVAL;
+
+	DBG("pmf: registering driver for node %s\n", np->full_name);
+
+	spin_lock_irqsave(&pmf_lock, flags);
+	dev = pmf_find_device(np);
+	spin_unlock_irqrestore(&pmf_lock, flags);
+	if (dev != NULL) {
+		DBG("pmf: already there !\n");
+		pmf_put_device(dev);
+		return -EBUSY;
+	}
+
+	dev = kzalloc(sizeof(struct pmf_device), GFP_KERNEL);
+	if (dev == NULL) {
+		DBG("pmf: no memory !\n");
+		return -ENOMEM;
+	}
+	kref_init(&dev->ref);
+	dev->node = of_node_get(np);
+	dev->handlers = handlers;
+	INIT_LIST_HEAD(&dev->functions);
+
+	rc = pmf_add_functions(dev, driverdata);
+	if (rc == 0) {
+		DBG("pmf: no functions, disposing.. \n");
+		of_node_put(np);
+		kfree(dev);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&pmf_lock, flags);
+	list_add(&dev->link, &pmf_devices);
+	spin_unlock_irqrestore(&pmf_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pmf_register_driver);
+
+struct pmf_function *pmf_get_function(struct pmf_function *func)
+{
+	if (!try_module_get(func->dev->handlers->owner))
+		return NULL;
+	kref_get(&func->ref);
+	return func;
+}
+EXPORT_SYMBOL_GPL(pmf_get_function);
+
+static void pmf_release_function(struct kref *kref)
+{
+	struct pmf_function *func =
+		container_of(kref, struct pmf_function, ref);
+	pmf_put_device(func->dev);
+	kfree(func);
+}
+
+static inline void __pmf_put_function(struct pmf_function *func)
+{
+	kref_put(&func->ref, pmf_release_function);
+}
+
+void pmf_put_function(struct pmf_function *func)
+{
+	if (func == NULL)
+		return;
+	module_put(func->dev->handlers->owner);
+	__pmf_put_function(func);
+}
+EXPORT_SYMBOL_GPL(pmf_put_function);
+
+void pmf_unregister_driver(struct device_node *np)
+{
+	struct pmf_device *dev;
+	unsigned long flags;
+
+	DBG("pmf: unregistering driver for node %s\n", np->full_name);
+
+	spin_lock_irqsave(&pmf_lock, flags);
+	dev = pmf_find_device(np);
+	if (dev == NULL) {
+		DBG("pmf: not such driver !\n");
+		spin_unlock_irqrestore(&pmf_lock, flags);
+		return;
+	}
+	list_del(&dev->link);
+
+	while(!list_empty(&dev->functions)) {
+		struct pmf_function *func =
+			list_entry(dev->functions.next, typeof(*func), link);
+		list_del(&func->link);
+		__pmf_put_function(func);
+	}
+
+	pmf_put_device(dev);
+	spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_unregister_driver);
+
+struct pmf_function *__pmf_find_function(struct device_node *target,
+					 const char *name, u32 flags)
+{
+	struct device_node *actor = of_node_get(target);
+	struct pmf_device *dev;
+	struct pmf_function *func, *result = NULL;
+	char fname[64];
+	u32 *prop, ph;
+
+	/*
+	 * Look for a "platform-*" function reference. If we can't find
+	 * one, then we fallback to a direct call attempt
+	 */
+	snprintf(fname, 63, "platform-%s", name);
+	prop = (u32 *)get_property(target, fname, NULL);
+	if (prop == NULL)
+		goto find_it;
+	ph = *prop;
+	if (ph == 0)
+		goto find_it;
+
+	/*
+	 * Ok, now try to find the actor. If we can't find it, we fail,
+	 * there is no point in falling back there
+	 */
+	of_node_put(actor);
+	actor = of_find_node_by_phandle(ph);
+	if (actor == NULL)
+		return NULL;
+ find_it:
+	dev = pmf_find_device(actor);
+	if (dev == NULL)
+		return NULL;
+
+	list_for_each_entry(func, &dev->functions, link) {
+		if (name && strcmp(name, func->name))
+			continue;
+		if (func->phandle && target->node != func->phandle)
+			continue;
+		if ((func->flags & flags) == 0)
+			continue;
+		result = func;
+		break;
+	}
+	of_node_put(actor);
+	pmf_put_device(dev);
+	return result;
+}
+
+
+int pmf_register_irq_client(struct device_node *target,
+			    const char *name,
+			    struct pmf_irq_client *client)
+{
+	struct pmf_function *func;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmf_lock, flags);
+	func = __pmf_find_function(target, name, PMF_FLAGS_INT_GEN);
+	if (func == NULL) {
+		spin_unlock_irqrestore(&pmf_lock, flags);
+		return -ENODEV;
+	}
+	list_add(&client->link, &func->irq_clients);
+	spin_unlock_irqrestore(&pmf_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pmf_register_irq_client);
+
+void pmf_unregister_irq_client(struct device_node *np,
+			      const char *name,
+			      struct pmf_irq_client *client)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmf_lock, flags);
+	list_del(&client->link);
+	spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_unregister_irq_client);
+
+
+void pmf_do_irq(struct pmf_function *func)
+{
+	unsigned long flags;
+	struct pmf_irq_client *client;
+
+	/* For now, using a spinlock over the whole function. Can be made
+	 * to drop the lock using 2 lists if necessary
+	 */
+	spin_lock_irqsave(&pmf_lock, flags);
+	list_for_each_entry(client, &func->irq_clients, link) {
+		if (!try_module_get(client->owner))
+			continue;
+		client->handler(client->data);
+		module_put(client->owner);
+	}
+	spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_do_irq);
+
+
+int pmf_call_one(struct pmf_function *func, struct pmf_args *args)
+{
+	struct pmf_device *dev = func->dev;
+	void *instdata = NULL;
+	int rc = 0;
+
+	DBG(" ** pmf_call_one(%s/%s) **\n", dev->node->full_name, func->name);
+
+	if (dev->handlers->begin)
+		instdata = dev->handlers->begin(func, args);
+	rc = pmf_parse_one(func, dev->handlers, instdata, args);
+	if (dev->handlers->end)
+		dev->handlers->end(func, instdata);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_call_one);
+
+int pmf_do_functions(struct device_node *np, const char *name,
+		     u32 phandle, u32 fflags, struct pmf_args *args)
+{
+	struct pmf_device *dev;
+	struct pmf_function *func, *tmp;
+	unsigned long flags;
+	int rc = -ENODEV;
+
+	spin_lock_irqsave(&pmf_lock, flags);
+
+	dev = pmf_find_device(np);
+	if (dev == NULL) {
+		spin_unlock_irqrestore(&pmf_lock, flags);
+		return -ENODEV;
+	}
+	list_for_each_entry_safe(func, tmp, &dev->functions, link) {
+		if (name && strcmp(name, func->name))
+			continue;
+		if (phandle && func->phandle && phandle != func->phandle)
+			continue;
+		if ((func->flags & fflags) == 0)
+			continue;
+		if (pmf_get_function(func) == NULL)
+			continue;
+		spin_unlock_irqrestore(&pmf_lock, flags);
+		rc = pmf_call_one(func, args);
+		pmf_put_function(func);
+		spin_lock_irqsave(&pmf_lock, flags);
+	}
+	pmf_put_device(dev);
+	spin_unlock_irqrestore(&pmf_lock, flags);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_do_functions);
+
+
+struct pmf_function *pmf_find_function(struct device_node *target,
+				       const char *name)
+{
+	struct pmf_function *func;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmf_lock, flags);
+	func = __pmf_find_function(target, name, PMF_FLAGS_ON_DEMAND);
+	if (func)
+		func = pmf_get_function(func);
+	spin_unlock_irqrestore(&pmf_lock, flags);
+	return func;
+}
+EXPORT_SYMBOL_GPL(pmf_find_function);
+
+int pmf_call_function(struct device_node *target, const char *name,
+		      struct pmf_args *args)
+{
+	struct pmf_function *func = pmf_find_function(target, name);
+	int rc;
+
+	if (func == NULL)
+		return -ENODEV;
+
+	rc = pmf_call_one(func, args);
+	pmf_put_function(func);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_call_function);
+
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 90040c4..18bf301 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -5,8 +5,8 @@
  *  in a separate file
  *
  *  Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
- *
- *  Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *  Copyright (C) 2005 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *                     IBM, Corp.
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -54,12 +54,7 @@
 };
 
 /* Default addresses */
-static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
-        (struct pmac_irq_hw *) 0xf3000020,
-        (struct pmac_irq_hw *) 0xf3000010,
-        (struct pmac_irq_hw *) 0xf4000020,
-        (struct pmac_irq_hw *) 0xf4000010,
-};
+static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4];
 
 #define GC_LEVEL_MASK		0x3ff00000
 #define OHARE_LEVEL_MASK	0x1ff00000
@@ -82,8 +77,7 @@
  * since it can lose interrupts (see pmac_set_irq_mask).
  * -- Cort
  */
-void
-__set_lost(unsigned long irq_nr, int nokick)
+void __set_lost(unsigned long irq_nr, int nokick)
 {
 	if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
 		atomic_inc(&ppc_n_lost_interrupts);
@@ -92,8 +86,7 @@
 	}
 }
 
-static void
-pmac_mask_and_ack_irq(unsigned int irq_nr)
+static void pmac_mask_and_ack_irq(unsigned int irq_nr)
 {
         unsigned long bit = 1UL << (irq_nr & 0x1f);
         int i = irq_nr >> 5;
@@ -224,8 +217,7 @@
 	return IRQ_NONE;
 }
 
-int
-pmac_get_irq(struct pt_regs *regs)
+static int pmac_get_irq(struct pt_regs *regs)
 {
 	int irq;
 	unsigned long bits = 0;
@@ -256,34 +248,40 @@
 
 /* This routine will fix some missing interrupt values in the device tree
  * on the gatwick mac-io controller used by some PowerBooks
+ *
+ * Walking of OF nodes could use a bit more fixing up here, but it's not
+ * very important as this is all boot time code on static portions of the
+ * device-tree.
+ *
+ * However, the modifications done to "intrs" will have to be removed and
+ * replaced with proper updates of the "interrupts" properties or
+ * AAPL,interrupts, yet to be decided, once the dynamic parsing is there.
  */
-static void __init
-pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+static void __init pmac_fix_gatwick_interrupts(struct device_node *gw,
+					       int irq_base)
 {
 	struct device_node *node;
 	int count;
 
 	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
-	node = gw->child;
 	count = 0;
-	while(node)
-	{
+	for (node = NULL; (node = of_get_next_child(gw, node)) != NULL;) {
 		/* Fix SCC */
-		if (strcasecmp(node->name, "escc") == 0)
-			if (node->child) {
-				if (node->child->n_intrs < 3) {
-					node->child->intrs = &gatwick_int_pool[count];
-					count += 3;
-				}
-				node->child->n_intrs = 3;
-				node->child->intrs[0].line = 15+irq_base;
-				node->child->intrs[1].line =  4+irq_base;
-				node->child->intrs[2].line =  5+irq_base;
-				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
-					node->child->intrs[0].line,
-					node->child->intrs[1].line,
-					node->child->intrs[2].line);
+		if ((strcasecmp(node->name, "escc") == 0) && node->child) {
+			if (node->child->n_intrs < 3) {
+				node->child->intrs = &gatwick_int_pool[count];
+				count += 3;
 			}
+			node->child->n_intrs = 3;
+			node->child->intrs[0].line = 15+irq_base;
+			node->child->intrs[1].line =  4+irq_base;
+			node->child->intrs[2].line =  5+irq_base;
+			printk(KERN_INFO "irq: fixed SCC on gatwick"
+			       " (%d,%d,%d)\n",
+			       node->child->intrs[0].line,
+			       node->child->intrs[1].line,
+			       node->child->intrs[2].line);
+		}
 		/* Fix media-bay & left SWIM */
 		if (strcasecmp(node->name, "media-bay") == 0) {
 			struct device_node* ya_node;
@@ -292,12 +290,11 @@
 				node->intrs = &gatwick_int_pool[count++];
 			node->n_intrs = 1;
 			node->intrs[0].line = 29+irq_base;
-			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
-					node->intrs[0].line);
+			printk(KERN_INFO "irq: fixed media-bay on gatwick"
+			       " (%d)\n", node->intrs[0].line);
 
 			ya_node = node->child;
-			while(ya_node)
-			{
+			while(ya_node) {
 				if (strcasecmp(ya_node->name, "floppy") == 0) {
 					if (ya_node->n_intrs < 2) {
 						ya_node->intrs = &gatwick_int_pool[count];
@@ -323,7 +320,6 @@
 				ya_node = ya_node->sibling;
 			}
 		}
-		node = node->sibling;
 	}
 	if (count > 10) {
 		printk("WARNING !! Gatwick interrupt pool overflow\n");
@@ -338,45 +334,41 @@
  * controller.  If we find this second ohare, set it up and fix the
  * interrupt value in the device tree for the ethernet chip.
  */
-static int __init enable_second_ohare(void)
+static void __init enable_second_ohare(struct device_node *np)
 {
 	unsigned char bus, devfn;
 	unsigned short cmd;
-        unsigned long addr;
-	struct device_node *irqctrler = find_devices("pci106b,7");
 	struct device_node *ether;
 
-	if (irqctrler == NULL || irqctrler->n_addrs <= 0)
-		return -1;
-	addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
-	pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
-	max_irqs = 64;
-	if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
-		struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
-		if (!hose)
-		    printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
-		else {
-		    early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
-		    cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-	  	    cmd &= ~PCI_COMMAND_IO;
-		    early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
+	/* This code doesn't strictly belong here, it could be part of
+	 * either the PCI initialisation or the feature code. It's kept
+	 * here for historical reasons.
+	 */
+	if (pci_device_from_OF_node(np, &bus, &devfn) == 0) {
+		struct pci_controller* hose =
+			pci_find_hose_for_OF_device(np);
+		if (!hose) {
+			printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+			return;
 		}
+		early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+		cmd &= ~PCI_COMMAND_IO;
+		early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
 	}
 
 	/* Fix interrupt for the modem/ethernet combo controller. The number
-	   in the device tree (27) is bogus (correct for the ethernet-only
-	   board but not the combo ethernet/modem board).
-	   The real interrupt is 28 on the second controller -> 28+32 = 60.
-	*/
-	ether = find_devices("pci1011,14");
+	 * in the device tree (27) is bogus (correct for the ethernet-only
+	 * board but not the combo ethernet/modem board).
+	 * The real interrupt is 28 on the second controller -> 28+32 = 60.
+	 */
+	ether = of_find_node_by_name(NULL, "pci1011,14");
 	if (ether && ether->n_intrs > 0) {
 		ether->intrs[0].line = 60;
 		printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
 		       ether->intrs[0].line);
 	}
-
-	/* Return the interrupt number of the cascade */
-	return irqctrler->intrs[0].line;
+	of_node_put(ether);
 }
 
 #ifdef CONFIG_XMON
@@ -394,6 +386,121 @@
 	.mask		= CPU_MASK_NONE,
 	.name		= "cascade",
 };
+
+static void __init pmac_pic_probe_oldstyle(void)
+{
+        int i;
+	int irq_cascade = -1;
+        struct device_node *master = NULL;
+	struct device_node *slave = NULL;
+	u8 __iomem *addr;
+	struct resource r;
+
+	/* Set our get_irq function */
+	ppc_md.get_irq = pmac_get_irq;
+
+	/*
+	 * Find the interrupt controller type & node
+	 */
+
+	if ((master = of_find_node_by_name(NULL, "gc")) != NULL) {
+		max_irqs = max_real_irqs = 32;
+		level_mask[0] = GC_LEVEL_MASK;
+	} else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) {
+		max_irqs = max_real_irqs = 32;
+		level_mask[0] = OHARE_LEVEL_MASK;
+
+		/* We might have a second cascaded ohare */
+		slave = of_find_node_by_name(NULL, "pci106b,7");
+		if (slave) {
+			max_irqs = 64;
+			level_mask[1] = OHARE_LEVEL_MASK;
+			enable_second_ohare(slave);
+		}
+	} else if ((master = of_find_node_by_name(NULL, "mac-io")) != NULL) {
+		max_irqs = max_real_irqs = 64;
+		level_mask[0] = HEATHROW_LEVEL_MASK;
+		level_mask[1] = 0;
+
+		/* We might have a second cascaded heathrow */
+		slave = of_find_node_by_name(master, "mac-io");
+
+		/* Check ordering of master & slave */
+		if (device_is_compatible(master, "gatwick")) {
+			struct device_node *tmp;
+			BUG_ON(slave == NULL);
+			tmp = master;
+			master = slave;
+			slave = tmp;
+		}
+
+		/* We found a slave */
+		if (slave) {
+			max_irqs = 128;
+			level_mask[2] = HEATHROW_LEVEL_MASK;
+			level_mask[3] = 0;
+			pmac_fix_gatwick_interrupts(slave, max_real_irqs);
+		}
+	}
+	BUG_ON(master == NULL);
+
+	/* Set the handler for the main PIC */
+	for ( i = 0; i < max_real_irqs ; i++ )
+		irq_desc[i].handler = &pmac_pic;
+
+	/* Get addresses of first controller if we have a node for it */
+	BUG_ON(of_address_to_resource(master, 0, &r));
+
+	/* Map interrupts of primary controller */
+	addr = (u8 __iomem *) ioremap(r.start, 0x40);
+	i = 0;
+	pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+		(addr + 0x20);
+	if (max_real_irqs > 32)
+		pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+			(addr + 0x10);
+	of_node_put(master);
+
+	printk(KERN_INFO "irq: Found primary Apple PIC %s for %d irqs\n",
+	       master->full_name, max_real_irqs);
+
+	/* Map interrupts of cascaded controller */
+	if (slave && !of_address_to_resource(slave, 0, &r)) {
+		addr = (u8 __iomem *)ioremap(r.start, 0x40);
+		pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+			(addr + 0x20);
+		if (max_irqs > 64)
+			pmac_irq_hw[i++] =
+				(volatile struct pmac_irq_hw __iomem *)
+				(addr + 0x10);
+		irq_cascade = slave->intrs[0].line;
+
+		printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"
+		       " cascade: %d\n", slave->full_name,
+		       max_irqs - max_real_irqs, irq_cascade);
+	}
+	of_node_put(slave);
+
+	/* disable all interrupts in all controllers */
+	for (i = 0; i * 32 < max_irqs; ++i)
+		out_le32(&pmac_irq_hw[i]->enable, 0);
+
+	/* mark level interrupts */
+	for (i = 0; i < max_irqs; i++)
+		if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
+			irq_desc[i].status = IRQ_LEVEL;
+
+	/* Setup handlers for secondary controller and hook cascade irq*/
+	if (slave) {
+		for ( i = max_real_irqs ; i < max_irqs ; i++ )
+			irq_desc[i].handler = &gatwick_pic;
+		setup_irq(irq_cascade, &gatwick_cascade_action);
+	}
+	printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
+#ifdef CONFIG_XMON
+	setup_irq(20, &xmon_action);
+#endif
+}
 #endif /* CONFIG_PPC32 */
 
 static int pmac_u3_cascade(struct pt_regs *regs, void *data)
@@ -401,182 +508,129 @@
 	return mpic_get_one_irq((struct mpic *)data, regs);
 }
 
+static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
+{
+#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
+	struct device_node* pswitch;
+	int nmi_irq;
+
+	pswitch = of_find_node_by_name(NULL, "programmer-switch");
+	if (pswitch && pswitch->n_intrs) {
+		nmi_irq = pswitch->intrs[0].line;
+		mpic_irq_set_priority(nmi_irq, 9);
+		setup_irq(nmi_irq, &xmon_action);
+	}
+	of_node_put(pswitch);
+#endif	/* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */
+}
+
+static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
+						int master)
+{
+	unsigned char senses[128];
+	int offset = master ? 0 : 128;
+	int count = master ? 128 : 124;
+	const char *name = master ? " MPIC 1   " : " MPIC 2   ";
+	struct resource r;
+	struct mpic *mpic;
+	unsigned int flags = master ? MPIC_PRIMARY : 0;
+	int rc;
+
+	rc = of_address_to_resource(np, 0, &r);
+	if (rc)
+		return NULL;
+
+	pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
+
+	prom_get_irq_senses(senses, offset, offset + count);
+
+	flags |= MPIC_WANTS_RESET;
+	if (get_property(np, "big-endian", NULL))
+		flags |= MPIC_BIG_ENDIAN;
+
+	/* Primary Big Endian means HT interrupts. This is quite dodgy
+	 * but works until I find a better way
+	 */
+	if (master && (flags & MPIC_BIG_ENDIAN))
+		flags |= MPIC_BROKEN_U3;
+
+	mpic = mpic_alloc(r.start, flags, 0, offset, count, master ? 252 : 0,
+			  senses, count, name);
+	if (mpic == NULL)
+		return NULL;
+
+	mpic_init(mpic);
+
+	return mpic;
+ }
+
+static int __init pmac_pic_probe_mpic(void)
+{
+	struct mpic *mpic1, *mpic2;
+	struct device_node *np, *master = NULL, *slave = NULL;
+
+	/* We can have up to 2 MPICs cascaded */
+	for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
+		     != NULL;) {
+		if (master == NULL &&
+		    get_property(np, "interrupts", NULL) == NULL)
+			master = of_node_get(np);
+		else if (slave == NULL)
+			slave = of_node_get(np);
+		if (master && slave)
+			break;
+	}
+
+	/* Check for bogus setups */
+	if (master == NULL && slave != NULL) {
+		master = slave;
+		slave = NULL;
+	}
+
+	/* Not found, default to good old pmac pic */
+	if (master == NULL)
+		return -ENODEV;
+
+	/* Set master handler */
+	ppc_md.get_irq = mpic_get_irq;
+
+	/* Setup master */
+	mpic1 = pmac_setup_one_mpic(master, 1);
+	BUG_ON(mpic1 == NULL);
+
+	/* Install NMI if any */
+	pmac_pic_setup_mpic_nmi(mpic1);
+
+	of_node_put(master);
+
+	/* No slave, let's go out */
+	if (slave == NULL || slave->n_intrs < 1)
+		return 0;
+
+	mpic2 = pmac_setup_one_mpic(slave, 0);
+	if (mpic2 == NULL) {
+		printk(KERN_ERR "Failed to setup slave MPIC\n");
+		of_node_put(slave);
+		return 0;
+	}
+	mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2);
+
+	of_node_put(slave);
+	return 0;
+}
+
+
 void __init pmac_pic_init(void)
 {
-        struct device_node *irqctrler  = NULL;
-        struct device_node *irqctrler2 = NULL;
-	struct device_node *np;
-#ifdef CONFIG_PPC32
-        int i;
-        unsigned long addr;
-	int irq_cascade = -1;
-#endif
-	struct mpic *mpic1, *mpic2;
-
 	/* We first try to detect Apple's new Core99 chipset, since mac-io
 	 * is quite different on those machines and contains an IBM MPIC2.
 	 */
-	np = find_type_devices("open-pic");
-	while (np) {
-		if (np->parent && !strcmp(np->parent->name, "u3"))
-			irqctrler2 = np;
-		else
-			irqctrler = np;
-		np = np->next;
-	}
-	if (irqctrler != NULL && irqctrler->n_addrs > 0) {
-		unsigned char senses[128];
-
-		printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
-		       (unsigned int)irqctrler->addrs[0].address);
-		pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
-
-		prom_get_irq_senses(senses, 0, 128);
-		mpic1 = mpic_alloc(irqctrler->addrs[0].address,
-				   MPIC_PRIMARY | MPIC_WANTS_RESET,
-				   0, 0, 128, 252, senses, 128, " OpenPIC  ");
-		BUG_ON(mpic1 == NULL);
-		mpic_init(mpic1);		
-
-		if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
-		    irqctrler2->n_addrs > 0) {
-			printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
-			       (u32)irqctrler2->addrs[0].address,
-			       irqctrler2->intrs[0].line);
-
-			pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
-			prom_get_irq_senses(senses, 128, 128 + 124);
-
-			/* We don't need to set MPIC_BROKEN_U3 here since we don't have
-			 * hypertransport interrupts routed to it
-			 */
-			mpic2 = mpic_alloc(irqctrler2->addrs[0].address,
-					   MPIC_BIG_ENDIAN | MPIC_WANTS_RESET,
-					   0, 128, 124, 0, senses, 124,
-					   " U3-MPIC  ");
-			BUG_ON(mpic2 == NULL);
-			mpic_init(mpic2);
-			mpic_setup_cascade(irqctrler2->intrs[0].line,
-					   pmac_u3_cascade, mpic2);
-		}
-#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
-		{
-			struct device_node* pswitch;
-			int nmi_irq;
-
-			pswitch = find_devices("programmer-switch");
-			if (pswitch && pswitch->n_intrs) {
-				nmi_irq = pswitch->intrs[0].line;
-				mpic_irq_set_priority(nmi_irq, 9);
-				setup_irq(nmi_irq, &xmon_action);
-			}
-		}
-#endif	/* CONFIG_XMON */
+	if (pmac_pic_probe_mpic() == 0)
 		return;
-	}
-	irqctrler = NULL;
 
 #ifdef CONFIG_PPC32
-	/* Get the level/edge settings, assume if it's not
-	 * a Grand Central nor an OHare, then it's an Heathrow
-	 * (or Paddington).
-	 */
-	ppc_md.get_irq = pmac_get_irq;
-	if (find_devices("gc"))
-		level_mask[0] = GC_LEVEL_MASK;
-	else if (find_devices("ohare")) {
-		level_mask[0] = OHARE_LEVEL_MASK;
-		/* We might have a second cascaded ohare */
-		level_mask[1] = OHARE_LEVEL_MASK;
-	} else {
-		level_mask[0] = HEATHROW_LEVEL_MASK;
-		level_mask[1] = 0;
-		/* We might have a second cascaded heathrow */
-		level_mask[2] = HEATHROW_LEVEL_MASK;
-		level_mask[3] = 0;
-	}
-
-	/*
-	 * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
-	 * 1998 G3 Series PowerBooks have 128,
-	 * other powermacs have 32.
-	 * The combo ethernet/modem card for the Powerstar powerbooks
-	 * (2400/3400/3500, ohare based) has a second ohare chip
-	 * effectively making a total of 64.
-	 */
-	max_irqs = max_real_irqs = 32;
-	irqctrler = find_devices("mac-io");
-	if (irqctrler)
-	{
-		max_real_irqs = 64;
-		if (irqctrler->next)
-			max_irqs = 128;
-		else
-			max_irqs = 64;
-	}
-	for ( i = 0; i < max_real_irqs ; i++ )
-		irq_desc[i].handler = &pmac_pic;
-
-	/* get addresses of first controller */
-	if (irqctrler) {
-		if  (irqctrler->n_addrs > 0) {
-			addr = (unsigned long)
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 0; i < 2; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (2 - i) * 0x10);
-		}
-
-		/* get addresses of second controller */
-		irqctrler = irqctrler->next;
-		if (irqctrler && irqctrler->n_addrs > 0) {
-			addr = (unsigned long)
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 2; i < 4; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (4 - i) * 0x10);
-			irq_cascade = irqctrler->intrs[0].line;
-			if (device_is_compatible(irqctrler, "gatwick"))
-				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-		}
-	} else {
-		/* older powermacs have a GC (grand central) or ohare at
-		   f3000000, with interrupt control registers at f3000020. */
-		addr = (unsigned long) ioremap(0xf3000000, 0x40);
-		pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
-	}
-
-	/* PowerBooks 3400 and 3500 can have a second controller in a second
-	   ohare chip, on the combo ethernet/modem card */
-	if (machine_is_compatible("AAPL,3400/2400")
-	     || machine_is_compatible("AAPL,3500"))
-		irq_cascade = enable_second_ohare();
-
-	/* disable all interrupts in all controllers */
-	for (i = 0; i * 32 < max_irqs; ++i)
-		out_le32(&pmac_irq_hw[i]->enable, 0);
-	/* mark level interrupts */
-	for (i = 0; i < max_irqs; i++)
-		if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
-			irq_desc[i].status = IRQ_LEVEL;
-
-	/* get interrupt line of secondary interrupt controller */
-	if (irq_cascade >= 0) {
-		printk(KERN_INFO "irq: secondary controller on irq %d\n",
-			(int)irq_cascade);
-		for ( i = max_real_irqs ; i < max_irqs ; i++ )
-			irq_desc[i].handler = &gatwick_pic;
-		setup_irq(irq_cascade, &gatwick_cascade_action);
-	}
-	printk("System has %d possible interrupts\n", max_irqs);
-	if (max_irqs != max_real_irqs)
-		printk(KERN_DEBUG "%d interrupts on main controller\n",
-			max_real_irqs);
-
-#ifdef CONFIG_XMON
-	setup_irq(20, &xmon_action);
-#endif	/* CONFIG_XMON */
-#endif	/* CONFIG_PPC32 */
+	pmac_pic_probe_oldstyle();
+#endif
 }
 
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h
index 2ad25e1..21c7b0f 100644
--- a/arch/powerpc/platforms/powermac/pmac.h
+++ b/arch/powerpc/platforms/powermac/pmac.h
@@ -42,10 +42,6 @@
 	unsigned long data_port, unsigned long ctrl_port, int *irq);
 
 extern int pmac_nvram_init(void);
-
-extern struct hw_interrupt_type pmac_pic;
-
-void pmac_pic_init(void);
-int pmac_get_irq(struct pt_regs *regs);
+extern void pmac_pic_init(void);
 
 #endif /* __PMAC_H__ */
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 7acb054..3b1a9d4 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -60,6 +60,7 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
+#include <asm/kexec.h>
 #include <asm/pci-bridge.h>
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
@@ -74,8 +75,8 @@
 #include <asm/iommu.h>
 #include <asm/smu.h>
 #include <asm/pmc.h>
-#include <asm/mpic.h>
 #include <asm/lmb.h>
+#include <asm/udbg.h>
 
 #include "pmac.h"
 
@@ -321,16 +322,6 @@
 	l2cr_init();
 #endif /* CONFIG_PPC32 */
 
-#ifdef CONFIG_PPC64
-	/* Probe motherboard chipset */
-	/* this is done earlier in setup_arch for 32-bit */
-	pmac_feature_init();
-
-	/* We can NAP */
-	powersave_nap = 1;
-	printk(KERN_INFO "Using native/NAP idle loop\n");
-#endif
-
 #ifdef CONFIG_KGDB
 	zs_kgdb_hook(0);
 #endif
@@ -354,7 +345,7 @@
 
 #ifdef CONFIG_SMP
 	/* Check for Core99 */
-	if (find_devices("uni-n") || find_devices("u3"))
+	if (find_devices("uni-n") || find_devices("u3") || find_devices("u4"))
 		smp_ops = &core99_smp_ops;
 #ifdef CONFIG_PPC32
 	else
@@ -621,37 +612,33 @@
 	 * and call ioremap
 	 */
 	hpte_init_native();
+#endif
 
-	/* Init SCC */
-	if (strstr(cmd_line, "sccdbg")) {
-		sccdbg = 1;
-		udbg_init_scc(NULL);
+	/* Enable early btext debug if requested */
+	if (strstr(cmd_line, "btextdbg")) {
+		udbg_adb_init_early();
+		register_early_udbg_console();
 	}
 
+	/* Probe motherboard chipset */
+	pmac_feature_init();
+
+	/* We can NAP */
+	powersave_nap = 1;
+	printk(KERN_INFO "Using native/NAP idle loop\n");
+
+	/* Initialize debug stuff */
+	udbg_scc_init(!!strstr(cmd_line, "sccdbg"));
+	udbg_adb_init(!!strstr(cmd_line, "btextdbg"));
+
+#ifdef CONFIG_PPC64
 	/* Setup interrupt mapping options */
 	ppc64_interrupt_controller = IC_OPEN_PIC;
 
-	iommu_init_early_u3();
+	iommu_init_early_dart();
 #endif
 }
 
-static void __init pmac_progress(char *s, unsigned short hex)
-{
-#ifdef CONFIG_PPC64
-	if (sccdbg) {
-		udbg_puts(s);
-		udbg_puts("\n");
-		return;
-	}
-#endif
-#ifdef CONFIG_BOOTX_TEXT
-	if (boot_text_mapped) {
-		btext_drawstring(s);
-		btext_drawchar('\n');
-	}
-#endif /* CONFIG_BOOTX_TEXT */
-}
-
 /*
  * pmac has no legacy IO, anything calling this function has to
  * fail or bad things will happen
@@ -663,35 +650,14 @@
 
 static int __init pmac_declare_of_platform_devices(void)
 {
-	struct device_node *np, *npp;
+	struct device_node *np;
 
-	np = find_devices("uni-n");
-	if (np) {
-		for (np = np->child; np != NULL; np = np->sibling)
-			if (strncmp(np->name, "i2c", 3) == 0) {
-				of_platform_device_create(np, "uni-n-i2c",
-							  NULL);
-				break;
-			}
-	}
-	np = find_devices("valkyrie");
+	np = of_find_node_by_name(NULL, "valkyrie");
 	if (np)
 		of_platform_device_create(np, "valkyrie", NULL);
-	np = find_devices("platinum");
+	np = of_find_node_by_name(NULL, "platinum");
 	if (np)
 		of_platform_device_create(np, "platinum", NULL);
-
-	npp = of_find_node_by_name(NULL, "u3");
-	if (npp) {
-		for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) {
-			if (strncmp(np->name, "i2c", 3) == 0) {
-				of_platform_device_create(np, "u3-i2c", NULL);
-				of_node_put(np);
-				break;
-			}
-		}
-		of_node_put(npp);
-	}
         np = of_find_node_by_type(NULL, "smu");
         if (np) {
 		of_platform_device_create(np, "smu", NULL);
@@ -718,7 +684,7 @@
 	 * occupies having to be broken up so the DART itself is not
 	 * part of the cacheable linar mapping
 	 */
-	alloc_u3_dart_table();
+	alloc_dart_table();
 #endif
 
 #ifdef CONFIG_PMAC_SMU
@@ -734,15 +700,17 @@
 }
 
 #ifdef CONFIG_PPC64
-static int pmac_probe_mode(struct pci_bus *bus)
+/* Move that to pci.c */
+static int pmac_pci_probe_mode(struct pci_bus *bus)
 {
 	struct device_node *node = bus->sysdata;
 
 	/* We need to use normal PCI probing for the AGP bus,
-	   since the device for the AGP bridge isn't in the tree. */
-	if (bus->self == NULL && device_is_compatible(node, "u3-agp"))
+	 * since the device for the AGP bridge isn't in the tree.
+	 */
+	if (bus->self == NULL && (device_is_compatible(node, "u3-agp") ||
+				  device_is_compatible(node, "u4-pcie")))
 		return PCI_PROBE_NORMAL;
-
 	return PCI_PROBE_DEVTREE;
 }
 #endif
@@ -756,7 +724,7 @@
 	.init_early		= pmac_init_early,
 	.show_cpuinfo		= pmac_show_cpuinfo,
 	.init_IRQ		= pmac_pic_init,
-	.get_irq		= mpic_get_irq,	/* changed later */
+	.get_irq		= NULL,	/* changed later */
 	.pcibios_fixup		= pmac_pcibios_fixup,
 	.restart		= pmac_restart,
 	.power_off		= pmac_power_off,
@@ -768,12 +736,17 @@
 	.calibrate_decr		= pmac_calibrate_decr,
 	.feature_call		= pmac_do_feature_call,
 	.check_legacy_ioport	= pmac_check_legacy_ioport,
-	.progress		= pmac_progress,
+	.progress		= udbg_progress,
 #ifdef CONFIG_PPC64
-	.pci_probe_mode		= pmac_probe_mode,
+	.pci_probe_mode		= pmac_pci_probe_mode,
 	.idle_loop		= native_idle,
 	.enable_pmcs		= power4_enable_pmcs,
+#ifdef CONFIG_KEXEC
+	.machine_kexec		= default_machine_kexec,
+	.machine_kexec_prepare	= default_machine_kexec_prepare,
+	.machine_crash_shutdown	= default_machine_crash_shutdown,
 #endif
+#endif /* CONFIG_PPC64 */
 #ifdef CONFIG_PPC32
 	.pcibios_enable_device_hook = pmac_pci_enable_device_hook,
 	.pcibios_after_init	= pmac_pcibios_after_init,
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index fb2a7c7..0df2cdc 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -52,8 +52,9 @@
 #include <asm/cacheflush.h>
 #include <asm/keylargo.h>
 #include <asm/pmac_low_i2c.h>
+#include <asm/pmac_pfunc.h>
 
-#undef DEBUG
+#define DEBUG
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -62,6 +63,7 @@
 #endif
 
 extern void __secondary_start_pmac_0(void);
+extern int pmac_pfunc_base_install(void);
 
 #ifdef CONFIG_PPC32
 
@@ -361,7 +363,6 @@
 	set_dec(tb_ticks_per_jiffy);
 	/* XXX fixme */
 	set_tb(0, 0);
-	last_jiffy_stamp(cpu_nr) = 0;
 
 	if (cpu_nr > 0) {
 		mb();
@@ -429,15 +430,62 @@
 };
 #endif /* CONFIG_PPC32 - actually powersurge support */
 
+/*
+ * Core 99 and later support
+ */
+
+static void (*pmac_tb_freeze)(int freeze);
+static unsigned long timebase;
+static int tb_req;
+
+static void smp_core99_give_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	while(!tb_req)
+		barrier();
+	tb_req = 0;
+	(*pmac_tb_freeze)(1);
+	mb();
+	timebase = get_tb();
+	mb();
+	while (timebase)
+		barrier();
+	mb();
+	(*pmac_tb_freeze)(0);
+	mb();
+
+	local_irq_restore(flags);
+}
+
+
+static void __devinit smp_core99_take_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	tb_req = 1;
+	mb();
+	while (!timebase)
+		barrier();
+	mb();
+	set_tb(timebase >> 32, timebase & 0xffffffff);
+	timebase = 0;
+	mb();
+	set_dec(tb_ticks_per_jiffy/2);
+
+	local_irq_restore(flags);
+}
+
 #ifdef CONFIG_PPC64
 /*
  * G5s enable/disable the timebase via an i2c-connected clock chip.
  */
-static struct device_node *pmac_tb_clock_chip_host;
+static struct pmac_i2c_bus *pmac_tb_clock_chip_host;
 static u8 pmac_tb_pulsar_addr;
-static void (*pmac_tb_freeze)(int freeze);
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned long timebase;
 
 static void smp_core99_cypress_tb_freeze(int freeze)
 {
@@ -447,19 +495,20 @@
 	/* Strangely, the device-tree says address is 0xd2, but darwin
 	 * accesses 0xd0 ...
 	 */
-	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
-	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-			       0xd0 | pmac_low_i2c_read,
-			       0x81, &data, 1);
+	pmac_i2c_setmode(pmac_tb_clock_chip_host,
+			 pmac_i2c_mode_combined);
+	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+			   0xd0 | pmac_i2c_read,
+			   1, 0x81, &data, 1);
 	if (rc != 0)
 		goto bail;
 
 	data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);
 
-       	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
-	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-			       0xd0 | pmac_low_i2c_write,
-			       0x81, &data, 1);
+       	pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
+	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+			   0xd0 | pmac_i2c_write,
+			   1, 0x81, &data, 1);
 
  bail:
 	if (rc != 0) {
@@ -475,19 +524,20 @@
 	u8 data;
 	int rc;
 
-	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
-	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-			       pmac_tb_pulsar_addr | pmac_low_i2c_read,
-			       0x2e, &data, 1);
+	pmac_i2c_setmode(pmac_tb_clock_chip_host,
+			 pmac_i2c_mode_combined);
+	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+			   pmac_tb_pulsar_addr | pmac_i2c_read,
+			   1, 0x2e, &data, 1);
 	if (rc != 0)
 		goto bail;
 
 	data = (data & 0x88) | (freeze ? 0x11 : 0x22);
 
-	pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
-	rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-			       pmac_tb_pulsar_addr | pmac_low_i2c_write,
-			       0x2e, &data, 1);
+	pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
+	rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+			   pmac_tb_pulsar_addr | pmac_i2c_write,
+			   1, 0x2e, &data, 1);
  bail:
 	if (rc != 0) {
 		printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",
@@ -496,54 +546,14 @@
 	}
 }
 
-
-static void smp_core99_give_timebase(void)
-{
-	/* Open i2c bus for synchronous access */
-	if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0))
-		panic("Can't open i2c for TB sync !\n");
-
-	spin_lock(&timebase_lock);
-	(*pmac_tb_freeze)(1);
-	mb();
-	timebase = get_tb();
-	spin_unlock(&timebase_lock);
-
-	while (timebase)
-		barrier();
-
-	spin_lock(&timebase_lock);
-	(*pmac_tb_freeze)(0);
-	spin_unlock(&timebase_lock);
-
-	/* Close i2c bus */
-	pmac_low_i2c_close(pmac_tb_clock_chip_host);
-}
-
-
-static void __devinit smp_core99_take_timebase(void)
-{
-	while (!timebase)
-		barrier();
-	spin_lock(&timebase_lock);
-	set_tb(timebase >> 32, timebase & 0xffffffff);
-	timebase = 0;
-	spin_unlock(&timebase_lock);
-}
-
-static void __init smp_core99_setup(int ncpus)
+static void __init smp_core99_setup_i2c_hwsync(int ncpus)
 {
 	struct device_node *cc = NULL;	
 	struct device_node *p;
+	const char *name = NULL;
 	u32 *reg;
 	int ok;
 
-	/* HW sync only on these platforms */
-	if (!machine_is_compatible("PowerMac7,2") &&
-	    !machine_is_compatible("PowerMac7,3") &&
-	    !machine_is_compatible("RackMac3,1"))
-		return;
-
 	/* Look for the clock chip */
 	while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {
 		p = of_get_parent(cc);
@@ -552,124 +562,86 @@
 		if (!ok)
 			continue;
 
+		pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
+		if (pmac_tb_clock_chip_host == NULL)
+			continue;
 		reg = (u32 *)get_property(cc, "reg", NULL);
 		if (reg == NULL)
 			continue;
-
 		switch (*reg) {
 		case 0xd2:
-			if (device_is_compatible(cc, "pulsar-legacy-slewing")) {
+			if (device_is_compatible(cc,"pulsar-legacy-slewing")) {
 				pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
 				pmac_tb_pulsar_addr = 0xd2;
-				printk(KERN_INFO "Timebase clock is Pulsar chip\n");
+				name = "Pulsar";
 			} else if (device_is_compatible(cc, "cy28508")) {
 				pmac_tb_freeze = smp_core99_cypress_tb_freeze;
-				printk(KERN_INFO "Timebase clock is Cypress chip\n");
+				name = "Cypress";
 			}
 			break;
 		case 0xd4:
 			pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
 			pmac_tb_pulsar_addr = 0xd4;
-			printk(KERN_INFO "Timebase clock is Pulsar chip\n");
+			name = "Pulsar";
 			break;
 		}
-		if (pmac_tb_freeze != NULL) {
-			pmac_tb_clock_chip_host = of_get_parent(cc);
-			of_node_put(cc);
+		if (pmac_tb_freeze != NULL)
 			break;
+	}
+	if (pmac_tb_freeze != NULL) {
+		/* Open i2c bus for synchronous access */
+		if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) {
+			printk(KERN_ERR "Failed top open i2c bus for clock"
+			       " sync, fallback to software sync !\n");
+			goto no_i2c_sync;
 		}
+		printk(KERN_INFO "Processor timebase sync using %s i2c clock\n",
+		       name);
+		return;
 	}
-	if (pmac_tb_freeze == NULL) {
-		smp_ops->give_timebase = smp_generic_give_timebase;
-		smp_ops->take_timebase = smp_generic_take_timebase;
-	}
+ no_i2c_sync:
+	pmac_tb_freeze = NULL;
+	pmac_tb_clock_chip_host = NULL;
 }
 
-/* nothing to do here, caches are already set up by service processor */
-static inline void __devinit core99_init_caches(int cpu)
+
+
+/*
+ * Newer G5s uses a platform function
+ */
+
+static void smp_core99_pfunc_tb_freeze(int freeze)
 {
+	struct device_node *cpus;
+	struct pmf_args args;
+
+	cpus = of_find_node_by_path("/cpus");
+	BUG_ON(cpus == NULL);
+	args.count = 1;
+	args.u[0].v = !freeze;
+	pmf_call_function(cpus, "cpu-timebase", &args);
+	of_node_put(cpus);
 }
 
 #else /* CONFIG_PPC64 */
 
 /*
- * SMP G4 powermacs use a GPIO to enable/disable the timebase.
+ * SMP G4 use a GPIO to enable/disable the timebase.
  */
 
 static unsigned int core99_tb_gpio;	/* Timebase freeze GPIO */
 
-static unsigned int pri_tb_hi, pri_tb_lo;
-static unsigned int pri_tb_stamp;
-
-/* not __init, called in sleep/wakeup code */
-void smp_core99_give_timebase(void)
+static void smp_core99_gpio_tb_freeze(int freeze)
 {
-	unsigned long flags;
-	unsigned int t;
-
-	/* wait for the secondary to be in take_timebase */
-	for (t = 100000; t > 0 && !sec_tb_reset; --t)
-		udelay(10);
-	if (!sec_tb_reset) {
-		printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
-		return;
-	}
-
-	/* freeze the timebase and read it */
-	/* disable interrupts so the timebase is disabled for the
-	   shortest possible time */
-	local_irq_save(flags);
-	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+	if (freeze)
+		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+	else
+		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
 	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-	mb();
-	pri_tb_hi = get_tbu();
-	pri_tb_lo = get_tbl();
-	pri_tb_stamp = last_jiffy_stamp(smp_processor_id());
-	mb();
-
-	/* tell the secondary we're ready */
-	sec_tb_reset = 2;
-	mb();
-
-	/* wait for the secondary to have taken it */
-	/* note: can't use udelay here, since it needs the timebase running */
-	for (t = 10000000; t > 0 && sec_tb_reset; --t)
-		barrier();
-	if (sec_tb_reset)
-		/* XXX BUG_ON here? */
-		printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
-
-	/* Now, restart the timebase by leaving the GPIO to an open collector */
-       	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
-        pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-	local_irq_restore(flags);
 }
 
-/* not __init, called in sleep/wakeup code */
-void smp_core99_take_timebase(void)
-{
-	unsigned long flags;
 
-	/* tell the primary we're here */
-	sec_tb_reset = 1;
-	mb();
-
-	/* wait for the primary to set pri_tb_hi/lo */
-	while (sec_tb_reset < 2)
-		mb();
-
-	/* set our stuff the same as the primary */
-	local_irq_save(flags);
-	set_dec(1);
-	set_tb(pri_tb_hi, pri_tb_lo);
-	last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;
-	mb();
-
-	/* tell the primary we're done */
-       	sec_tb_reset = 0;
-	mb();
-	local_irq_restore(flags);
-}
+#endif /* !CONFIG_PPC64 */
 
 /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */
 volatile static long int core99_l2_cache;
@@ -677,6 +649,7 @@
 
 static void __devinit core99_init_caches(int cpu)
 {
+#ifndef CONFIG_PPC64
 	if (!cpu_has_feature(CPU_FTR_L2CR))
 		return;
 
@@ -702,30 +675,76 @@
 		_set_L3CR(core99_l3_cache);
 		printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
 	}
+#endif /* !CONFIG_PPC64 */
 }
 
 static void __init smp_core99_setup(int ncpus)
 {
-	struct device_node *cpu;
-	u32 *tbprop = NULL;
-	int i;
+#ifdef CONFIG_PPC64
 
-	core99_tb_gpio = KL_GPIO_TB_ENABLE;	/* default value */
-	cpu = of_find_node_by_type(NULL, "cpu");
-	if (cpu != NULL) {
-		tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL);
-		if (tbprop)
-			core99_tb_gpio = *tbprop;
-		of_node_put(cpu);
+	/* i2c based HW sync on some G5s */
+	if (machine_is_compatible("PowerMac7,2") ||
+	    machine_is_compatible("PowerMac7,3") ||
+	    machine_is_compatible("RackMac3,1"))
+		smp_core99_setup_i2c_hwsync(ncpus);
+
+	/* pfunc based HW sync on recent G5s */
+	if (pmac_tb_freeze == NULL) {
+		struct device_node *cpus =
+			of_find_node_by_path("/cpus");
+		if (cpus &&
+		    get_property(cpus, "platform-cpu-timebase", NULL)) {
+			pmac_tb_freeze = smp_core99_pfunc_tb_freeze;
+			printk(KERN_INFO "Processor timebase sync using"
+			       " platform function\n");
+		}
 	}
 
-	/* XXX should get this from reg properties */
-	for (i = 1; i < ncpus; ++i)
-		smp_hw_index[i] = i;
-	powersave_nap = 0;
-}
+#else /* CONFIG_PPC64 */
+
+	/* GPIO based HW sync on ppc32 Core99 */
+	if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) {
+		struct device_node *cpu;
+		u32 *tbprop = NULL;
+
+		core99_tb_gpio = KL_GPIO_TB_ENABLE;	/* default value */
+		cpu = of_find_node_by_type(NULL, "cpu");
+		if (cpu != NULL) {
+			tbprop = (u32 *)get_property(cpu, "timebase-enable",
+						     NULL);
+			if (tbprop)
+				core99_tb_gpio = *tbprop;
+			of_node_put(cpu);
+		}
+		pmac_tb_freeze = smp_core99_gpio_tb_freeze;
+		printk(KERN_INFO "Processor timebase sync using"
+		       " GPIO 0x%02x\n", core99_tb_gpio);
+	}
+
+#endif /* CONFIG_PPC64 */
+
+	/* No timebase sync, fallback to software */
+	if (pmac_tb_freeze == NULL) {
+		smp_ops->give_timebase = smp_generic_give_timebase;
+		smp_ops->take_timebase = smp_generic_take_timebase;
+		printk(KERN_INFO "Processor timebase sync using software\n");
+	}
+
+#ifndef CONFIG_PPC64
+	{
+		int i;
+
+		/* XXX should get this from reg properties */
+		for (i = 1; i < ncpus; ++i)
+			smp_hw_index[i] = i;
+	}
 #endif
 
+	/* 32 bits SMP can't NAP */
+	if (!machine_is_compatible("MacRISC4"))
+		powersave_nap = 0;
+}
+
 static int __init smp_core99_probe(void)
 {
 	struct device_node *cpus;
@@ -743,8 +762,19 @@
 	if (ncpus <= 1)
 		return 1;
 
+	/* We need to perform some early initialisations before we can start
+	 * setting up SMP as we are running before initcalls
+	 */
+	pmac_pfunc_base_install();
+	pmac_i2c_init();
+
+	/* Setup various bits like timebase sync method, ability to nap, ... */
 	smp_core99_setup(ncpus);
+
+	/* Install IPIs */
 	mpic_request_ipis();
+
+	/* Collect l2cr and l3cr values from CPU 0 */
 	core99_init_caches(0);
 
 	return ncpus;
@@ -753,14 +783,15 @@
 static void __devinit smp_core99_kick_cpu(int nr)
 {
 	unsigned int save_vector;
-	unsigned long new_vector;
-	unsigned long flags;
+	unsigned long target, flags;
 	volatile unsigned int *vector
 		 = ((volatile unsigned int *)(KERNELBASE+0x100));
 
 	if (nr < 0 || nr > 3)
 		return;
-	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
+
+	if (ppc_md.progress)
+		ppc_md.progress("smp_core99_kick_cpu", 0x346);
 
 	local_irq_save(flags);
 	local_irq_disable();
@@ -768,14 +799,11 @@
 	/* Save reset vector */
 	save_vector = *vector;
 
-	/* Setup fake reset vector that does	
+	/* Setup fake reset vector that does
 	 *   b __secondary_start_pmac_0 + nr*8 - KERNELBASE
 	 */
-	new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8;
-	*vector = 0x48000002 + new_vector - KERNELBASE;
-
-	/* flush data cache and inval instruction cache */
-	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+	target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
+	create_branch((unsigned long)vector, target, BRANCH_SET_LINK);
 
 	/* Put some life in our friend */
 	pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
@@ -805,17 +833,25 @@
 	mpic_setup_this_cpu();
 
 	if (cpu_nr == 0) {
-#ifdef CONFIG_POWER4
+#ifdef CONFIG_PPC64
 		extern void g5_phy_disable_cpu1(void);
 
+		/* Close i2c bus if it was used for tb sync */
+		if (pmac_tb_clock_chip_host) {
+			pmac_i2c_close(pmac_tb_clock_chip_host);
+			pmac_tb_clock_chip_host	= NULL;
+		}
+
 		/* If we didn't start the second CPU, we must take
 		 * it off the bus
 		 */
 		if (machine_is_compatible("MacRISC4") &&
 		    num_online_cpus() < 2)		
 			g5_phy_disable_cpu1();
-#endif /* CONFIG_POWER4 */
-		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+#endif /* CONFIG_PPC64 */
+
+		if (ppc_md.progress)
+			ppc_md.progress("core99_setup_cpu 0 done", 0x349);
 	}
 }
 
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index feb0a94..5d9afa1 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -258,15 +258,20 @@
 	volatile unsigned char __iomem *via;
 	int count = VIA_TIMER_FREQ_6 / 100;
 	unsigned int dstart, dend;
+	struct resource rsrc;
 
-	vias = find_devices("via-cuda");
+	vias = of_find_node_by_name(NULL, "via-cuda");
 	if (vias == 0)
-		vias = find_devices("via-pmu");
+		vias = of_find_node_by_name(NULL, "via-pmu");
 	if (vias == 0)
-		vias = find_devices("via");
-	if (vias == 0 || vias->n_addrs == 0)
+		vias = of_find_node_by_name(NULL, "via");
+	if (vias == 0 || of_address_to_resource(vias, 0, &rsrc))
 		return 0;
-	via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
+	via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+	if (via == NULL) {
+		printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
+		return 0;
+	}
 
 	/* set timer 1 for continuous interrupts */
 	out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c
new file mode 100644
index 0000000..06c8265
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/udbg_adb.c
@@ -0,0 +1,221 @@
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/bitops.h>
+#include <linux/ptrace.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/cuda.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/xmon.h>
+#include <asm/prom.h>
+#include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/errno.h>
+#include <asm/pmac_feature.h>
+#include <asm/processor.h>
+#include <asm/delay.h>
+#include <asm/btext.h>
+#include <asm/time.h>
+#include <asm/udbg.h>
+
+/*
+ * This implementation is "special", it can "patch" the current
+ * udbg implementation and work on top of it. It must thus be
+ * initialized last
+ */
+
+static void (*udbg_adb_old_putc)(char c);
+static int (*udbg_adb_old_getc)(void);
+static int (*udbg_adb_old_getc_poll)(void);
+
+static enum {
+	input_adb_none,
+	input_adb_pmu,
+	input_adb_cuda,
+} input_type = input_adb_none;
+
+int xmon_wants_key, xmon_adb_keycode;
+
+static inline void udbg_adb_poll(void)
+{
+#ifdef CONFIG_ADB_PMU
+	if (input_type == input_adb_pmu)
+		pmu_poll_adb();
+#endif /* CONFIG_ADB_PMU */
+#ifdef CONFIG_ADB_CUDA
+	if (input_type == input_adb_cuda)
+		cuda_poll();
+#endif /* CONFIG_ADB_CUDA */
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+
+static int udbg_adb_use_btext;
+static int xmon_adb_shiftstate;
+
+static unsigned char xmon_keytab[128] =
+	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
+	"yt123465=97-80]o"				/* 0x10 - 0x1f */
+	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
+	"\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"		/* 0x30 - 0x3f */
+	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
+	"\0\0000123456789\0\0\0";			/* 0x50 - 0x5f */
+
+static unsigned char xmon_shift_keytab[128] =
+	"ASDFHGZXCV\000BQWER"				/* 0x00 - 0x0f */
+	"YT!@#$^%+(&_*)}O"				/* 0x10 - 0x1f */
+	"U{IP\rLJ\"K:|<?NM>"				/* 0x20 - 0x2f */
+	"\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"		/* 0x30 - 0x3f */
+	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
+	"\0\0000123456789\0\0\0";			/* 0x50 - 0x5f */
+
+static int udbg_adb_local_getc(void)
+{
+	int k, t, on;
+
+	xmon_wants_key = 1;
+	for (;;) {
+		xmon_adb_keycode = -1;
+		t = 0;
+		on = 0;
+		k = -1;
+		do {
+			if (--t < 0) {
+				on = 1 - on;
+				btext_drawchar(on? 0xdb: 0x20);
+				btext_drawchar('\b');
+				t = 200000;
+			}
+			udbg_adb_poll();
+			if (udbg_adb_old_getc_poll)
+				k = udbg_adb_old_getc_poll();
+		} while (k == -1 && xmon_adb_keycode == -1);
+		if (on)
+			btext_drawstring(" \b");
+		if (k != -1)
+			return k;
+		k = xmon_adb_keycode;
+
+		/* test for shift keys */
+		if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
+			xmon_adb_shiftstate = (k & 0x80) == 0;
+			continue;
+		}
+		if (k >= 0x80)
+			continue;	/* ignore up transitions */
+		k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
+		if (k != 0)
+			break;
+	}
+	xmon_wants_key = 0;
+	return k;
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static int udbg_adb_getc(void)
+{
+#ifdef CONFIG_BOOTX_TEXT
+	if (udbg_adb_use_btext && input_type != input_adb_none)
+		return udbg_adb_local_getc();
+#endif
+	if (udbg_adb_old_getc)
+		return udbg_adb_old_getc();
+	return -1;
+}
+
+/* getc_poll() is not really used, unless you have the xmon-over modem
+ * hack that doesn't quite concern us here, thus we just poll the low level
+ * ADB driver to prevent it from timing out and call back the original poll
+ * routine.
+ */
+static int udbg_adb_getc_poll(void)
+{
+	udbg_adb_poll();
+
+	if (udbg_adb_old_getc_poll)
+		return udbg_adb_old_getc_poll();
+	return -1;
+}
+
+static void udbg_adb_putc(char c)
+{
+#ifdef CONFIG_BOOTX_TEXT
+	if (udbg_adb_use_btext)
+		btext_drawchar(c);
+#endif
+	if (udbg_adb_old_putc)
+		return udbg_adb_old_putc(c);
+}
+
+void udbg_adb_init_early(void)
+{
+#ifdef CONFIG_BOOTX_TEXT
+	if (btext_find_display(1) == 0) {
+		udbg_adb_use_btext = 1;
+		udbg_putc = udbg_adb_putc;
+	}
+#endif
+}
+
+int udbg_adb_init(int force_btext)
+{
+	struct device_node *np;
+
+	/* Capture existing callbacks */
+	udbg_adb_old_putc = udbg_putc;
+	udbg_adb_old_getc = udbg_getc;
+	udbg_adb_old_getc_poll = udbg_getc_poll;
+
+	/* Check if our early init was already called */
+	if (udbg_adb_old_putc == udbg_adb_putc)
+		udbg_adb_old_putc = NULL;
+#ifdef CONFIG_BOOTX_TEXT
+	if (udbg_adb_old_putc == btext_drawchar)
+		udbg_adb_old_putc = NULL;
+#endif
+
+	/* Set ours as output */
+	udbg_putc = udbg_adb_putc;
+	udbg_getc = udbg_adb_getc;
+	udbg_getc_poll = udbg_adb_getc_poll;
+
+#ifdef CONFIG_BOOTX_TEXT
+	/* Check if we should use btext output */
+	if (btext_find_display(force_btext) == 0)
+		udbg_adb_use_btext = 1;
+#endif
+
+	/* See if there is a keyboard in the device tree with a parent
+	 * of type "adb". If not, we return a failure, but we keep the
+	 * bext output set for now
+	 */
+	for (np = NULL; (np = of_find_node_by_name(np, "keyboard")) != NULL;) {
+		struct device_node *parent = of_get_parent(np);
+		int found = (parent && strcmp(parent->type, "adb") == 0);
+		of_node_put(parent);
+		if (found)
+			break;
+	}
+	if (np == NULL)
+		return -ENODEV;
+	of_node_put(np);
+
+#ifdef CONFIG_ADB_PMU
+	if (find_via_pmu())
+		input_type = input_adb_pmu;
+#endif
+#ifdef CONFIG_ADB_CUDA
+	if (find_via_cuda())
+		input_type = input_adb_cuda;
+#endif
+
+	/* Same as above: nothing found, keep btext set for output */
+	if (input_type == input_adb_none)
+		return -ENODEV;
+
+	return 0;
+}
diff --git a/arch/powerpc/kernel/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
similarity index 66%
rename from arch/powerpc/kernel/udbg_scc.c
rename to arch/powerpc/platforms/powermac/udbg_scc.c
index 820c535..e87d53a 100644
--- a/arch/powerpc/kernel/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -25,7 +25,7 @@
 static volatile u8 __iomem *sccc;
 static volatile u8 __iomem *sccd;
 
-static void udbg_scc_putc(unsigned char c)
+static void udbg_scc_putc(char c)
 {
 	if (sccc) {
 		while ((in_8(sccc) & SCC_TXRDY) == 0)
@@ -47,14 +47,14 @@
 	return -1;
 }
 
-static unsigned char udbg_scc_getc(void)
+static int udbg_scc_getc(void)
 {
 	if (sccc) {
 		while ((in_8(sccc) & SCC_RXRDY) == 0)
 			;
 		return in_8(sccd);
 	}
-	return 0;
+	return -1;
 }
 
 static unsigned char scc_inittab[] = {
@@ -67,38 +67,59 @@
     3,  0xc1,		/* rx enable, 8 bits */
 };
 
-void udbg_init_scc(struct device_node *np)
+void udbg_scc_init(int force_scc)
 {
 	u32 *reg;
 	unsigned long addr;
+	struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
+	struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
+	char *path;
 	int i, x;
 
-	if (np == NULL)
-		np = of_find_node_by_name(NULL, "escc");
-	if (np == NULL || np->parent == NULL)
-		return;
+	escc = of_find_node_by_name(NULL, "escc");
+	if (escc == NULL)
+		goto bail;
+	macio = of_get_parent(escc);
+	if (macio == NULL)
+		goto bail;
+	path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+	if (path != NULL)
+		stdout = of_find_node_by_path(path);
+	for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
+		if (ch == stdout)
+			ch_def = of_node_get(ch);
+		if (strcmp(ch->name, "ch-a") == 0)
+			ch_a = of_node_get(ch);
+	}
+	if (ch_def == NULL && !force_scc)
+		goto bail;
 
-	udbg_printf("found SCC...\n");
+	ch = ch_def ? ch_def : ch_a;
+
 	/* Get address within mac-io ASIC */
-	reg = (u32 *)get_property(np, "reg", NULL);
+	reg = (u32 *)get_property(escc, "reg", NULL);
 	if (reg == NULL)
-		return;
+		goto bail;
 	addr = reg[0];
-	udbg_printf("local addr: %lx\n", addr);
+
 	/* Get address of mac-io PCI itself */
-	reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
+	reg = (u32 *)get_property(macio, "assigned-addresses", NULL);
 	if (reg == NULL)
-		return;
+		goto bail;
 	addr += reg[2];
-	udbg_printf("final addr: %lx\n", addr);
+
+	/* Lock the serial port */
+	pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
+			  PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
+
 
 	/* Setup for 57600 8N1 */
-	addr += 0x20;
+	if (ch == ch_a)
+		addr += 0x20;
 	sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
 	sccc += addr & ~PAGE_MASK;
 	sccd = sccc + 0x10;
 
-	udbg_printf("ioremap result sccc: %p\n", sccc);
 	mb();
 
 	for (i = 20000; i != 0; --i)
@@ -113,9 +134,17 @@
 	udbg_getc_poll = udbg_scc_getc_poll;
 
 	udbg_puts("Hello World !\n");
+
+ bail:
+	of_node_put(macio);
+	of_node_put(escc);
+	of_node_put(stdout);
+	of_node_put(ch_def);
+	of_node_put(ch_a);
 }
 
-static void udbg_real_scc_putc(unsigned char c)
+#ifdef CONFIG_PPC64
+static void udbg_real_scc_putc(char c)
 {
 	while ((real_readb(sccc) & SCC_TXRDY) == 0)
 		;
@@ -133,3 +162,4 @@
 	udbg_getc = NULL;
 	udbg_getc_poll = NULL;
 }
+#endif /* CONFIG_PPC64 */
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 06d5ef5..6accdd1 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -1,5 +1,5 @@
 obj-y			:= pci.o lpar.o hvCall.o nvram.o reconfig.o \
-			   setup.o iommu.o ras.o rtasd.o
+			   setup.o iommu.o ras.o rtasd.o pci_dlpar.o
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_IBMVIO)	+= vio.o
 obj-$(CONFIG_XICS)	+= xics.o
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index c8d2a40..7fbfd16 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1093,6 +1093,15 @@
 }
 EXPORT_SYMBOL_GPL(eeh_add_device_early);
 
+void eeh_add_device_tree_early(struct device_node *dn)
+{
+	struct device_node *sib;
+	for (sib = dn->child; sib; sib = sib->sibling)
+		eeh_add_device_tree_early(sib);
+	eeh_add_device_early(dn);
+}
+EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
+
 /**
  * eeh_add_device_late - perform EEH initialization for the indicated pci device
  * @dev: pci device for which to set up EEH
@@ -1147,6 +1156,23 @@
 }
 EXPORT_SYMBOL_GPL(eeh_remove_device);
 
+void eeh_remove_bus_device(struct pci_dev *dev)
+{
+	eeh_remove_device(dev);
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		struct pci_bus *bus = dev->subordinate;
+		struct list_head *ln;
+		if (!bus)
+			return; 
+		for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+			struct pci_dev *pdev = pci_dev_b(ln);
+			if (pdev)
+				eeh_remove_bus_device(pdev);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(eeh_remove_bus_device);
+
 static int proc_eeh_show(struct seq_file *m, void *v)
 {
 	unsigned int cpu;
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 2043659..169f914 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -436,7 +436,7 @@
 		return;
 	}
 
-	ppci = pdn->data;
+	ppci = PCI_DN(pdn);
 	if (!ppci->iommu_table) {
 		/* Bussubno hasn't been copied yet.
 		 * Do it now because iommu_table_setparms_lpar needs it.
@@ -483,10 +483,10 @@
 	 * an already allocated iommu table is found and use that.
 	 */
 
-	while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL)
+	while (dn && PCI_DN(dn) && PCI_DN(dn)->iommu_table == NULL)
 		dn = dn->parent;
 
-	if (dn && dn->data) {
+	if (dn && PCI_DN(dn)) {
 		PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table;
 	} else {
 		DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, pci_name(dev));
@@ -497,7 +497,7 @@
 {
 	int err = NOTIFY_OK;
 	struct device_node *np = node;
-	struct pci_dn *pci = np->data;
+	struct pci_dn *pci = PCI_DN(np);
 
 	switch (action) {
 	case PSERIES_RECONFIG_REMOVE:
@@ -533,7 +533,7 @@
 	 */
 	dn = pci_device_to_OF_node(dev);
 
-	for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table;
+	for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
 	     pdn = pdn->parent) {
 		dma_window = (unsigned int *)
 			get_property(pdn, "ibm,dma-window", NULL);
@@ -552,7 +552,7 @@
 		DBG("Found DMA window, allocating table\n");
 	}
 
-	pci = pdn->data;
+	pci = PCI_DN(pdn);
 	if (!pci->iommu_table) {
 		/* iommu_table_setparms_lpar needs bussubno. */
 		pci->bussubno = pci->phb->bus->number;
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index cf1bc11..1fe445a 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -24,6 +24,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/dma-mapping.h>
+#include <linux/console.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/page.h>
@@ -60,7 +61,7 @@
 int vtermno;	/* virtual terminal# for udbg  */
 
 #define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
-static void udbg_hvsi_putc(unsigned char c)
+static void udbg_hvsi_putc(char c)
 {
 	/* packet's seqno isn't used anyways */
 	uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c };
@@ -111,7 +112,7 @@
 	return ch;
 }
 
-static unsigned char udbg_hvsi_getc(void)
+static int udbg_hvsi_getc(void)
 {
 	int ch;
 	for (;;) {
@@ -127,7 +128,7 @@
 	}
 }
 
-static void udbg_putcLP(unsigned char c)
+static void udbg_putcLP(char c)
 {
 	char buf[16];
 	unsigned long rc;
@@ -172,7 +173,7 @@
 	return ch;
 }
 
-static unsigned char udbg_getcLP(void)
+static int udbg_getcLP(void)
 {
 	int ch;
 	for (;;) {
@@ -191,7 +192,7 @@
 /* call this from early_init() for a working debug console on
  * vterm capable LPAR machines
  */
-void udbg_init_debug_lpar(void)
+void __init udbg_init_debug_lpar(void)
 {
 	vtermno = 0;
 	udbg_putc = udbg_putcLP;
@@ -200,63 +201,54 @@
 }
 
 /* returns 0 if couldn't find or use /chosen/stdout as console */
-int find_udbg_vterm(void)
+void __init find_udbg_vterm(void)
 {
 	struct device_node *stdout_node;
 	u32 *termno;
 	char *name;
-	int found = 0;
+	int add_console;
 
 	/* find the boot console from /chosen/stdout */
 	if (!of_chosen)
-		return 0;
+		return;
 	name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
 	if (name == NULL)
-		return 0;
+		return;
 	stdout_node = of_find_node_by_path(name);
 	if (!stdout_node)
-		return 0;
-
-	/* now we have the stdout node; figure out what type of device it is. */
+		return;
 	name = (char *)get_property(stdout_node, "name", NULL);
 	if (!name) {
 		printk(KERN_WARNING "stdout node missing 'name' property!\n");
 		goto out;
 	}
+	/* The user has requested a console so this is already set up. */
+	add_console = !strstr(cmd_line, "console=");
 
-	if (strncmp(name, "vty", 3) == 0) {
-		if (device_is_compatible(stdout_node, "hvterm1")) {
-			termno = (u32 *)get_property(stdout_node, "reg", NULL);
-			if (termno) {
-				vtermno = termno[0];
-				udbg_putc = udbg_putcLP;
-				udbg_getc = udbg_getcLP;
-				udbg_getc_poll = udbg_getc_pollLP;
-				found = 1;
-			}
-		} else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
-			termno = (u32 *)get_property(stdout_node, "reg", NULL);
-			if (termno) {
-				vtermno = termno[0];
-				udbg_putc = udbg_hvsi_putc;
-				udbg_getc = udbg_hvsi_getc;
-				udbg_getc_poll = udbg_hvsi_getc_poll;
-				found = 1;
-			}
-		}
-	} else if (strncmp(name, "serial", 6)) {
-		/* XXX fix ISA serial console */
-		printk(KERN_WARNING "serial stdout on LPAR ('%s')! "
-				"can't print udbg messages\n",
-		       stdout_node->full_name);
-	} else {
-		printk(KERN_WARNING "don't know how to print to stdout '%s'\n",
-		       stdout_node->full_name);
+	/* Check if it's a virtual terminal */
+	if (strncmp(name, "vty", 3) != 0)
+		goto out;
+	termno = (u32 *)get_property(stdout_node, "reg", NULL);
+	if (termno == NULL)
+		goto out;
+	vtermno = termno[0];
+
+	if (device_is_compatible(stdout_node, "hvterm1")) {
+		udbg_putc = udbg_putcLP;
+		udbg_getc = udbg_getcLP;
+		udbg_getc_poll = udbg_getc_pollLP;
+		if (add_console)
+			add_preferred_console("hvc", termno[0] & 0xff, NULL);
+	} else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
+		vtermno = termno[0];
+		udbg_putc = udbg_hvsi_putc;
+		udbg_getc = udbg_hvsi_getc;
+		udbg_getc_poll = udbg_hvsi_getc_poll;
+		if (add_console)
+			add_preferred_console("hvsi", termno[0] & 0xff, NULL);
 	}
-
 out:
 	of_node_put(stdout_node);
-	return found;
 }
 
 void vpa_init(int cpu)
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
new file mode 100644
index 0000000..2193478
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -0,0 +1,174 @@
+/*
+ * PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code
+ * for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ * Copyright (C) 2005 International Business Machines
+ *
+ * Updates, 2005, John Rose <johnrose@austin.ibm.com>
+ * Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>
+
+static struct pci_bus *
+find_bus_among_children(struct pci_bus *bus,
+                        struct device_node *dn)
+{
+	struct pci_bus *child = NULL;
+	struct list_head *tmp;
+	struct device_node *busdn;
+
+	busdn = pci_bus_to_OF_node(bus);
+	if (busdn == dn)
+		return bus;
+
+	list_for_each(tmp, &bus->children) {
+		child = find_bus_among_children(pci_bus_b(tmp), dn);
+		if (child)
+			break;
+	};
+	return child;
+}
+
+struct pci_bus *
+pcibios_find_pci_bus(struct device_node *dn)
+{
+	struct pci_dn *pdn = dn->data;
+
+	if (!pdn  || !pdn->phb || !pdn->phb->bus)
+		return NULL;
+
+	return find_bus_among_children(pdn->phb->bus, dn);
+}
+
+/**
+ * pcibios_remove_pci_devices - remove all devices under this bus
+ *
+ * Remove all of the PCI devices under this bus both from the
+ * linux pci device tree, and from the powerpc EEH address cache.
+ */
+void
+pcibios_remove_pci_devices(struct pci_bus *bus)
+{
+	struct pci_dev *dev, *tmp;
+
+	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
+		eeh_remove_bus_device(dev);
+		pci_remove_bus_device(dev);
+	}
+}
+
+/* Must be called before pci_bus_add_devices */
+void
+pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		/*
+		 * Skip already-present devices (which are on the
+		 * global device list.)
+		 */
+		if (list_empty(&dev->global_list)) {
+			int i;
+
+			/* Need to setup IOMMU tables */
+			ppc_md.iommu_dev_setup(dev);
+
+			if(fix_bus)
+				pcibios_fixup_device_resources(dev, bus);
+			pci_read_irq_line(dev);
+			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+				struct resource *r = &dev->resource[i];
+
+				if (r->parent || !r->start || !r->flags)
+					continue;
+				pci_claim_resource(dev, i);
+			}
+		}
+	}
+}
+
+static int
+pcibios_pci_config_bridge(struct pci_dev *dev)
+{
+	u8 sec_busno;
+	struct pci_bus *child_bus;
+	struct pci_dev *child_dev;
+
+	/* Get busno of downstream bus */
+	pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
+
+	/* Add to children of PCI bridge dev->bus */
+	child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
+	if (!child_bus) {
+		printk (KERN_ERR "%s: could not add second bus\n", __FUNCTION__);
+		return -EIO;
+	}
+	sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
+
+	pci_scan_child_bus(child_bus);
+
+	list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
+		eeh_add_device_late(child_dev);
+	}
+
+	/* Fixup new pci devices without touching bus struct */
+	pcibios_fixup_new_pci_devices(child_bus, 0);
+
+	/* Make the discovered devices available */
+	pci_bus_add_devices(child_bus);
+	return 0;
+}
+
+/**
+ * pcibios_add_pci_devices - adds new pci devices to bus
+ *
+ * This routine will find and fixup new pci devices under
+ * the indicated bus. This routine presumes that there
+ * might already be some devices under this bridge, so
+ * it carefully tries to add only new devices.  (And that
+ * is how this routine differs from other, similar pcibios
+ * routines.)
+ */
+void
+pcibios_add_pci_devices(struct pci_bus * bus)
+{
+	int slotno, num;
+	struct pci_dev *dev;
+	struct device_node *dn = pci_bus_to_OF_node(bus);
+
+	eeh_add_device_tree_early(dn);
+
+	/* pci_scan_slot should find all children */
+	slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
+	num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
+	if (num) {
+		pcibios_fixup_new_pci_devices(bus, 1);
+		pci_bus_add_devices(bus);
+	}
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		eeh_add_device_late (dev);
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+			pcibios_pci_config_bridge(dev);
+	}
+}
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index fbd214d..b046bcf 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -49,14 +49,14 @@
 #include <asm/machdep.h>
 #include <asm/rtas.h>
 #include <asm/udbg.h>
+#include <asm/firmware.h>
+
+#include "ras.h"
 
 static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
 static DEFINE_SPINLOCK(ras_log_buf_lock);
 
-char mce_data_buf[RTAS_ERROR_LOG_MAX]
-;
-/* This is true if we are using the firmware NMI handler (typically LPAR) */
-extern int fwnmi_active;
+char mce_data_buf[RTAS_ERROR_LOG_MAX];
 
 static int ras_get_sensor_state_token;
 static int ras_check_exception_token;
@@ -280,7 +280,7 @@
 		printk("FWNMI: nmi-interlock failed: %d\n", ret);
 }
 
-void pSeries_system_reset_exception(struct pt_regs *regs)
+int pSeries_system_reset_exception(struct pt_regs *regs)
 {
 	if (fwnmi_active) {
 		struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
@@ -289,6 +289,7 @@
 		}
 		fwnmi_release_errinfo();
 	}
+	return 0; /* need to perform reset */
 }
 
 /*
diff --git a/arch/powerpc/platforms/pseries/ras.h b/arch/powerpc/platforms/pseries/ras.h
new file mode 100644
index 0000000..0e66b0d
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/ras.h
@@ -0,0 +1,9 @@
+#ifndef _PSERIES_RAS_H
+#define _PSERIES_RAS_H
+
+struct pt_regs;
+
+extern int pSeries_system_reset_exception(struct pt_regs *regs);
+extern int pSeries_machine_check_exception(struct pt_regs *regs);
+
+#endif /* _PSERIES_RAS_H */
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 4a465f0..8903cf6 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -56,6 +56,7 @@
 #include <asm/dma.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
+#include <asm/kexec.h>
 #include <asm/time.h>
 #include <asm/nvram.h>
 #include "xics.h"
@@ -68,6 +69,7 @@
 #include <asm/smp.h>
 
 #include "plpar_wrappers.h"
+#include "ras.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -76,16 +78,9 @@
 #endif
 
 extern void find_udbg_vterm(void);
-extern void system_reset_fwnmi(void);	/* from head.S */
-extern void machine_check_fwnmi(void);	/* from head.S */
-extern void generic_find_legacy_serial_ports(u64 *physport,
-		unsigned int *default_speed);
 
 int fwnmi_active;  /* TRUE if an FWNMI handler is present */
 
-extern void pSeries_system_reset_exception(struct pt_regs *regs);
-extern int pSeries_machine_check_exception(struct pt_regs *regs);
-
 static void pseries_shared_idle(void);
 static void pseries_dedicated_idle(void);
 
@@ -105,18 +100,22 @@
 
 /* Initialize firmware assisted non-maskable interrupts if
  * the firmware supports this feature.
- *
  */
 static void __init fwnmi_init(void)
 {
-	int ret;
+	unsigned long system_reset_addr, machine_check_addr;
+
 	int ibm_nmi_register = rtas_token("ibm,nmi-register");
 	if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE)
 		return;
-	ret = rtas_call(ibm_nmi_register, 2, 1, NULL,
-			__pa((unsigned long)system_reset_fwnmi),
-			__pa((unsigned long)machine_check_fwnmi));
-	if (ret == 0)
+
+	/* If the kernel's not linked at zero we point the firmware at low
+	 * addresses anyway, and use a trampoline to get to the real code. */
+	system_reset_addr  = __pa(system_reset_fwnmi) - PHYSICAL_START;
+	machine_check_addr = __pa(machine_check_fwnmi) - PHYSICAL_START;
+
+	if (0 == rtas_call(ibm_nmi_register, 2, 1, NULL, system_reset_addr,
+				machine_check_addr))
 		fwnmi_active = 1;
 }
 
@@ -323,15 +322,18 @@
 	ppc64_interrupt_controller = IC_INVALID;
 	for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) {
 		typep = (char *)get_property(np, "compatible", NULL);
-		if (strstr(typep, "open-pic"))
+		if (strstr(typep, "open-pic")) {
 			ppc64_interrupt_controller = IC_OPEN_PIC;
-		else if (strstr(typep, "ppc-xicp"))
+			break;
+		} else if (strstr(typep, "ppc-xicp")) {
 			ppc64_interrupt_controller = IC_PPC_XIC;
-		else
-			printk("pSeries_discover_pic: failed to recognize"
-			       " interrupt-controller\n");
-		break;
+			break;
+		}
 	}
+	if (ppc64_interrupt_controller == IC_INVALID)
+		printk("pSeries_discover_pic: failed to recognize"
+			" interrupt-controller\n");
+
 }
 
 static void pSeries_mach_cpu_die(void)
@@ -365,10 +367,7 @@
  */
 static void __init pSeries_init_early(void)
 {
-	void *comport;
 	int iommu_off = 0;
-	unsigned int default_speed;
-	u64 physport;
 
 	DBG(" -> pSeries_init_early()\n");
 
@@ -382,17 +381,8 @@
 			     get_property(of_chosen, "linux,iommu-off", NULL));
 	}
 
-	generic_find_legacy_serial_ports(&physport, &default_speed);
-
 	if (platform_is_lpar())
 		find_udbg_vterm();
-	else if (physport) {
-		/* Map the uart for udbg. */
-		comport = (void *)ioremap(physport, 16);
-		udbg_init_uart(comport, default_speed);
-
-		DBG("Hello World !\n");
-	}
 
 	if (firmware_has_feature(FW_FEATURE_DABR))
 		ppc_md.set_dabr = pseries_set_dabr;
@@ -638,5 +628,8 @@
 	.machine_check_exception = pSeries_machine_check_exception,
 #ifdef CONFIG_KEXEC
 	.kexec_cpu_down		= pseries_kexec_cpu_down,
+	.machine_kexec		= default_machine_kexec,
+	.machine_kexec_prepare	= default_machine_kexec_prepare,
+	.machine_crash_shutdown	= default_machine_crash_shutdown,
 #endif
 };
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 0377dec..0c0cfa3 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -407,7 +407,7 @@
 			smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
 		}
 #endif
-#ifdef CONFIG_DEBUGGER
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 		if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
 				       &xics_ipi_message[cpu].value)) {
 			mb();
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 6b7efcf..14b9abd 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -4,5 +4,6 @@
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
 obj-$(CONFIG_BOOKE)		+= dcr.o
 obj-$(CONFIG_40x)		+= dcr.o
-obj-$(CONFIG_U3_DART)		+= u3_iommu.o
+obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
+obj-$(CONFIG_83xx)		+= ipic.o
diff --git a/arch/powerpc/sysdev/dart.h b/arch/powerpc/sysdev/dart.h
index 33ed9ed..c2d0576 100644
--- a/arch/powerpc/sysdev/dart.h
+++ b/arch/powerpc/sysdev/dart.h
@@ -20,29 +20,44 @@
 #define _POWERPC_SYSDEV_DART_H
 
 
-/* physical base of DART registers */
-#define DART_BASE        0xf8033000UL
-
 /* Offset from base to control register */
-#define DARTCNTL   0
-/* Offset from base to exception register */
-#define DARTEXCP   0x10
-/* Offset from base to TLB tag registers */
-#define DARTTAG    0x1000
+#define DART_CNTL	0
 
+/* Offset from base to exception register */
+#define DART_EXCP_U3	0x10
+/* Offset from base to TLB tag registers */
+#define DART_TAGS_U3	0x1000
+
+/* U4 registers */
+#define DART_BASE_U4	0x10
+#define DART_SIZE_U4	0x20
+#define DART_EXCP_U4	0x30
+#define DART_TAGS_U4	0x1000
 
 /* Control Register fields */
 
-/* base address of table (pfn) */
-#define DARTCNTL_BASE_MASK    0xfffff
-#define DARTCNTL_BASE_SHIFT   12
+/* U3 registers */
+#define DART_CNTL_U3_BASE_MASK	0xfffff
+#define DART_CNTL_U3_BASE_SHIFT	12
+#define DART_CNTL_U3_FLUSHTLB	0x400
+#define DART_CNTL_U3_ENABLE	0x200
+#define DART_CNTL_U3_SIZE_MASK	0x1ff
+#define DART_CNTL_U3_SIZE_SHIFT	0
 
-#define DARTCNTL_FLUSHTLB     0x400
-#define DARTCNTL_ENABLE       0x200
+/* U4 registers */
+#define DART_BASE_U4_BASE_MASK	0xffffff
+#define DART_BASE_U4_BASE_SHIFT	0
+#define DART_CNTL_U4_FLUSHTLB	0x20000000
+#define DART_CNTL_U4_ENABLE	0x80000000
+#define DART_SIZE_U4_SIZE_MASK	0x1fff
+#define DART_SIZE_U4_SIZE_SHIFT	0
+
+#define DART_REG(r)	(dart + ((r) >> 2))
+#define DART_IN(r)	(in_be32(DART_REG(r)))
+#define DART_OUT(r,v)	(out_be32(DART_REG(r), (v)))
+
 
 /* size of table in pages */
-#define DARTCNTL_SIZE_MASK    0x1ff
-#define DARTCNTL_SIZE_SHIFT   0
 
 
 /* DART table fields */
diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
similarity index 65%
rename from arch/powerpc/sysdev/u3_iommu.c
rename to arch/powerpc/sysdev/dart_iommu.c
index 5c1a26a..e00b46b 100644
--- a/arch/powerpc/sysdev/u3_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -1,25 +1,27 @@
 /*
- * arch/powerpc/sysdev/u3_iommu.c
+ * arch/powerpc/sysdev/dart_iommu.c
  *
  * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
+ * Copyright (C) 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>,
+ *                    IBM Corporation
  *
  * Based on pSeries_iommu.c:
  * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
  * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
  *
- * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu.
+ * Dynamic DMA mapping support, Apple U3, U4 & IBM CPC925 "DART" iommu.
  *
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
@@ -57,21 +59,22 @@
 static u32 *dart_vbase;
 
 /* Mapped base address for the dart */
-static unsigned int *dart; 
+static unsigned int *__iomem dart;
 
 /* Dummy val that entries are set to when unused */
 static unsigned int dart_emptyval;
 
-static struct iommu_table iommu_table_u3;
-static int iommu_table_u3_inited;
+static struct iommu_table iommu_table_dart;
+static int iommu_table_dart_inited;
 static int dart_dirty;
+static int dart_is_u4;
 
 #define DBG(...)
 
 static inline void dart_tlb_invalidate_all(void)
 {
 	unsigned long l = 0;
-	unsigned int reg;
+	unsigned int reg, inv_bit;
 	unsigned long limit;
 
 	DBG("dart: flush\n");
@@ -81,29 +84,28 @@
 	 *
 	 * Gotcha: Sometimes, the DART won't detect that the bit gets
 	 * set. If so, clear it and set it again.
-	 */ 
+	 */
 
 	limit = 0;
 
+	inv_bit = dart_is_u4 ? DART_CNTL_U4_FLUSHTLB : DART_CNTL_U3_FLUSHTLB;
 retry:
-	reg = in_be32((unsigned int *)dart+DARTCNTL);
-	reg |= DARTCNTL_FLUSHTLB;
-	out_be32((unsigned int *)dart+DARTCNTL, reg);
-
 	l = 0;
-	while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) &&
-		l < (1L<<limit)) {
+	reg = DART_IN(DART_CNTL);
+	reg |= inv_bit;
+	DART_OUT(DART_CNTL, reg);
+
+	while ((DART_IN(DART_CNTL) & inv_bit) && l < (1L << limit))
 		l++;
-	}
-	if (l == (1L<<limit)) {
+	if (l == (1L << limit)) {
 		if (limit < 4) {
 			limit++;
-		        reg = in_be32((unsigned int *)dart+DARTCNTL);
-		        reg &= ~DARTCNTL_FLUSHTLB;
-		        out_be32((unsigned int *)dart+DARTCNTL, reg);
+		        reg = DART_IN(DART_CNTL);
+		        reg &= ~inv_bit;
+			DART_OUT(DART_CNTL, reg);
 			goto retry;
 		} else
-			panic("U3-DART: TLB did not flush after waiting a long "
+			panic("DART: TLB did not flush after waiting a long "
 			      "time. Buggy U3 ?");
 	}
 }
@@ -115,7 +117,7 @@
 	dart_dirty = 0;
 }
 
-static void dart_build(struct iommu_table *tbl, long index, 
+static void dart_build(struct iommu_table *tbl, long index,
 		       long npages, unsigned long uaddr,
 		       enum dma_data_direction direction)
 {
@@ -128,7 +130,7 @@
 	npages <<= DART_PAGE_FACTOR;
 
 	dp = ((unsigned int*)tbl->it_base) + index;
-	
+
 	/* On U3, all memory is contigous, so we can move this
 	 * out of the loop.
 	 */
@@ -148,7 +150,7 @@
 static void dart_free(struct iommu_table *tbl, long index, long npages)
 {
 	unsigned int *dp;
-	
+
 	/* We don't worry about flushing the TLB cache. The only drawback of
 	 * not doing it is that we won't catch buggy device drivers doing
 	 * bad DMAs, but then no 32-bit architecture ever does either.
@@ -160,7 +162,7 @@
 	npages <<= DART_PAGE_FACTOR;
 
 	dp  = ((unsigned int *)tbl->it_base) + index;
-		
+
 	while (npages--)
 		*(dp++) = dart_emptyval;
 }
@@ -168,20 +170,25 @@
 
 static int dart_init(struct device_node *dart_node)
 {
-	unsigned int regword;
 	unsigned int i;
-	unsigned long tmp;
+	unsigned long tmp, base, size;
+	struct resource r;
 
 	if (dart_tablebase == 0 || dart_tablesize == 0) {
-		printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n");
+		printk(KERN_INFO "DART: table not allocated, using "
+		       "direct DMA\n");
 		return -ENODEV;
 	}
 
+	if (of_address_to_resource(dart_node, 0, &r))
+		panic("DART: can't get register base ! ");
+
 	/* Make sure nothing from the DART range remains in the CPU cache
 	 * from a previous mapping that existed before the kernel took
 	 * over
 	 */
-	flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize);
+	flush_dcache_phys_range(dart_tablebase,
+				dart_tablebase + dart_tablesize);
 
 	/* Allocate a spare page to map all invalid DART pages. We need to do
 	 * that to work around what looks like a problem with the HT bridge
@@ -189,21 +196,16 @@
 	 */
 	tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
 	if (!tmp)
-		panic("U3-DART: Cannot allocate spare page!");
-	dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & DARTMAP_RPNMASK);
+		panic("DART: Cannot allocate spare page!");
+	dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) &
+					 DARTMAP_RPNMASK);
 
-	/* Map in DART registers. FIXME: Use device node to get base address */
-	dart = ioremap(DART_BASE, 0x7000);
+	/* Map in DART registers */
+	dart = ioremap(r.start, r.end - r.start + 1);
 	if (dart == NULL)
-		panic("U3-DART: Cannot map registers!");
+		panic("DART: Cannot map registers!");
 
-	/* Set initial control register contents: table base, 
-	 * table size and enable bit
-	 */
-	regword = DARTCNTL_ENABLE | 
-		((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) |
-		(((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
-				 << DARTCNTL_SIZE_SHIFT);
+	/* Map in DART table */
 	dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize);
 
 	/* Fill initial table */
@@ -211,36 +213,50 @@
 		dart_vbase[i] = dart_emptyval;
 
 	/* Initialize DART with table base and enable it. */
-	out_be32((unsigned int *)dart, regword);
+	base = dart_tablebase >> DART_PAGE_SHIFT;
+	size = dart_tablesize >> DART_PAGE_SHIFT;
+	if (dart_is_u4) {
+		size &= DART_SIZE_U4_SIZE_MASK;
+		DART_OUT(DART_BASE_U4, base);
+		DART_OUT(DART_SIZE_U4, size);
+		DART_OUT(DART_CNTL, DART_CNTL_U4_ENABLE);
+	} else {
+		size &= DART_CNTL_U3_SIZE_MASK;
+		DART_OUT(DART_CNTL,
+			 DART_CNTL_U3_ENABLE |
+			 (base << DART_CNTL_U3_BASE_SHIFT) |
+			 (size << DART_CNTL_U3_SIZE_SHIFT));
+	}
 
 	/* Invalidate DART to get rid of possible stale TLBs */
 	dart_tlb_invalidate_all();
 
-	printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n");
+	printk(KERN_INFO "DART IOMMU initialized for %s type chipset\n",
+	       dart_is_u4 ? "U4" : "U3");
 
 	return 0;
 }
 
-static void iommu_table_u3_setup(void)
+static void iommu_table_dart_setup(void)
 {
-	iommu_table_u3.it_busno = 0;
-	iommu_table_u3.it_offset = 0;
+	iommu_table_dart.it_busno = 0;
+	iommu_table_dart.it_offset = 0;
 	/* it_size is in number of entries */
-	iommu_table_u3.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
+	iommu_table_dart.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
 
 	/* Initialize the common IOMMU code */
-	iommu_table_u3.it_base = (unsigned long)dart_vbase;
-	iommu_table_u3.it_index = 0;
-	iommu_table_u3.it_blocksize = 1;
-	iommu_init_table(&iommu_table_u3);
+	iommu_table_dart.it_base = (unsigned long)dart_vbase;
+	iommu_table_dart.it_index = 0;
+	iommu_table_dart.it_blocksize = 1;
+	iommu_init_table(&iommu_table_dart);
 
 	/* Reserve the last page of the DART to avoid possible prefetch
 	 * past the DART mapped area
 	 */
-	set_bit(iommu_table_u3.it_size - 1, iommu_table_u3.it_map);
+	set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
 }
 
-static void iommu_dev_setup_u3(struct pci_dev *dev)
+static void iommu_dev_setup_dart(struct pci_dev *dev)
 {
 	struct device_node *dn;
 
@@ -254,35 +270,39 @@
 	dn = pci_device_to_OF_node(dev);
 
 	if (dn)
-		PCI_DN(dn)->iommu_table = &iommu_table_u3;
+		PCI_DN(dn)->iommu_table = &iommu_table_dart;
 }
 
-static void iommu_bus_setup_u3(struct pci_bus *bus)
+static void iommu_bus_setup_dart(struct pci_bus *bus)
 {
 	struct device_node *dn;
 
-	if (!iommu_table_u3_inited) {
-		iommu_table_u3_inited = 1;
-		iommu_table_u3_setup();
+	if (!iommu_table_dart_inited) {
+		iommu_table_dart_inited = 1;
+		iommu_table_dart_setup();
 	}
 
 	dn = pci_bus_to_OF_node(bus);
 
 	if (dn)
-		PCI_DN(dn)->iommu_table = &iommu_table_u3;
+		PCI_DN(dn)->iommu_table = &iommu_table_dart;
 }
 
 static void iommu_dev_setup_null(struct pci_dev *dev) { }
 static void iommu_bus_setup_null(struct pci_bus *bus) { }
 
-void iommu_init_early_u3(void)
+void iommu_init_early_dart(void)
 {
 	struct device_node *dn;
 
 	/* Find the DART in the device-tree */
 	dn = of_find_compatible_node(NULL, "dart", "u3-dart");
-	if (dn == NULL)
-		return;
+	if (dn == NULL) {
+		dn = of_find_compatible_node(NULL, "dart", "u4-dart");
+		if (dn == NULL)
+			goto bail;
+		dart_is_u4 = 1;
+	}
 
 	/* Setup low level TCE operations for the core IOMMU code */
 	ppc_md.tce_build = dart_build;
@@ -290,24 +310,27 @@
 	ppc_md.tce_flush = dart_flush;
 
 	/* Initialize the DART HW */
-	if (dart_init(dn)) {
-		/* If init failed, use direct iommu and null setup functions */
-		ppc_md.iommu_dev_setup = iommu_dev_setup_null;
-		ppc_md.iommu_bus_setup = iommu_bus_setup_null;
-
-		/* Setup pci_dma ops */
-		pci_direct_iommu_init();
-	} else {
-		ppc_md.iommu_dev_setup = iommu_dev_setup_u3;
-		ppc_md.iommu_bus_setup = iommu_bus_setup_u3;
+	if (dart_init(dn) == 0) {
+		ppc_md.iommu_dev_setup = iommu_dev_setup_dart;
+		ppc_md.iommu_bus_setup = iommu_bus_setup_dart;
 
 		/* Setup pci_dma ops */
 		pci_iommu_init();
+
+		return;
 	}
+
+ bail:
+	/* If init failed, use direct iommu and null setup functions */
+	ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+	ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+
+	/* Setup pci_dma ops */
+	pci_direct_iommu_init();
 }
 
 
-void __init alloc_u3_dart_table(void)
+void __init alloc_dart_table(void)
 {
 	/* Only reserve DART space if machine has more than 2GB of RAM
 	 * or if requested with iommu=on on cmdline.
@@ -323,5 +346,5 @@
 	dart_tablebase = (unsigned long)
 		abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
 
-	printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase);
+	printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase);
 }
diff --git a/arch/ppc/syslib/ipic.c b/arch/powerpc/sysdev/ipic.c
similarity index 100%
rename from arch/ppc/syslib/ipic.c
rename to arch/powerpc/sysdev/ipic.c
diff --git a/arch/ppc/syslib/ipic.h b/arch/powerpc/sysdev/ipic.h
similarity index 100%
rename from arch/ppc/syslib/ipic.h
rename to arch/powerpc/sysdev/ipic.h
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 58d1cc2..4f26304 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -13,6 +13,9 @@
  */
 
 #undef DEBUG
+#undef DEBUG_IPI
+#undef DEBUG_IRQ
+#undef DEBUG_LOW
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -45,7 +48,11 @@
 static DEFINE_SPINLOCK(mpic_lock);
 
 #ifdef CONFIG_PPC32	/* XXX for now */
-#define distribute_irqs	CONFIG_IRQ_ALL_CPUS
+#ifdef CONFIG_IRQ_ALL_CPUS
+#define distribute_irqs	(1)
+#else
+#define distribute_irqs	(0)
+#endif
 #endif
 
 /*
@@ -164,70 +171,129 @@
 /* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
  * to force the edge setting on the MPIC and do the ack workaround.
  */
-static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no)
+static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
 {
-	if (source_no >= 128 || !mpic->fixups)
+	if (source >= 128 || !mpic->fixups)
 		return 0;
-	return mpic->fixups[source_no].base != NULL;
-}
-
-static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no)
-{
-	struct mpic_irq_fixup *fixup = &mpic->fixups[source_no];
-	u32 tmp;
-
-	spin_lock(&mpic->fixup_lock);
-	writeb(0x11 + 2 * fixup->irq, fixup->base);
-	tmp = readl(fixup->base + 2);
-	writel(tmp | 0x80000000ul, fixup->base + 2);
-	/* config writes shouldn't be posted but let's be safe ... */
-	(void)readl(fixup->base + 2);
-	spin_unlock(&mpic->fixup_lock);
+	return mpic->fixups[source].base != NULL;
 }
 
 
-static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase)
+static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source)
 {
-	int i, irq;
+	struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+
+	if (fixup->applebase) {
+		unsigned int soff = (fixup->index >> 3) & ~3;
+		unsigned int mask = 1U << (fixup->index & 0x1f);
+		writel(mask, fixup->applebase + soff);
+	} else {
+		spin_lock(&mpic->fixup_lock);
+		writeb(0x11 + 2 * fixup->index, fixup->base + 2);
+		writel(fixup->data, fixup->base + 4);
+		spin_unlock(&mpic->fixup_lock);
+	}
+}
+
+static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
+				      unsigned int irqflags)
+{
+	struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+	unsigned long flags;
 	u32 tmp;
 
-	printk(KERN_INFO "mpic:    - Workarounds on AMD 8111 @ %p\n", devbase);
+	if (fixup->base == NULL)
+		return;
 
-	for (i=0; i < 24; i++) {
-		writeb(0x10 + 2*i, devbase + 0xf2);
-		tmp = readl(devbase + 0xf4);
-		if ((tmp & 0x1) || !(tmp & 0x20))
-			continue;
+	DBG("startup_ht_interrupt(%u, %u) index: %d\n",
+	    source, irqflags, fixup->index);
+	spin_lock_irqsave(&mpic->fixup_lock, flags);
+	/* Enable and configure */
+	writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+	tmp = readl(fixup->base + 4);
+	tmp &= ~(0x23U);
+	if (irqflags & IRQ_LEVEL)
+		tmp |= 0x22;
+	writel(tmp, fixup->base + 4);
+	spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+}
+
+static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
+				       unsigned int irqflags)
+{
+	struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+	unsigned long flags;
+	u32 tmp;
+
+	if (fixup->base == NULL)
+		return;
+
+	DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags);
+
+	/* Disable */
+	spin_lock_irqsave(&mpic->fixup_lock, flags);
+	writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+	tmp = readl(fixup->base + 4);
+	tmp &= ~1U;
+	writel(tmp, fixup->base + 4);
+	spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+}
+
+static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
+				    unsigned int devfn, u32 vdid)
+{
+	int i, irq, n;
+	u8 __iomem *base;
+	u32 tmp;
+	u8 pos;
+
+	for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
+	     pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
+		u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
+		if (id == PCI_CAP_ID_HT_IRQCONF) {
+			id = readb(devbase + pos + 3);
+			if (id == 0x80)
+				break;
+		}
+	}
+	if (pos == 0)
+		return;
+
+	base = devbase + pos;
+	writeb(0x01, base + 2);
+	n = (readl(base + 4) >> 16) & 0xff;
+
+	printk(KERN_INFO "mpic:   - HT:%02x.%x [0x%02x] vendor %04x device %04x"
+	       " has %d irqs\n",
+	       devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1);
+
+	for (i = 0; i <= n; i++) {
+		writeb(0x10 + 2 * i, base + 2);
+		tmp = readl(base + 4);
 		irq = (tmp >> 16) & 0xff;
-		mpic->fixups[irq].irq = i;
-		mpic->fixups[irq].base = devbase + 0xf2;
+		DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp);
+		/* mask it , will be unmasked later */
+		tmp |= 0x1;
+		writel(tmp, base + 4);
+		mpic->fixups[irq].index = i;
+		mpic->fixups[irq].base = base;
+		/* Apple HT PIC has a non-standard way of doing EOIs */
+		if ((vdid & 0xffff) == 0x106b)
+			mpic->fixups[irq].applebase = devbase + 0x60;
+		else
+			mpic->fixups[irq].applebase = NULL;
+		writeb(0x11 + 2 * i, base + 2);
+		mpic->fixups[irq].data = readl(base + 4) | 0x80000000;
 	}
 }
  
-static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase)
-{
-	int i, irq;
-	u32 tmp;
 
-	printk(KERN_INFO "mpic:    - Workarounds on AMD 8131 @ %p\n", devbase);
-
-	for (i=0; i < 4; i++) {
-		writeb(0x10 + 2*i, devbase + 0xba);
-		tmp = readl(devbase + 0xbc);
-		if ((tmp & 0x1) || !(tmp & 0x20))
-			continue;
-		irq = (tmp >> 16) & 0xff;
-		mpic->fixups[irq].irq = i;
-		mpic->fixups[irq].base = devbase + 0xba;
-	}
-}
- 
-static void __init mpic_scan_ioapics(struct mpic *mpic)
+static void __init mpic_scan_ht_pics(struct mpic *mpic)
 {
 	unsigned int devfn;
 	u8 __iomem *cfgspace;
 
-	printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n");
+	printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n");
 
 	/* Allocate fixups array */
 	mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
@@ -237,21 +303,20 @@
 	/* Init spinlock */
 	spin_lock_init(&mpic->fixup_lock);
 
-	/* Map u3 config space. We assume all IO-APICs are on the primary bus
-	 * and slot will never be above "0xf" so we only need to map 32k
+	/* Map U3 config space. We assume all IO-APICs are on the primary bus
+	 * so we only need to map 64kB.
 	 */
-	cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000);
+	cfgspace = ioremap(0xf2000000, 0x10000);
 	BUG_ON(cfgspace == NULL);
 
-	/* Now we scan all slots. We do a very quick scan, we read the header type,
-	 * vendor ID and device ID only, that's plenty enough
+	/* Now we scan all slots. We do a very quick scan, we read the header
+	 * type, vendor ID and device ID only, that's plenty enough
 	 */
-	for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) {
+	for (devfn = 0; devfn < 0x100; devfn++) {
 		u8 __iomem *devbase = cfgspace + (devfn << 8);
 		u8 hdr_type = readb(devbase + PCI_HEADER_TYPE);
 		u32 l = readl(devbase + PCI_VENDOR_ID);
-		u16 vendor_id, device_id;
-		int multifunc = 0;
+		u16 s;
 
 		DBG("devfn %x, l: %x\n", devfn, l);
 
@@ -259,22 +324,16 @@
 		if (l == 0xffffffff || l == 0x00000000 ||
 		    l == 0x0000ffff || l == 0xffff0000)
 			goto next;
+		/* Check if is supports capability lists */
+		s = readw(devbase + PCI_STATUS);
+		if (!(s & PCI_STATUS_CAP_LIST))
+			goto next;
 
-		/* Check if it's a multifunction device (only really used
-		 * to function 0 though
-		 */
-		multifunc = !!(hdr_type & 0x80);
-		vendor_id = l & 0xffff;
-		device_id = (l >> 16) & 0xffff;
+		mpic_scan_ht_pic(mpic, devbase, devfn, l);
 
-		/* If a known device, go to fixup setup code */
-		if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460)
-			mpic_amd8111_read_irq(mpic, devbase);
-		if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450)
-			mpic_amd8131_read_irq(mpic, devbase);
 	next:
 		/* next device, if function 0 */
-		if ((PCI_FUNC(devfn) == 0) && !multifunc)
+		if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0)
 			devfn += 7;
 	}
 }
@@ -371,6 +430,31 @@
 			break;
 		}
 	} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);	
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+	if (mpic->flags & MPIC_BROKEN_U3) {
+		unsigned int src = irq - mpic->irq_offset;
+		if (mpic_is_ht_interrupt(mpic, src) &&
+		    (irq_desc[irq].status & IRQ_LEVEL))
+			mpic_ht_end_irq(mpic, src);
+	}
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+}
+
+static unsigned int mpic_startup_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+	struct mpic *mpic = mpic_from_irq(irq);
+	unsigned int src = irq - mpic->irq_offset;
+
+	if (mpic_is_ht_interrupt(mpic, src))
+		mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+	mpic_enable_irq(irq);
+
+	return 0;
 }
 
 static void mpic_disable_irq(unsigned int irq)
@@ -394,12 +478,27 @@
 	} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
 }
 
+static void mpic_shutdown_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+	struct mpic *mpic = mpic_from_irq(irq);
+	unsigned int src = irq - mpic->irq_offset;
+
+	if (mpic_is_ht_interrupt(mpic, src))
+		mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+	mpic_disable_irq(irq);
+}
+
 static void mpic_end_irq(unsigned int irq)
 {
 	struct mpic *mpic = mpic_from_irq(irq);
 
+#ifdef DEBUG_IRQ
 	DBG("%s: end_irq: %d\n", mpic->name, irq);
-
+#endif
 	/* We always EOI on end_irq() even for edge interrupts since that
 	 * should only lower the priority, the MPIC should have properly
 	 * latched another edge interrupt coming in anyway
@@ -408,8 +507,9 @@
 #ifdef CONFIG_MPIC_BROKEN_U3
 	if (mpic->flags & MPIC_BROKEN_U3) {
 		unsigned int src = irq - mpic->irq_offset;
-		if (mpic_is_ht_interrupt(mpic, src))
-			mpic_apic_end_irq(mpic, src);
+		if (mpic_is_ht_interrupt(mpic, src) &&
+		    (irq_desc[irq].status & IRQ_LEVEL))
+			mpic_ht_end_irq(mpic, src);
 	}
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
@@ -490,6 +590,8 @@
 	mpic->name = name;
 
 	mpic->hc_irq.typename = name;
+	mpic->hc_irq.startup = mpic_startup_irq;
+	mpic->hc_irq.shutdown = mpic_shutdown_irq;
 	mpic->hc_irq.enable = mpic_enable_irq;
 	mpic->hc_irq.disable = mpic_disable_irq;
 	mpic->hc_irq.end = mpic_end_irq;
@@ -658,10 +760,10 @@
 		mpic->irq_count = mpic->num_sources;
 
 #ifdef CONFIG_MPIC_BROKEN_U3
-	/* Do the ioapic fixups on U3 broken mpic */
+	/* Do the HT PIC fixups on U3 broken mpic */
 	DBG("MPIC flags: %x\n", mpic->flags);
 	if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
-		mpic_scan_ioapics(mpic);
+		mpic_scan_ht_pics(mpic);
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
 	for (i = 0; i < mpic->num_sources; i++) {
@@ -848,7 +950,9 @@
 
 	BUG_ON(mpic == NULL);
 
+#ifdef DEBUG_IPI
 	DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
+#endif
 
 	mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
 		       mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
@@ -859,19 +963,28 @@
 	u32 irq;
 
 	irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
+#ifdef DEBUG_LOW
 	DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
-
+#endif
 	if (mpic->cascade && irq == mpic->cascade_vec) {
+#ifdef DEBUG_LOW
 		DBG("%s: cascading ...\n", mpic->name);
+#endif
 		irq = mpic->cascade(regs, mpic->cascade_data);
 		mpic_eoi(mpic);
 		return irq;
 	}
 	if (unlikely(irq == MPIC_VEC_SPURRIOUS))
 		return -1;
-	if (irq < MPIC_VEC_IPI_0) 
+	if (irq < MPIC_VEC_IPI_0) {
+#ifdef DEBUG_IRQ
+		DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset);
+#endif
 		return irq + mpic->irq_offset;
+	}
+#ifdef DEBUG_IPI
        	DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0);
+#endif
 	return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset;
 }
 
diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile
index b20312e..109d874 100644
--- a/arch/powerpc/xmon/Makefile
+++ b/arch/powerpc/xmon/Makefile
@@ -3,9 +3,5 @@
 ifdef CONFIG_PPC64
 EXTRA_CFLAGS += -mno-minimal-toc
 endif
-
-obj-$(CONFIG_8xx)	+= start_8xx.o
-obj-$(CONFIG_6xx)	+= start_32.o
-obj-$(CONFIG_4xx)	+= start_32.o
-obj-$(CONFIG_PPC64)	+= start_64.o
-obj-y			+= xmon.o ppc-dis.o ppc-opc.o setjmp.o nonstdio.o
+obj-y			+= xmon.o ppc-dis.o ppc-opc.o setjmp.o start.o \
+			   nonstdio.o
diff --git a/arch/powerpc/xmon/start_64.c b/arch/powerpc/xmon/start.c
similarity index 100%
rename from arch/powerpc/xmon/start_64.c
rename to arch/powerpc/xmon/start.c
diff --git a/arch/powerpc/xmon/start_32.c b/arch/powerpc/xmon/start_32.c
deleted file mode 100644
index c2464df..0000000
--- a/arch/powerpc/xmon/start_32.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- */
-#include <linux/config.h>
-#include <linux/string.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/cuda.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <asm/xmon.h>
-#include <asm/prom.h>
-#include <asm/bootx.h>
-#include <asm/machdep.h>
-#include <asm/errno.h>
-#include <asm/pmac_feature.h>
-#include <asm/processor.h>
-#include <asm/delay.h>
-#include <asm/btext.h>
-#include <asm/time.h>
-#include "nonstdio.h"
-
-static volatile unsigned char __iomem *sccc, *sccd;
-unsigned int TXRDY, RXRDY, DLAB;
-
-static int use_serial;
-static int use_screen;
-static int via_modem;
-static int xmon_use_sccb;
-static struct device_node *channel_node;
-
-void buf_access(void)
-{
-	if (DLAB)
-		sccd[3] &= ~DLAB;	/* reset DLAB */
-}
-
-extern int adb_init(void);
-
-#ifdef CONFIG_PPC_CHRP
-/*
- * This looks in the "ranges" property for the primary PCI host bridge
- * to find the physical address of the start of PCI/ISA I/O space.
- * It is basically a cut-down version of pci_process_bridge_OF_ranges.
- */
-static unsigned long chrp_find_phys_io_base(void)
-{
-	struct device_node *node;
-	unsigned int *ranges;
-	unsigned long base = CHRP_ISA_IO_BASE;
-	int rlen = 0;
-	int np;
-
-	node = find_devices("isa");
-	if (node != NULL) {
-		node = node->parent;
-		if (node == NULL || node->type == NULL
-		    || strcmp(node->type, "pci") != 0)
-			node = NULL;
-	}
-	if (node == NULL)
-		node = find_devices("pci");
-	if (node == NULL)
-		return base;
-
-	ranges = (unsigned int *) get_property(node, "ranges", &rlen);
-	np = prom_n_addr_cells(node) + 5;
-	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
-		if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
-			/* I/O space starting at 0, grab the phys base */
-			base = ranges[np - 3];
-			break;
-		}
-		ranges += np;
-	}
-	return base;
-}
-#endif /* CONFIG_PPC_CHRP */
-
-void xmon_map_scc(void)
-{
-#ifdef CONFIG_PPC_MULTIPLATFORM
-	volatile unsigned char __iomem *base;
-
-	if (_machine == _MACH_Pmac) {
-		struct device_node *np;
-		unsigned long addr;
-#ifdef CONFIG_BOOTX_TEXT
-		if (!use_screen && !use_serial
-		    && !machine_is_compatible("iMac")) {
-			/* see if there is a keyboard in the device tree
-			   with a parent of type "adb" */
-			for (np = find_devices("keyboard"); np; np = np->next)
-				if (np->parent && np->parent->type
-				    && strcmp(np->parent->type, "adb") == 0)
-					break;
-
-			/* needs to be hacked if xmon_printk is to be used
-			   from within find_via_pmu() */
-#ifdef CONFIG_ADB_PMU
-			if (np != NULL && boot_text_mapped && find_via_pmu())
-				use_screen = 1;
-#endif
-#ifdef CONFIG_ADB_CUDA
-			if (np != NULL && boot_text_mapped && find_via_cuda())
-				use_screen = 1;
-#endif
-		}
-		if (!use_screen && (np = find_devices("escc")) != NULL) {
-			/*
-			 * look for the device node for the serial port
-			 * we're using and see if it says it has a modem
-			 */
-			char *name = xmon_use_sccb? "ch-b": "ch-a";
-			char *slots;
-			int l;
-
-			np = np->child;
-			while (np != NULL && strcmp(np->name, name) != 0)
-				np = np->sibling;
-			if (np != NULL) {
-				/* XXX should parse this properly */
-				channel_node = np;
-				slots = get_property(np, "slot-names", &l);
-				if (slots != NULL && l >= 10
-				    && strcmp(slots+4, "Modem") == 0)
-					via_modem = 1;
-			}
-		}
-		btext_drawstring("xmon uses ");
-		if (use_screen)
-			btext_drawstring("screen and keyboard\n");
-		else {
-			if (via_modem)
-				btext_drawstring("modem on ");
-			btext_drawstring(xmon_use_sccb? "printer": "modem");
-			btext_drawstring(" port\n");
-		}
-
-#endif /* CONFIG_BOOTX_TEXT */
-
-#ifdef CHRP_ESCC
-		addr = 0xc1013020;
-#else
-		addr = 0xf3013020;
-#endif
-		TXRDY = 4;
-		RXRDY = 1;
-	
-		np = find_devices("mac-io");
-		if (np && np->n_addrs)
-			addr = np->addrs[0].address + 0x13020;
-		base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
-		sccc = base + (addr & ~PAGE_MASK);
-		sccd = sccc + 0x10;
-
-	} else {
-		base = (volatile unsigned char *) isa_io_base;
-
-#ifdef CONFIG_PPC_CHRP
-		if (_machine == _MACH_chrp)
-			base = (volatile unsigned char __iomem *)
-				ioremap(chrp_find_phys_io_base(), 0x1000);
-#endif
-
-		sccc = base + 0x3fd;
-		sccd = base + 0x3f8;
-		if (xmon_use_sccb) {
-			sccc -= 0x100;
-			sccd -= 0x100;
-		}
-		TXRDY = 0x20;
-		RXRDY = 1;
-		DLAB = 0x80;
-	}
-#elif defined(CONFIG_GEMINI)
-	/* should already be mapped by the kernel boot */
-	sccc = (volatile unsigned char __iomem *) 0xffeffb0d;
-	sccd = (volatile unsigned char __iomem *) 0xffeffb08;
-	TXRDY = 0x20;
-	RXRDY = 1;
-	DLAB = 0x80;
-#elif defined(CONFIG_405GP)
-	sccc = (volatile unsigned char __iomem *)0xef600305;
-	sccd = (volatile unsigned char __iomem *)0xef600300;
-	TXRDY = 0x20;
-	RXRDY = 1;
-	DLAB = 0x80;
-#endif /* platform */
-}
-
-static int scc_initialized = 0;
-
-void xmon_init_scc(void);
-extern void cuda_poll(void);
-
-static inline void do_poll_adb(void)
-{
-#ifdef CONFIG_ADB_PMU
-	if (sys_ctrler == SYS_CTRLER_PMU)
-		pmu_poll_adb();
-#endif /* CONFIG_ADB_PMU */
-#ifdef CONFIG_ADB_CUDA
-	if (sys_ctrler == SYS_CTRLER_CUDA)
-		cuda_poll();
-#endif /* CONFIG_ADB_CUDA */
-}
-
-int xmon_write(void *ptr, int nb)
-{
-	char *p = ptr;
-	int i, c, ct;
-
-#ifdef CONFIG_SMP
-	static unsigned long xmon_write_lock;
-	int lock_wait = 1000000;
-	int locked;
-
-	while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
-		if (--lock_wait == 0)
-			break;
-#endif
-
-#ifdef CONFIG_BOOTX_TEXT
-	if (use_screen) {
-		/* write it on the screen */
-		for (i = 0; i < nb; ++i)
-			btext_drawchar(*p++);
-		goto out;
-	}
-#endif
-	if (!scc_initialized)
-		xmon_init_scc();
-	ct = 0;
-	for (i = 0; i < nb; ++i) {
-		while ((*sccc & TXRDY) == 0)
-			do_poll_adb();
-		c = p[i];
-		if (c == '\n' && !ct) {
-			c = '\r';
-			ct = 1;
-			--i;
-		} else {
-			ct = 0;
-		}
-		buf_access();
-		*sccd = c;
-		eieio();
-	}
-
- out:
-#ifdef CONFIG_SMP
-	if (!locked)
-		clear_bit(0, &xmon_write_lock);
-#endif
-	return nb;
-}
-
-int xmon_wants_key;
-int xmon_adb_keycode;
-
-#ifdef CONFIG_BOOTX_TEXT
-static int xmon_adb_shiftstate;
-
-static unsigned char xmon_keytab[128] =
-	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
-	"yt123465=97-80]o"				/* 0x10 - 0x1f */
-	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
-	"\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"		/* 0x30 - 0x3f */
-	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
-	"\0\0000123456789\0\0\0";			/* 0x50 - 0x5f */
-
-static unsigned char xmon_shift_keytab[128] =
-	"ASDFHGZXCV\000BQWER"				/* 0x00 - 0x0f */
-	"YT!@#$^%+(&_*)}O"				/* 0x10 - 0x1f */
-	"U{IP\rLJ\"K:|<?NM>"				/* 0x20 - 0x2f */
-	"\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"		/* 0x30 - 0x3f */
-	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
-	"\0\0000123456789\0\0\0";			/* 0x50 - 0x5f */
-
-static int xmon_get_adb_key(void)
-{
-	int k, t, on;
-
-	xmon_wants_key = 1;
-	for (;;) {
-		xmon_adb_keycode = -1;
-		t = 0;
-		on = 0;
-		do {
-			if (--t < 0) {
-				on = 1 - on;
-				btext_drawchar(on? 0xdb: 0x20);
-				btext_drawchar('\b');
-				t = 200000;
-			}
-			do_poll_adb();
-		} while (xmon_adb_keycode == -1);
-		k = xmon_adb_keycode;
-		if (on)
-			btext_drawstring(" \b");
-
-		/* test for shift keys */
-		if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
-			xmon_adb_shiftstate = (k & 0x80) == 0;
-			continue;
-		}
-		if (k >= 0x80)
-			continue;	/* ignore up transitions */
-		k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
-		if (k != 0)
-			break;
-	}
-	xmon_wants_key = 0;
-	return k;
-}
-#endif /* CONFIG_BOOTX_TEXT */
-
-int xmon_readchar(void)
-{
-#ifdef CONFIG_BOOTX_TEXT
-	if (use_screen)
-		return xmon_get_adb_key();
-#endif
-	if (!scc_initialized)
-		xmon_init_scc();
-	while ((*sccc & RXRDY) == 0)
-		do_poll_adb();
-	buf_access();
-	return *sccd;
-}
-
-int xmon_read_poll(void)
-{
-	if ((*sccc & RXRDY) == 0) {
-		do_poll_adb();
-		return -1;
-	}
-	buf_access();
-	return *sccd;
-}
-
-static unsigned char scc_inittab[] = {
-    13, 0,		/* set baud rate divisor */
-    12, 1,
-    14, 1,		/* baud rate gen enable, src=rtxc */
-    11, 0x50,		/* clocks = br gen */
-    5,  0xea,		/* tx 8 bits, assert DTR & RTS */
-    4,  0x46,		/* x16 clock, 1 stop */
-    3,  0xc1,		/* rx enable, 8 bits */
-};
-
-void xmon_init_scc(void)
-{
-	if ( _machine == _MACH_chrp )
-	{
-		sccd[3] = 0x83; eieio();	/* LCR = 8N1 + DLAB */
-		sccd[0] = 12; eieio();		/* DLL = 9600 baud */
-		sccd[1] = 0; eieio();
-		sccd[2] = 0; eieio();		/* FCR = 0 */
-		sccd[3] = 3; eieio();		/* LCR = 8N1 */
-		sccd[1] = 0; eieio();		/* IER = 0 */
-	}
-	else if ( _machine == _MACH_Pmac )
-	{
-		int i, x;
-		unsigned long timeout;
-
-		if (channel_node != 0)
-			pmac_call_feature(
-				PMAC_FTR_SCC_ENABLE,
-				channel_node,
-				PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
-			printk(KERN_INFO "Serial port locked ON by debugger !\n");
-		if (via_modem && channel_node != 0) {
-			unsigned int t0;
-
-			pmac_call_feature(
-				PMAC_FTR_MODEM_ENABLE,
-				channel_node, 0, 1);
-			printk(KERN_INFO "Modem powered up by debugger !\n");
-			t0 = get_tbl();
-			timeout = 3 * tb_ticks_per_sec;
-			if (timeout == 0)
-				/* assume 25MHz if tb_ticks_per_sec not set */
-				timeout = 75000000;
-			while (get_tbl() - t0 < timeout)
-				eieio();
-		}
-		/* use the B channel if requested */
-		if (xmon_use_sccb) {
-			sccc = (volatile unsigned char *)
-				((unsigned long)sccc & ~0x20);
-			sccd = sccc + 0x10;
-		}
-		for (i = 20000; i != 0; --i) {
-			x = *sccc; eieio();
-		}
-		*sccc = 9; eieio();		/* reset A or B side */
-		*sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
-		for (i = 0; i < sizeof(scc_inittab); ++i) {
-			*sccc = scc_inittab[i];
-			eieio();
-		}
-	}
-	scc_initialized = 1;
-	if (via_modem) {
-		for (;;) {
-			xmon_write("ATE1V1\r", 7);
-			if (xmon_expect("OK", 5)) {
-				xmon_write("ATA\r", 4);
-				if (xmon_expect("CONNECT", 40))
-					break;
-			}
-			xmon_write("+++", 3);
-			xmon_expect("OK", 3);
-		}
-	}
-}
-
-void xmon_enter(void)
-{
-#ifdef CONFIG_ADB_PMU
-	if (_machine == _MACH_Pmac) {
-		pmu_suspend();
-	}
-#endif
-}
-
-void xmon_leave(void)
-{
-#ifdef CONFIG_ADB_PMU
-	if (_machine == _MACH_Pmac) {
-		pmu_resume();
-	}
-#endif
-}
diff --git a/arch/powerpc/xmon/start_8xx.c b/arch/powerpc/xmon/start_8xx.c
deleted file mode 100644
index 4c17b04..0000000
--- a/arch/powerpc/xmon/start_8xx.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- * Copyright (C) 2000 Dan Malek.
- * Quick hack of Paul's code to make XMON work on 8xx processors.  Lots
- * of assumptions, like the SMC1 is used, it has been initialized by the
- * loader at some point, and we can just stuff and suck bytes.
- * We rely upon the 8xx uart driver to support us, as the interface
- * changes between boot up and operational phases of the kernel.
- */
-#include <linux/string.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <linux/kernel.h>
-#include <asm/8xx_immap.h>
-#include <asm/mpc8xx.h>
-#include <asm/commproc.h>
-#include "nonstdio.h"
-
-extern int xmon_8xx_write(char *str, int nb);
-extern int xmon_8xx_read_poll(void);
-extern int xmon_8xx_read_char(void);
-
-void xmon_map_scc(void)
-{
-	cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-}
-
-void xmon_init_scc(void);
-
-int xmon_write(void *ptr, int nb)
-{
-	return(xmon_8xx_write(ptr, nb));
-}
-
-int xmon_readchar(void)
-{
-	return xmon_8xx_read_char();
-}
-
-int xmon_read_poll(void)
-{
-	return(xmon_8xx_read_poll());
-}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index c45a6ad..22612ed 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -450,7 +450,6 @@
  leave:
 	cpu_clear(cpu, cpus_in_xmon);
 	xmon_fault_jmp[cpu] = NULL;
-
 #else
 	/* UP is simple... */
 	if (in_xmon) {
@@ -805,7 +804,10 @@
 			break;
 		case 'x':
 		case 'X':
+			return cmd;
 		case EOF:
+			printf(" <no input ...>\n");
+			mdelay(2000);
 			return cmd;
 		case '?':
 			printf(help_string);
@@ -1011,7 +1013,7 @@
 	unsigned int instr;
 
 	addr &= ~3;
-	if (addr < KERNELBASE) {
+	if (!is_kernel_addr(addr)) {
 		printf("Breakpoints may only be placed at kernel addresses\n");
 		return 0;
 	}
@@ -1062,7 +1064,7 @@
 		dabr.address = 0;
 		dabr.enabled = 0;
 		if (scanhex(&dabr.address)) {
-			if (dabr.address < KERNELBASE) {
+			if (!is_kernel_addr(dabr.address)) {
 				printf(badaddr);
 				break;
 			}
diff --git a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S
index c96c9f8..368ec03 100644
--- a/arch/ppc/boot/common/util.S
+++ b/arch/ppc/boot/common/util.S
@@ -234,7 +234,8 @@
  * First, flush the data cache in case it was enabled and may be
  * holding instructions for copy back.
  */
-_GLOBAL(flush_instruction_cache)
+        .globl flush_instruction_cache
+flush_instruction_cache:        
 	mflr	r6
 	bl	flush_data_cache
 
@@ -279,7 +280,8 @@
  * Flush data cache
  * Do this by just reading lots of stuff into the cache.
  */
-_GLOBAL(flush_data_cache)
+        .globl flush_data_cache
+flush_data_cache:       
 	lis	r3,cache_flush_buffer@h
 	ori	r3,r3,cache_flush_buffer@l
 	li	r4,NUM_CACHE_LINES
diff --git a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile
index 532e7ef..58415d5 100644
--- a/arch/ppc/boot/images/Makefile
+++ b/arch/ppc/boot/images/Makefile
@@ -26,7 +26,7 @@
 targets += uImage
 $(obj)/uImage: $(obj)/vmlinux.gz
 	$(Q)rm -f $@
-	$(call if_changed,uimage)
+	$(call cmd,uimage)
 	@echo -n '  Image: $@ '
 	@if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
 
diff --git a/arch/ppc/configs/TQM8540_defconfig b/arch/ppc/configs/TQM8540_defconfig
new file mode 100644
index 0000000..99bf3b7
--- /dev/null
+++ b/arch/ppc/configs/TQM8540_defconfig
@@ -0,0 +1,973 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Fri Nov 25 17:26:50 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+CONFIG_TQM8540=y
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8540=y
+
+#
+# Platform options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# 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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE 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_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# 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 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_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# 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_BLKMTD 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# 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 is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=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
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 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_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV 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_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB 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
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# 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 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_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_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 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_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/TQM8541_defconfig b/arch/ppc/configs/TQM8541_defconfig
new file mode 100644
index 0000000..0ff5669
--- /dev/null
+++ b/arch/ppc/configs/TQM8541_defconfig
@@ -0,0 +1,986 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Wed Nov 30 13:36:28 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+CONFIG_TQM8541=y
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8555=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# 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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE 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_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# 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 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_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# 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_BLKMTD 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# 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 is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=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
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_FS_ENET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 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_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV 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_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_CPM is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_MPC8260 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB 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
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_MAX6900 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8563 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# 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 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_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_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 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_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/TQM8555_defconfig b/arch/ppc/configs/TQM8555_defconfig
new file mode 100644
index 0000000..730b3db
--- /dev/null
+++ b/arch/ppc/configs/TQM8555_defconfig
@@ -0,0 +1,983 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Thu Nov 24 17:10:52 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+CONFIG_TQM8555=y
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8555=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# 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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE 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_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# 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 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_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# 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_BLKMTD 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# 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 is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=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
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_FS_ENET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 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_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV 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_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_CPM is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB 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
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# 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 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_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_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 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_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/TQM8560_defconfig b/arch/ppc/configs/TQM8560_defconfig
new file mode 100644
index 0000000..1d90207
--- /dev/null
+++ b/arch/ppc/configs/TQM8560_defconfig
@@ -0,0 +1,992 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Wed Nov 30 16:47:53 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8555 is not set
+CONFIG_TQM8560=y
+CONFIG_MPC8560=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# 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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE 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_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# 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 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_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# 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_BLKMTD 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# 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 is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=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
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_FS_ENET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 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_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV 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_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+CONFIG_SERIAL_CPM_SCC1=y
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+# CONFIG_SERIAL_CPM_SMC1 is not set
+# CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_MPC8260 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB 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
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_MAX6900 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8563 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# 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 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_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_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 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_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 0bb23fc..e6c1d615 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -49,5 +49,4 @@
 ifndef CONFIG_E200
 obj-$(CONFIG_FSL_BOOKE)		+= perfmon_fsl_booke.o
 endif
-obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 endif
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
index fe0e767..7964bf6 100644
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -131,7 +131,7 @@
 	DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
 	DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
 
-	DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
+	DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame));
 	DEFINE(TI_TASK, offsetof(struct thread_info, task));
 	DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index f044edb..a48b950 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -200,8 +200,6 @@
 	bl	do_show_syscall
 #endif /* SHOW_SYSCALLS */
 	rlwinm	r10,r1,0,0,18	/* current_thread_info() */
-	li	r11,0
-	stb	r11,TI_SC_NOERR(r10)
 	lwz	r11,TI_FLAGS(r10)
 	andi.	r11,r11,_TIF_SYSCALL_T_OR_A
 	bne-	syscall_dotrace
@@ -222,25 +220,21 @@
 	bl	do_show_syscall_exit
 #endif
 	mr	r6,r3
-	li	r11,-_LAST_ERRNO
-	cmplw	0,r3,r11
 	rlwinm	r12,r1,0,0,18	/* current_thread_info() */
-	blt+	30f
-	lbz	r11,TI_SC_NOERR(r12)
-	cmpwi	r11,0
-	bne	30f
-	neg	r3,r3
-	lwz	r10,_CCR(r1)	/* Set SO bit in CR */
-	oris	r10,r10,0x1000
-	stw	r10,_CCR(r1)
-
 	/* disable interrupts so current_thread_info()->flags can't change */
-30:	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
+	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
 	SYNC
 	MTMSRD(r10)
 	lwz	r9,TI_FLAGS(r12)
-	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+	li	r8,-_LAST_ERRNO
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
 	bne-	syscall_exit_work
+	cmplw	0,r3,r8
+	blt+	syscall_exit_cont
+	lwz	r11,_CCR(r1)			/* Load CR */
+	neg	r3,r3
+	oris	r11,r11,0x1000	/* Set SO bit in CR */
+	stw	r11,_CCR(r1)
 syscall_exit_cont:
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 	/* If the process has its own DBCR0 value, load it up.  The single
@@ -292,46 +286,113 @@
 	b	syscall_dotrace_cont
 
 syscall_exit_work:
-	stw	r6,RESULT(r1)	/* Save result */
+	andi.	r0,r9,_TIF_RESTOREALL
+	bne-	2f
+	cmplw	0,r3,r8
+	blt+	1f
+	andi.	r0,r9,_TIF_NOERROR
+	bne-	1f
+	lwz	r11,_CCR(r1)			/* Load CR */
+	neg	r3,r3
+	oris	r11,r11,0x1000	/* Set SO bit in CR */
+	stw	r11,_CCR(r1)
+
+1:	stw	r6,RESULT(r1)	/* Save result */
 	stw	r3,GPR3(r1)	/* Update return value */
-	andi.	r0,r9,_TIF_SYSCALL_T_OR_A
-	beq	5f
-	ori	r10,r10,MSR_EE
-	SYNC
-	MTMSRD(r10)		/* re-enable interrupts */
+2:	andi.	r0,r9,(_TIF_PERSYSCALL_MASK)
+	beq	4f
+
+	/* Clear per-syscall TIF flags if any are set, but _leave_
+	_TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+	yet.  */
+
+	li	r11,_TIF_PERSYSCALL_MASK
+	addi	r12,r12,TI_FLAGS
+3:	lwarx	r8,0,r12
+	andc	r8,r8,r11
+#ifdef CONFIG_IBM405_ERR77
+	dcbt	0,r12
+#endif
+	stwcx.	r8,0,r12
+	bne-	3b
+	subi	r12,r12,TI_FLAGS
+	
+4:	/* Anything which requires enabling interrupts? */
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+	beq	7f
+
+	/* Save NVGPRS if they're not saved already */
 	lwz	r4,TRAP(r1)
 	andi.	r4,r4,1
-	beq	4f
+	beq	5f
 	SAVE_NVGPRS(r1)
 	li	r4,0xc00
 	stw	r4,TRAP(r1)
-4:
+
+	/* Re-enable interrupts */
+5:	ori	r10,r10,MSR_EE
+	SYNC
+	MTMSRD(r10)
+
+	andi.	r0,r9,_TIF_SAVE_NVGPRS
+	bne	save_user_nvgprs
+
+save_user_nvgprs_cont:
+	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+	beq	7f
+
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	do_syscall_trace_leave
 	REST_NVGPRS(r1)
-2:
-	lwz	r3,GPR3(r1)
+
+6:	lwz	r3,GPR3(r1)
 	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
 	SYNC
 	MTMSRD(r10)		/* disable interrupts again */
 	rlwinm	r12,r1,0,0,18	/* current_thread_info() */
 	lwz	r9,TI_FLAGS(r12)
-5:
+7:
 	andi.	r0,r9,_TIF_NEED_RESCHED
-	bne	1f
+	bne	8f
 	lwz	r5,_MSR(r1)
 	andi.	r5,r5,MSR_PR
-	beq	syscall_exit_cont
+	beq	ret_from_except
 	andi.	r0,r9,_TIF_SIGPENDING
-	beq	syscall_exit_cont
+	beq	ret_from_except
 	b	do_user_signal
-1:
+8:
 	ori	r10,r10,MSR_EE
 	SYNC
 	MTMSRD(r10)		/* re-enable interrupts */
 	bl	schedule
-	b	2b
+	b	6b
 
+save_user_nvgprs:
+	lwz	r8,TI_SIGFRAME(r12)
+
+.macro savewords start, end
+  1:	stw \start,4*(\start)(r8)
+	.section __ex_table,"a"
+	.align	2
+	.long	1b,save_user_nvgprs_fault
+	.previous
+	.if \end - \start
+	savewords "(\start+1)",\end
+	.endif
+.endm	
+	savewords 14,31
+	b	save_user_nvgprs_cont
+
+	
+save_user_nvgprs_fault:
+	li	r3,11		/* SIGSEGV */
+	lwz	r4,TI_TASK(r12)
+	bl	force_sigsegv
+
+	rlwinm	r12,r1,0,0,18	/* current_thread_info() */
+	lwz	r9,TI_FLAGS(r12)
+	b	save_user_nvgprs_cont
+	
 #ifdef SHOW_SYSCALLS
 do_show_syscall:
 #ifdef SHOW_SYSCALLS_TASK
@@ -401,28 +462,10 @@
 #endif /* SHOW_SYSCALLS */
 
 /*
- * The sigsuspend and rt_sigsuspend system calls can call do_signal
- * and thus put the process into the stopped state where we might
- * want to examine its user state with ptrace.  Therefore we need
- * to save all the nonvolatile registers (r13 - r31) before calling
- * the C code.
+ * The fork/clone functions need to copy the full register set into
+ * the child process. Therefore we need to save all the nonvolatile
+ * registers (r13 - r31) before calling the C code.
  */
-	.globl	ppc_sigsuspend
-ppc_sigsuspend:
-	SAVE_NVGPRS(r1)
-	lwz	r0,TRAP(r1)
-	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
-	stw	r0,TRAP(r1)		/* register set saved */
-	b	sys_sigsuspend
-
-	.globl	ppc_rt_sigsuspend
-ppc_rt_sigsuspend:
-	SAVE_NVGPRS(r1)
-	lwz	r0,TRAP(r1)
-	rlwinm	r0,r0,0,0,30
-	stw	r0,TRAP(r1)
-	b	sys_rt_sigsuspend
-
 	.globl	ppc_fork
 ppc_fork:
 	SAVE_NVGPRS(r1)
@@ -447,14 +490,6 @@
 	stw	r0,TRAP(r1)		/* register set saved */
 	b	sys_clone
 
-	.globl	ppc_swapcontext
-ppc_swapcontext:
-	SAVE_NVGPRS(r1)
-	lwz	r0,TRAP(r1)
-	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
-	stw	r0,TRAP(r1)		/* register set saved */
-	b	sys_swapcontext
-
 /*
  * Top-level page fault handling.
  * This is in assembler because if do_page_fault tells us that
@@ -626,16 +661,6 @@
 	.long	ret_from_except
 #endif
 
-	.globl	sigreturn_exit
-sigreturn_exit:
-	subi	r1,r3,STACK_FRAME_OVERHEAD
-	rlwinm	r12,r1,0,0,18	/* current_thread_info() */
-	lwz	r9,TI_FLAGS(r12)
-	andi.	r0,r9,_TIF_SYSCALL_T_OR_A
-	beq+	ret_from_except_full
-	bl	do_syscall_trace_leave
-	/* fall through */
-
 	.globl	ret_from_except_full
 ret_from_except_full:
 	REST_NVGPRS(r1)
@@ -658,7 +683,7 @@
 	/* Check current_thread_info()->flags */
 	rlwinm	r9,r1,0,0,18
 	lwz	r9,TI_FLAGS(r9)
-	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
 	bne	do_work
 
 restore_user:
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 5e61124..fb5658b 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -1197,7 +1197,7 @@
 	.long sys_ssetmask
 	.long sys_setreuid	/* 70 */
 	.long sys_setregid
-	.long ppc_sigsuspend
+	.long sys_sigsuspend
 	.long sys_sigpending
 	.long sys_sethostname
 	.long sys_setrlimit	/* 75 */
@@ -1303,7 +1303,7 @@
 	.long sys_rt_sigpending	/* 175 */
 	.long sys_rt_sigtimedwait
 	.long sys_rt_sigqueueinfo
-	.long ppc_rt_sigsuspend
+	.long sys_rt_sigsuspend
 	.long sys_pread64
 	.long sys_pwrite64	/* 180 */
 	.long sys_chown
@@ -1374,7 +1374,7 @@
 	.long sys_clock_gettime
 	.long sys_clock_getres
 	.long sys_clock_nanosleep
-	.long ppc_swapcontext
+	.long sys_swapcontext
 	.long sys_tgkill	/* 250 */
 	.long sys_utimes
 	.long sys_statfs64
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index f7fae5f..50c75ee 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -815,8 +815,7 @@
  * to set pci_assign_all_buses to 1 and still use RTAS for PCI
  * config cycles.
  */
-struct pci_controller*
-pci_find_hose_for_OF_device(struct device_node* node)
+struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
 {
 	if (!have_of)
 		return NULL;
@@ -942,7 +941,7 @@
 	while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
 		res = NULL;
 		size = ranges[na+4];
-		switch (ranges[0] >> 24) {
+		switch ((ranges[0] >> 24) & 0x3) {
 		case 1:		/* I/O space */
 			if (ranges[2] != 0)
 				break;
@@ -956,6 +955,8 @@
 			res = &hose->io_resource;
 			res->flags = IORESOURCE_IO;
 			res->start = ranges[2];
+			DBG("PCI: IO 0x%lx -> 0x%lx\n",
+				    res->start, res->start + size - 1);
 			break;
 		case 2:		/* memory space */
 			memno = 0;
@@ -973,7 +974,11 @@
 			if (memno < 3) {
 				res = &hose->mem_resources[memno];
 				res->flags = IORESOURCE_MEM;
+				if(ranges[0] & 0x40000000)
+					res->flags |= IORESOURCE_PREFETCH;
 				res->start = ranges[na+2];
+				DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno,
+					    res->start, res->start + size - 1);
 			}
 			break;
 		}
@@ -1806,6 +1811,23 @@
 EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
 
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+	struct pci_controller* hose = hose_head;
+
+	for (; hose; hose = hose->next) {
+		unsigned int size = hose->io_resource.end -
+			hose->io_resource.start + 1;
+		if (address >= hose->io_base_phys &&
+		    address < (hose->io_base_phys + size)) {
+			unsigned long base =
+				(unsigned long)hose->io_base_virt - _IO_BASE;
+			return base + (address - hose->io_base_phys);
+		}
+	}
+	return (unsigned int)-1;
+}
+EXPORT_SYMBOL(pci_address_to_pio);
 
 /*
  * Null PCI config access functions, for the case when we can't
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index bb6a5c6..95075f9 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -82,10 +82,6 @@
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
 EXPORT_SYMBOL(DMA_MODE_READ);
 EXPORT_SYMBOL(DMA_MODE_WRITE);
-#if defined(CONFIG_PPC_PREP)
-EXPORT_SYMBOL(_prep_type);
-EXPORT_SYMBOL(ucSystemType);
-#endif
 
 #if !defined(__INLINE_BITOPS)
 EXPORT_SYMBOL(set_bit);
@@ -311,7 +307,6 @@
 
 EXPORT_SYMBOL(next_mmu_context);
 EXPORT_SYMBOL(set_context);
-EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */
 EXPORT_SYMBOL(disarm_decr);
 #ifdef CONFIG_PPC_STD_MMU
 extern long mol_trampoline;
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 0eb0b70..e707c6f 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -744,6 +744,9 @@
 	/* so udelay does something sensible, assume <= 1000 bogomips */
 	loops_per_jiffy = 500000000 / HZ;
 
+	if (ppc_md.init_early)
+		ppc_md.init_early();
+
 #ifdef CONFIG_PPC_MULTIPLATFORM
 	/* This could be called "early setup arch", it must be done
 	 * now because xmon need it
diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig
index c5bc282..7ddd331 100644
--- a/arch/ppc/platforms/85xx/Kconfig
+++ b/arch/ppc/platforms/85xx/Kconfig
@@ -39,7 +39,7 @@
 config SBC8560
 	bool "WindRiver PowerQUICC III SBC8560"
 	help
-	  This option enables support for the WindRiver PowerQUICC III 
+	  This option enables support for the WindRiver PowerQUICC III
 	  SBC8560 board.
 
 config STX_GP3
@@ -48,6 +48,26 @@
 	  This option enables support for the Silicon Turnkey Express GP3
 	  board.
 
+config TQM8540
+	bool "TQ Components TQM8540"
+	help
+	  This option enablese support for the TQ Components TQM8540 board.
+
+config TQM8541
+	bool "TQ Components TQM8541"
+	help
+	  This option enablese support for the TQ Components TQM8541 board.
+
+config TQM8555
+	bool "TQ Components TQM8555"
+	help
+	  This option enablese support for the TQ Components TQM8555 board.
+
+config TQM8560
+	bool "TQ Components TQM8560"
+	help
+	  This option enablese support for the TQ Components TQM8560 board.
+
 endchoice
 
 # It's often necessary to know the specific 85xx processor type.
@@ -55,7 +75,7 @@
 # don't need to ask more redundant questions.
 config MPC8540
 	bool
-	depends on MPC8540_ADS
+	depends on MPC8540_ADS || TQM8540
 	default y
 
 config MPC8548
@@ -65,12 +85,12 @@
 
 config MPC8555
 	bool
-	depends on MPC8555_CDS
+	depends on MPC8555_CDS || TQM8541 || TQM8555
 	default y
 
 config MPC8560
 	bool
-	depends on SBC8560 || MPC8560_ADS || STX_GP3
+	depends on SBC8560 || MPC8560_ADS || STX_GP3 || TQM8560
 	default y
 
 config 85xx_PCI2
diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile
index efdf813..6c4753c 100644
--- a/arch/ppc/platforms/85xx/Makefile
+++ b/arch/ppc/platforms/85xx/Makefile
@@ -7,3 +7,7 @@
 obj-$(CONFIG_MPC8560_ADS)	+= mpc85xx_ads_common.o mpc8560_ads.o
 obj-$(CONFIG_SBC8560)		+= sbc85xx.o sbc8560.o
 obj-$(CONFIG_STX_GP3)		+= stx_gp3.o
+obj-$(CONFIG_TQM8540)		+= tqm85xx.o
+obj-$(CONFIG_TQM8541)		+= tqm85xx.o
+obj-$(CONFIG_TQM8555)		+= tqm85xx.o
+obj-$(CONFIG_TQM8560)		+= tqm85xx.o
diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
new file mode 100644
index 0000000..c6dfd8f
--- /dev/null
+++ b/arch/ppc/platforms/85xx/tqm85xx.c
@@ -0,0 +1,419 @@
+/*
+ * arch/ppc/platforms/85xx/tqm85xx.c
+ *
+ * TQM85xx (40/41/55/60) board specific routines
+ *
+ * Copyright (c) 2005 DENX Software Engineering
+ * Stefan Roese <sr@denx.de>
+ *
+ * Based on original work by
+ * 	Kumar Gala <galak@kernel.crashing.org>
+ *      Copyright 2004 Freescale Semiconductor 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/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>	/* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.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/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
+#include <asm/cpm2.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc85xx_setup.h>
+#include <syslib/cpm2_pic.h>
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_rio.h>
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+
+extern unsigned long total_memory;	/* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+static u_char tqm85xx_openpic_initsenses[] __initdata = {
+	MPC85XX_INTERNAL_IRQ_SENSES,
+	0x0,						/* External  0: */
+	0x0,						/* External  1: */
+#if defined(CONFIG_PCI)
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 2: PCI INTA */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 3: PCI INTB */
+#else
+	0x0,				/* External  2: */
+	0x0,				/* External  3: */
+#endif
+	0x0,				/* External  4: */
+	0x0,				/* External  5: */
+	0x0,				/* External  6: */
+	0x0,				/* External  7: */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 8: PHY */
+	0x0,				/* External  9: */
+	0x0,				/* External 10: */
+	0x0,				/* External 11: */
+};
+
+static const char *GFAR_PHY_0 = "phy0:2";
+static const char *GFAR_PHY_1 = "phy0:1";
+#ifdef CONFIG_MPC8540
+static const char *GFAR_PHY_3 = "phy0:3";
+#endif
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+tqm85xx_setup_arch(void)
+{
+	bd_t *binfo = (bd_t *) __res;
+	unsigned int freq;
+	struct gianfar_platform_data *pdata;
+	struct gianfar_mdio_data *mdata;
+
+#ifdef CONFIG_MPC8560
+	cpm2_reset();
+#endif
+
+	/* get the core frequency */
+	freq = binfo->bi_intfreq;
+
+	if (ppc_md.progress)
+		ppc_md.progress("tqm85xx_setup_arch()", 0);
+
+	/* Set loops_per_jiffy to a half-way reasonable value,
+	   for use until calibrate_delay gets called. */
+	loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+	/* setup PCI host bridges */
+	mpc85xx_setup_hose();
+#endif
+
+#ifndef CONFIG_MPC8560
+#if defined(CONFIG_SERIAL_8250)
+	mpc85xx_early_serial_map();
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	/* Invalidate the entry we stole earlier the serial ports
+	 * should be properly mapped */
+	invalidate_tlbcam_entry(num_tlbcam_entries - 1);
+#endif
+#endif /* CONFIG_MPC8560 */
+
+	/* setup the board related info for the MDIO bus */
+	mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO);
+
+	mdata->irq[0] = MPC85xx_IRQ_EXT8;
+	mdata->irq[1] = MPC85xx_IRQ_EXT8;
+	mdata->irq[2] = -1;
+	mdata->irq[3] = MPC85xx_IRQ_EXT8;
+	mdata->irq[31] = -1;
+	mdata->paddr += binfo->bi_immr_base;
+
+	/* setup the board related information for the enet controllers */
+	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
+	if (pdata) {
+		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+		pdata->bus_id = GFAR_PHY_0;
+		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+	}
+
+	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
+	if (pdata) {
+		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+		pdata->bus_id = GFAR_PHY_1;
+		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+	}
+
+#ifdef CONFIG_MPC8540
+	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
+	if (pdata) {
+		pdata->board_flags = 0;
+		pdata->bus_id = GFAR_PHY_3;
+		memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
+	}
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
+#endif
+#ifdef  CONFIG_ROOT_NFS
+		ROOT_DEV = Root_NFS;
+#else
+	ROOT_DEV = Root_HDA1;
+#endif
+}
+
+#ifdef CONFIG_MPC8560
+static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+	while ((irq = cpm2_get_irq(regs)) >= 0)
+		__do_IRQ(irq, regs);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction cpm2_irqaction = {
+	.handler = cpm2_cascade,
+	.flags = SA_INTERRUPT,
+	.mask = CPU_MASK_NONE,
+	.name = "cpm2_cascade",
+};
+#endif /* CONFIG_MPC8560 */
+
+void __init
+tqm85xx_init_IRQ(void)
+{
+	bd_t *binfo = (bd_t *) __res;
+
+	/* Determine the Physical Address of the OpenPIC regs */
+	phys_addr_t OpenPIC_PAddr =
+		binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+	OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+	OpenPIC_InitSenses = tqm85xx_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof (tqm85xx_openpic_initsenses);
+
+	/* Skip reserved space and internal sources */
+	openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+
+	/* Map PIC IRQs 0-11 */
+	openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000);
+
+	/* we let openpic interrupts starting from an offset, to
+	 * leave space for cascading interrupts underneath.
+	 */
+	openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+#ifdef CONFIG_MPC8560
+	/* Setup CPM2 PIC */
+        cpm2_init_IRQ();
+
+	setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
+#endif /* CONFIG_MPC8560 */
+
+	return;
+}
+
+int tqm85xx_show_cpuinfo(struct seq_file *m)
+{
+	uint pvid, svid, phid1;
+	uint memsize = total_memory;
+	bd_t *binfo = (bd_t *) __res;
+	unsigned int freq;
+
+	/* get the core frequency */
+	freq = binfo->bi_intfreq;
+
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
+
+	seq_printf(m, "Vendor\t\t: TQ Components\n");
+	seq_printf(m, "Machine\t\t: TQM%s\n", cur_ppc_sys_spec->ppc_sys_name);
+	seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+
+	return 0;
+}
+
+#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_DS1337)
+extern ulong ds1337_get_rtc_time(void);
+extern int ds1337_set_rtc_time(unsigned long nowtime);
+
+static int __init
+tqm85xx_rtc_hookup(void)
+{
+	struct timespec	tv;
+
+        ppc_md.set_rtc_time = ds1337_set_rtc_time;
+        ppc_md.get_rtc_time = ds1337_get_rtc_time;
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = (ppc_md.get_rtc_time)();
+	do_settimeofday(&tv);
+
+	return 0;
+}
+late_initcall(tqm85xx_rtc_hookup);
+#endif
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+		/*
+		 *      PCI IDSEL/INTPIN->INTLINE
+		 *       A      B      C      D
+		 */
+		{
+			{PIRQA, PIRQB, 0, 0},
+		};
+
+	const long min_idsel = 0x1c, max_idsel = 0x1c, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+	if (bus == 0 && PCI_SLOT(devfn) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	else
+		return PCIBIOS_SUCCESSFUL;
+}
+
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_RAPIDIO
+void platform_rio_init(void)
+{
+	/* 512MB RIO LAW at 0xc0000000 */
+	mpc85xx_rio_setup(0xc0000000, 0x20000000);
+}
+#endif /* CONFIG_RAPIDIO */
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	/* parse_bootinfo must always be called first */
+	parse_bootinfo(find_bootinfo());
+
+	/*
+	 * If we were passed in a board information, copy it into the
+	 * residual data area.
+	 */
+	if (r3) {
+		memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+		       sizeof (bd_t));
+	}
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && !defined(CONFIG_MPC8560)
+	{
+		bd_t *binfo = (bd_t *) __res;
+		struct uart_port p;
+
+		/* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+		settlbcam(num_tlbcam_entries - 1, binfo->bi_immr_base,
+			  binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+
+		memset(&p, 0, sizeof (p));
+		p.iotype = SERIAL_IO_MEM;
+		p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART0_OFFSET;
+		p.uartclk = binfo->bi_busfreq;
+
+		gen550_init(0, &p);
+
+		memset(&p, 0, sizeof (p));
+		p.iotype = SERIAL_IO_MEM;
+		p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART1_OFFSET;
+		p.uartclk = binfo->bi_busfreq;
+
+		gen550_init(1, &p);
+	}
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+	/*
+	 * If the init RAM disk has been configured in, and there's a valid
+	 * starting address for it, set it up.
+	 */
+	if (r4) {
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif				/* CONFIG_BLK_DEV_INITRD */
+
+	/* Copy the kernel command line arguments to a safe place. */
+
+	if (r6) {
+		*(char *) (r7 + KERNELBASE) = 0;
+		strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+	}
+
+	identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+	/* setup the PowerPC module struct */
+	ppc_md.setup_arch = tqm85xx_setup_arch;
+	ppc_md.show_cpuinfo = tqm85xx_show_cpuinfo;
+
+	ppc_md.init_IRQ = tqm85xx_init_IRQ;
+	ppc_md.get_irq = openpic_get_irq;
+
+	ppc_md.restart = mpc85xx_restart;
+	ppc_md.power_off = mpc85xx_power_off;
+	ppc_md.halt = mpc85xx_halt;
+
+	ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+	ppc_md.time_init = NULL;
+	ppc_md.set_rtc_time = NULL;
+	ppc_md.get_rtc_time = NULL;
+	ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#ifndef CONFIG_MPC8560
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+	ppc_md.progress = gen550_progress;
+#endif	/* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
+	ppc_md.early_serial_map = mpc85xx_early_serial_map;
+#endif	/* CONFIG_SERIAL_8250 && CONFIG_KGDB */
+#endif /* CONFIG_MPC8560 */
+
+	if (ppc_md.progress)
+		ppc_md.progress("tqm85xx_init(): exit", 0);
+
+	return;
+}
diff --git a/arch/ppc/platforms/85xx/tqm85xx.h b/arch/ppc/platforms/85xx/tqm85xx.h
new file mode 100644
index 0000000..3775eb3
--- /dev/null
+++ b/arch/ppc/platforms/85xx/tqm85xx.h
@@ -0,0 +1,56 @@
+/*
+ * arch/ppc/platforms/85xx/tqm85xx.h
+ *
+ * TQM85xx (40/41/55/60) board definitions
+ *
+ * Copyright (c) 2005 DENX Software Engineering
+ * Stefan Roese <sr@denx.de>
+ *
+ * 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 __MACH_TQM85XX_H
+#define __MACH_TQM85XX_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/ppcboot.h>
+
+#define BOARD_CCSRBAR		((uint)0xe0000000)
+#define CCSRBAR_SIZE		((uint)1024*1024)
+
+#define CPM_MAP_ADDR		(CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#define PCI_CFG_ADDR_OFFSET	(0x8000)
+#define PCI_CFG_DATA_OFFSET	(0x8004)
+
+/* PCI interrupt controller */
+#define PIRQA			MPC85xx_IRQ_EXT2
+#define PIRQB			MPC85xx_IRQ_EXT3
+
+#define MPC85XX_PCI1_LOWER_IO	0x00000000
+#define MPC85XX_PCI1_UPPER_IO	0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM	0x80000000
+#define MPC85XX_PCI1_UPPER_MEM	0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE	0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET	0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE	0x01000000
+
+#define BASE_BAUD 115200
+
+extern void mpc85xx_setup_hose(void) __init;
+extern void mpc85xx_restart(char *cmd);
+extern void mpc85xx_power_off(void);
+extern void mpc85xx_halt(void);
+extern void mpc85xx_init_IRQ(void) __init;
+extern unsigned long mpc85xx_find_end_of_memory(void) __init;
+extern void mpc85xx_calibrate_decr(void) __init;
+
+#endif /* __MACH_TQM85XX_H */
diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
index f1b70ab..056ac2a 100644
--- a/arch/ppc/platforms/chrp_setup.c
+++ b/arch/ppc/platforms/chrp_setup.c
@@ -404,7 +404,6 @@
 void __init chrp_init_IRQ(void)
 {
 	struct device_node *np;
-	int i;
 	unsigned long chrp_int_ack = 0;
 	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
 #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index 4415748..d065358 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -72,7 +72,6 @@
 
 TODC_ALLOC();
 
-unsigned char ucSystemType;
 unsigned char ucBoardRev;
 unsigned char ucBoardRevMaj, ucBoardRevMin;
 
@@ -954,7 +953,6 @@
 static void __init
 prep_init_IRQ(void)
 {
-	int i;
 	unsigned int pci_viddid, pci_did;
 
 	if (OpenPIC_Addr != NULL) {
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 5b7f2b8..84ef030 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -96,7 +96,7 @@
 obj-$(CONFIG_PCI)		+= pci_auto.o
 endif
 obj-$(CONFIG_RAPIDIO)		+= ppc85xx_rio.o
-obj-$(CONFIG_83xx)		+= ipic.o ppc83xx_setup.o ppc_sys.o \
+obj-$(CONFIG_83xx)		+= ppc83xx_setup.o ppc_sys.o \
 					mpc83xx_sys.o mpc83xx_devices.o
 ifeq ($(CONFIG_83xx),y)
 obj-$(CONFIG_PCI)		+= pci_auto.o
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 1cc3abe..688616d 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -135,6 +135,16 @@
 	.name = "tbint",
 };
 
+/* per-board overridable init_internal_rtc() function. */
+void __init __attribute__ ((weak))
+init_internal_rtc(void)
+{
+	/* Disable the RTC one second and alarm interrupts. */
+	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
+	/* Enable the RTC */
+	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
+}
+
 /* The decrementer counts at the system (internal) clock frequency divided by
  * sixteen, or external oscillator divided by four.  We force the processor
  * to use system clock divided by sixteen.
@@ -183,10 +193,7 @@
 	out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck, KAPWR_KEY);
 	out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, KAPWR_KEY);
 
-	/* Disable the RTC one second and alarm interrupts. */
-	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
-	/* Enable the RTC */
-	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
+	init_internal_rtc();
 
 	/* Enabling the decrementer also enables the timebase interrupts
 	 * (or from the other point of view, to get decrementer interrupts
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
index a21632d..df6c955 100644
--- a/arch/ppc/syslib/m8xx_wdt.c
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -19,6 +19,7 @@
 #include <syslib/m8xx_wdt.h>
 
 static int wdt_timeout;
+int m8xx_has_internal_rtc = 0;
 
 static irqreturn_t m8xx_wdt_interrupt(int, void *, struct pt_regs *);
 static struct irqaction m8xx_wdt_irqaction = {
@@ -45,35 +46,15 @@
 	return IRQ_HANDLED;
 }
 
-void __init m8xx_wdt_handler_install(bd_t * binfo)
+#define SYPCR_SWP 0x1
+#define SYPCR_SWE 0x4
+
+
+void __init m8xx_wdt_install_irq(volatile immap_t *imap, bd_t *binfo)
 {
-	volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
 	u32 pitc;
-	u32 sypcr;
 	u32 pitrtclk;
 
-	sypcr = in_be32(&imap->im_siu_conf.sc_sypcr);
-
-	if (!(sypcr & 0x04)) {
-		printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
-		       sypcr);
-		return;
-	}
-
-	m8xx_wdt_reset();
-
-	printk(KERN_NOTICE
-	       "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
-	       (sypcr >> 16), sypcr & 0x01);
-
-	wdt_timeout = (sypcr >> 16) & 0xFFFF;
-
-	if (!wdt_timeout)
-		wdt_timeout = 0xFFFF;
-
-	if (sypcr & 0x01)
-		wdt_timeout *= 2048;
-
 	/*
 	 * Fire trigger if half of the wdt ticked down 
 	 */
@@ -98,6 +79,67 @@
 	printk(KERN_NOTICE
 	       "m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc);
 
+}
+
+static void m8xx_wdt_timer_func(unsigned long data);
+
+static struct timer_list m8xx_wdt_timer =
+	TIMER_INITIALIZER(m8xx_wdt_timer_func, 0, 0);
+
+void m8xx_wdt_stop_timer(void)
+{
+	del_timer(&m8xx_wdt_timer);
+}
+
+void m8xx_wdt_install_timer(void)
+{
+	m8xx_wdt_timer.expires = jiffies + (HZ/2);
+	add_timer(&m8xx_wdt_timer);
+}
+
+static void m8xx_wdt_timer_func(unsigned long data)
+{
+	m8xx_wdt_reset();
+	m8xx_wdt_install_timer();
+}
+
+void __init m8xx_wdt_handler_install(bd_t * binfo)
+{
+	volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+	u32 sypcr;
+
+	sypcr = in_be32(&imap->im_siu_conf.sc_sypcr);
+
+	if (!(sypcr & SYPCR_SWE)) {
+		printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
+		       sypcr);
+		return;
+	}
+
+	m8xx_wdt_reset();
+
+	printk(KERN_NOTICE
+	       "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
+	       (sypcr >> 16), sypcr & SYPCR_SWP);
+
+	wdt_timeout = (sypcr >> 16) & 0xFFFF;
+
+	if (!wdt_timeout)
+		wdt_timeout = 0xFFFF;
+
+	if (sypcr & SYPCR_SWP)
+		wdt_timeout *= 2048;
+
+	m8xx_has_internal_rtc = in_be16(&imap->im_sit.sit_rtcsc) & RTCSC_RTE;
+
+	/* if the internal RTC is off use a kernel timer */
+	if (!m8xx_has_internal_rtc) {
+		if (wdt_timeout < (binfo->bi_intfreq/HZ))
+			printk(KERN_ERR "m8xx_wdt: timeout too short for ktimer!\n");
+		m8xx_wdt_install_timer();
+	} else
+		m8xx_wdt_install_irq(imap, binfo);
+
 	wdt_timeout /= binfo->bi_intfreq;
 }
 
diff --git a/arch/ppc/syslib/m8xx_wdt.h b/arch/ppc/syslib/m8xx_wdt.h
index 0d81a9f..e75835f 100644
--- a/arch/ppc/syslib/m8xx_wdt.h
+++ b/arch/ppc/syslib/m8xx_wdt.h
@@ -9,8 +9,12 @@
 #ifndef _PPC_SYSLIB_M8XX_WDT_H
 #define _PPC_SYSLIB_M8XX_WDT_H
 
+extern int m8xx_has_internal_rtc;
+
 extern void m8xx_wdt_handler_install(bd_t * binfo);
 extern int m8xx_wdt_get_timeout(void);
 extern void m8xx_wdt_reset(void);
+extern void m8xx_wdt_install_timer(void);
+extern void m8xx_wdt_stop_timer(void);
 
 #endif				/* _PPC_SYSLIB_M8XX_WDT_H */
diff --git a/block/elevator.c b/block/elevator.c
index 39dcccc..99a4d7b 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -64,7 +64,7 @@
 }
 EXPORT_SYMBOL(elv_rq_merge_ok);
 
-inline int elv_try_merge(struct request *__rq, struct bio *bio)
+static inline int elv_try_merge(struct request *__rq, struct bio *bio)
 {
 	int ret = ELEVATOR_NO_MERGE;
 
@@ -80,7 +80,6 @@
 
 	return ret;
 }
-EXPORT_SYMBOL(elv_try_merge);
 
 static struct elevator_type *elevator_find(const char *name)
 {
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 91d3b48..8e27d0a 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -26,7 +26,8 @@
 #include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
-#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
 
 /*
  * for max sense size
@@ -62,13 +63,15 @@
 /*
  * Controlling structure to kblockd
  */
-static struct workqueue_struct *kblockd_workqueue; 
+static struct workqueue_struct *kblockd_workqueue;
 
 unsigned long blk_max_low_pfn, blk_max_pfn;
 
 EXPORT_SYMBOL(blk_max_low_pfn);
 EXPORT_SYMBOL(blk_max_pfn);
 
+static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
+
 /* Amount of time in which a process may batch requests */
 #define BLK_BATCH_TIME	(HZ/50UL)
 
@@ -207,6 +210,13 @@
 
 EXPORT_SYMBOL(blk_queue_merge_bvec);
 
+void blk_queue_softirq_done(request_queue_t *q, softirq_done_fn *fn)
+{
+	q->softirq_done_fn = fn;
+}
+
+EXPORT_SYMBOL(blk_queue_softirq_done);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -270,6 +280,7 @@
 static inline void rq_init(request_queue_t *q, struct request *rq)
 {
 	INIT_LIST_HEAD(&rq->queuelist);
+	INIT_LIST_HEAD(&rq->donelist);
 
 	rq->errors = 0;
 	rq->rq_status = RQ_ACTIVE;
@@ -286,6 +297,7 @@
 	rq->sense = NULL;
 	rq->end_io = NULL;
 	rq->end_io_data = NULL;
+	rq->completion_data = NULL;
 }
 
 /**
@@ -2735,30 +2747,6 @@
 	return 0;
 }
 
-/**
- * blk_attempt_remerge  - attempt to remerge active head with next request
- * @q:    The &request_queue_t belonging to the device
- * @rq:   The head request (usually)
- *
- * Description:
- *    For head-active devices, the queue can easily be unplugged so quickly
- *    that proper merging is not done on the front request. This may hurt
- *    performance greatly for some devices. The block layer cannot safely
- *    do merging on that first request for these queues, but the driver can
- *    call this function and make it happen any way. Only the driver knows
- *    when it is safe to do so.
- **/
-void blk_attempt_remerge(request_queue_t *q, struct request *rq)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(q->queue_lock, flags);
-	attempt_back_merge(q, rq);
-	spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
-EXPORT_SYMBOL(blk_attempt_remerge);
-
 static void init_request_from_bio(struct request *req, struct bio *bio)
 {
 	req->flags |= REQ_CMD;
@@ -3287,6 +3275,87 @@
 EXPORT_SYMBOL(end_that_request_chunk);
 
 /*
+ * splice the completion data to a local structure and hand off to
+ * process_completion_queue() to complete the requests
+ */
+static void blk_done_softirq(struct softirq_action *h)
+{
+	struct list_head *cpu_list;
+	LIST_HEAD(local_list);
+
+	local_irq_disable();
+	cpu_list = &__get_cpu_var(blk_cpu_done);
+	list_splice_init(cpu_list, &local_list);
+	local_irq_enable();
+
+	while (!list_empty(&local_list)) {
+		struct request *rq = list_entry(local_list.next, struct request, donelist);
+
+		list_del_init(&rq->donelist);
+		rq->q->softirq_done_fn(rq);
+	}
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
+			  void *hcpu)
+{
+	/*
+	 * If a CPU goes away, splice its entries to the current CPU
+	 * and trigger a run of the softirq
+	 */
+	if (action == CPU_DEAD) {
+		int cpu = (unsigned long) hcpu;
+
+		local_irq_disable();
+		list_splice_init(&per_cpu(blk_cpu_done, cpu),
+				 &__get_cpu_var(blk_cpu_done));
+		raise_softirq_irqoff(BLOCK_SOFTIRQ);
+		local_irq_enable();
+	}
+
+	return NOTIFY_OK;
+}
+
+
+static struct notifier_block __devinitdata blk_cpu_notifier = {
+	.notifier_call	= blk_cpu_notify,
+};
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/**
+ * blk_complete_request - end I/O on a request
+ * @req:      the request being processed
+ *
+ * Description:
+ *     Ends all I/O on a request. It does not handle partial completions,
+ *     unless the driver actually implements this in its completionc callback
+ *     through requeueing. Theh actual completion happens out-of-order,
+ *     through a softirq handler. The user must have registered a completion
+ *     callback through blk_queue_softirq_done().
+ **/
+
+void blk_complete_request(struct request *req)
+{
+	struct list_head *cpu_list;
+	unsigned long flags;
+
+	BUG_ON(!req->q->softirq_done_fn);
+		
+	local_irq_save(flags);
+
+	cpu_list = &__get_cpu_var(blk_cpu_done);
+	list_add_tail(&req->donelist, cpu_list);
+	raise_softirq_irqoff(BLOCK_SOFTIRQ);
+
+	local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(blk_complete_request);
+	
+/*
  * queue lock must be held
  */
 void end_that_request_last(struct request *req, int uptodate)
@@ -3364,6 +3433,8 @@
 
 int __init blk_dev_init(void)
 {
+	int i;
+
 	kblockd_workqueue = create_workqueue("kblockd");
 	if (!kblockd_workqueue)
 		panic("Failed to create kblockd\n");
@@ -3377,6 +3448,14 @@
 	iocontext_cachep = kmem_cache_create("blkdev_ioc",
 			sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL);
 
+	for (i = 0; i < NR_CPUS; i++)
+		INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
+
+	open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL);
+#ifdef CONFIG_HOTPLUG_CPU
+	register_cpu_notifier(&blk_cpu_notifier);
+#endif
+
 	blk_max_low_pfn = max_low_pfn;
 	blk_max_pfn = max_pfn;
 
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index c2ac36d..18de84c 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -190,16 +190,21 @@
 		safe_for_write(GPCMD_SET_STREAMING),
 	};
 	unsigned char type = cmd_type[cmd[0]];
+	int has_write_perm = 0;
 
 	/* Anybody who can open the device can do a read-safe command */
 	if (type & CMD_READ_SAFE)
 		return 0;
 
+	/*
+	 * file can be NULL from ioctl_by_bdev()...
+	 */
+	if (file)
+		has_write_perm = file->f_mode & FMODE_WRITE;
+
 	/* Write-safe commands just require a writable open.. */
-	if (type & CMD_WRITE_SAFE) {
-		if (file->f_mode & FMODE_WRITE)
-			return 0;
-	}
+	if ((type & CMD_WRITE_SAFE) && has_write_perm)
+		return 0;
 
 	/* And root can do any command.. */
 	if (capable(CAP_SYS_RAWIO))
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 88452c7..e4e9f25 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -2178,16 +2178,48 @@
 
 	start_io(h);
 }
+
+static void cciss_softirq_done(struct request *rq)
+{
+	CommandList_struct *cmd = rq->completion_data;
+	ctlr_info_t *h = hba[cmd->ctlr];
+	u64bit temp64;
+	int i, ddir;
+
+	if (cmd->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
+
+	/* command did not need to be retried */
+	/* unmap the DMA mapping for all the scatter gather elements */
+	for(i=0; i<cmd->Header.SGList; i++) {
+		temp64.val32.lower = cmd->SG[i].Addr.lower;
+		temp64.val32.upper = cmd->SG[i].Addr.upper;
+		pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
+	}
+
+	complete_buffers(rq->bio, rq->errors);
+
+#ifdef CCISS_DEBUG
+	printk("Done with %p\n", rq);
+#endif /* CCISS_DEBUG */ 
+
+	spin_lock_irq(&h->lock);
+	end_that_request_last(rq, rq->errors);
+	cmd_free(h, cmd,1);
+	spin_unlock_irq(&h->lock);
+}
+
 /* checks the status of the job and calls complete buffers to mark all 
- * buffers for the completed job. 
+ * buffers for the completed job. Note that this function does not need
+ * to hold the hba/queue lock.
  */ 
 static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
 		int timeout)
 {
 	int status = 1;
-	int i;
 	int retry_cmd = 0;
-	u64bit temp64;
 		
 	if (timeout)
 		status = 0; 
@@ -2295,24 +2327,10 @@
 		resend_cciss_cmd(h,cmd);
 		return;
 	}	
-	/* command did not need to be retried */
-	/* unmap the DMA mapping for all the scatter gather elements */
-	for(i=0; i<cmd->Header.SGList; i++) {
-		temp64.val32.lower = cmd->SG[i].Addr.lower;
-		temp64.val32.upper = cmd->SG[i].Addr.upper;
-		pci_unmap_page(hba[cmd->ctlr]->pdev,
-			temp64.val, cmd->SG[i].Len,
-			(cmd->Request.Type.Direction == XFER_READ) ?
-				PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-	}
-	complete_buffers(cmd->rq->bio, status);
 
-#ifdef CCISS_DEBUG
-	printk("Done with %p\n", cmd->rq);
-#endif /* CCISS_DEBUG */ 
-
-	end_that_request_last(cmd->rq, status ? 1 : -EIO);
-	cmd_free(h,cmd,1);
+	cmd->rq->completion_data = cmd;
+	cmd->rq->errors = status;
+	blk_complete_request(cmd->rq);
 }
 
 /* 
@@ -3199,15 +3217,17 @@
 		drv->queue = q;
 
 		q->backing_dev_info.ra_pages = READ_AHEAD;
-	blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+		blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
 
-	/* This is a hardware imposed limit. */
-	blk_queue_max_hw_segments(q, MAXSGENTRIES);
+		/* This is a hardware imposed limit. */
+		blk_queue_max_hw_segments(q, MAXSGENTRIES);
 
-	/* This is a limit in the driver and could be eliminated. */
-	blk_queue_max_phys_segments(q, MAXSGENTRIES);
+		/* This is a limit in the driver and could be eliminated. */
+		blk_queue_max_phys_segments(q, MAXSGENTRIES);
 
-	blk_queue_max_sectors(q, 512);
+		blk_queue_max_sectors(q, 512);
+
+		blk_queue_softirq_done(q, cciss_softirq_done);
 
 		q->queuedata = hba[i];
 		sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index af7cb2b..01f042f 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -1083,23 +1083,33 @@
 {
 	struct device_node *mediabay;
 	struct floppy_state *fs = &floppy_states[floppy_count];
+	struct resource res_reg, res_dma;
 
-	if (swim->n_addrs < 2)
-	{
-		printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
-		       swim->n_addrs, swim->n_intrs);
+	if (of_address_to_resource(swim, 0, &res_reg) ||
+	    of_address_to_resource(swim, 1, &res_dma)) {
+		printk(KERN_ERR "swim3: Can't get addresses\n");
+		return -EINVAL;
+	}
+	if (request_mem_region(res_reg.start, res_reg.end - res_reg.start + 1,
+			       " (reg)") == NULL) {
+		printk(KERN_ERR "swim3: Can't request register space\n");
+		return -EINVAL;
+	}
+	if (request_mem_region(res_dma.start, res_dma.end - res_dma.start + 1,
+			       " (dma)") == NULL) {
+		release_mem_region(res_reg.start,
+				   res_reg.end - res_reg.start + 1);
+		printk(KERN_ERR "swim3: Can't request DMA space\n");
 		return -EINVAL;
 	}
 
-	if (swim->n_intrs < 2)
-	{
-		printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n",
-		       swim->n_addrs, swim->n_intrs);
-		return -EINVAL;
-	}
-
-	if (!request_OF_resource(swim, 0, NULL)) {
-		printk(KERN_INFO "swim3: can't request IO resource !\n");
+	if (swim->n_intrs < 2) {
+		printk(KERN_INFO "swim3: expecting 2 intrs (n_intrs:%d)\n",
+		       swim->n_intrs);
+		release_mem_region(res_reg.start,
+				   res_reg.end - res_reg.start + 1);
+		release_mem_region(res_dma.start,
+				   res_dma.end - res_dma.start + 1);
 		return -EINVAL;
 	}
 
@@ -1110,10 +1120,8 @@
 	memset(fs, 0, sizeof(*fs));
 	spin_lock_init(&fs->lock);
 	fs->state = idle;
-	fs->swim3 = (struct swim3 __iomem *)
-		ioremap(swim->addrs[0].address, 0x200);
-	fs->dma = (struct dbdma_regs __iomem *)
-		ioremap(swim->addrs[1].address, 0x200);
+	fs->swim3 = (struct swim3 __iomem *)ioremap(res_reg.start, 0x200);
+	fs->dma = (struct dbdma_regs __iomem *)ioremap(res_dma.start, 0x200);
 	fs->swim3_intr = swim->intrs[0].line;
 	fs->dma_intr = swim->intrs[1].line;
 	fs->cur_cyl = -1;
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index 56d62ba..b2fc71e 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -18,6 +18,7 @@
 #include <linux/watchdog.h>
 #include <asm/8xx_immap.h>
 #include <asm/uaccess.h>
+#include <asm/io.h>
 #include <syslib/m8xx_wdt.h>
 
 static unsigned long wdt_opened;
@@ -25,18 +26,26 @@
 
 static void mpc8xx_wdt_handler_disable(void)
 {
-	volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+	volatile uint __iomem *piscr;
+	piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
 
-	imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
+	if (!m8xx_has_internal_rtc)
+		m8xx_wdt_stop_timer();
+	else
+		out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
 
 	printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
 }
 
 static void mpc8xx_wdt_handler_enable(void)
 {
-	volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+	volatile uint __iomem *piscr;
+	piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
 
-	imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
+	if (!m8xx_has_internal_rtc)
+		m8xx_wdt_install_timer();
+	else
+		out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
 
 	printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
 }
@@ -68,9 +77,6 @@
 static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
 				loff_t * ppos)
 {
-	if (ppos != &file->f_pos)
-		return -ESPIPE;
-
 	if (len)
 		m8xx_wdt_reset();
 
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 4010fe9..08d5b8f 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -236,27 +236,17 @@
 	  This support is also available as a module. If so, the module
 	  will be called i2c-ixp2000.
 
-config I2C_KEYWEST
-	tristate "Powermac Keywest I2C interface"
+config I2C_POWERMAC
+	tristate "Powermac I2C interface"
 	depends on I2C && PPC_PMAC
+	default y
 	help
-	  This supports the use of the I2C interface in the combo-I/O
-	  chip on recent Apple machines.  Say Y if you have such a machine.
-
-	  This support is also available as a module.  If so, the module 
-	  will be called i2c-keywest.
-
-config I2C_PMAC_SMU
-	tristate "Powermac SMU I2C interface"
-	depends on I2C && PMAC_SMU
-	help
-	  This supports the use of the I2C interface in the SMU
-	  chip on recent Apple machines like the iMac G5.  It is used
-	  among others by the thermal control driver for those machines.
-	  Say Y if you have such a machine.
+	  This exposes the various PowerMac i2c interfaces to the linux i2c
+	  layer and to userland. It is used by various drivers on the powemac
+	  platform, thus should generally be enabled.
 
 	  This support is also available as a module.  If so, the module
-	  will be called i2c-pmac-smu.
+	  will be called i2c-powermac.
 
 config I2C_MPC
 	tristate "MPC107/824x/85xx/52xx"
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index f1df00f..b44831d 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -19,8 +19,7 @@
 obj-$(CONFIG_I2C_ITE)		+= i2c-ite.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
 obj-$(CONFIG_I2C_IXP4XX)	+= i2c-ixp4xx.o
-obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
-obj-$(CONFIG_I2C_PMAC_SMU)	+= i2c-pmac-smu.o
+obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
 obj-$(CONFIG_I2C_NFORCE2)	+= i2c-nforce2.o
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
deleted file mode 100644
index d61f748..0000000
--- a/drivers/i2c/busses/i2c-keywest.c
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
-    i2c Support for Apple Keywest I2C Bus Controller
-
-    Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
-
-    Original work by
-    
-    Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Changes:
-
-    2001/12/13 BenH	New implementation
-    2001/12/15 BenH	Add support for "byte" and "quick"
-                        transfers. Add i2c_xfer routine.
-    2003/09/21 BenH	Rework state machine with Paulus help
-    2004/01/21 BenH	Merge in Greg KH changes, polled mode is back
-    2004/02/05 BenH	Merge 64 bits fixes from the g5 ppc64 tree
-
-    My understanding of the various modes supported by keywest are:
-
-     - Dumb mode : not implemented, probably direct tweaking of lines
-     - Standard mode : simple i2c transaction of type
-         S Addr R/W A Data A Data ... T
-     - Standard sub mode : combined 8 bit subaddr write with data read
-         S Addr R/W A SubAddr A Data A Data ... T
-     - Combined mode : Subaddress and Data sequences appended with no stop
-         S Addr R/W A SubAddr S Addr R/W A Data A Data ... T
-
-    Currently, this driver uses only Standard mode for i2c xfer, and
-    smbus byte & quick transfers ; and uses StandardSub mode for
-    other smbus transfers instead of combined as we need that for the
-    sound driver to be happy
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pmac_low_i2c.h>
-
-#include "i2c-keywest.h"
-
-#undef POLLED_MODE
-
-/* Some debug macros */
-#define WRONG_STATE(name) do {\
-		pr_debug("KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
-			 name, __kw_state_names[iface->state], isr);	\
-	} while(0)
-
-#ifdef DEBUG
-static const char *__kw_state_names[] = {
-	"state_idle",
-	"state_addr",
-	"state_read",
-	"state_write",
-	"state_stop",
-	"state_dead"
-};
-#endif /* DEBUG */
-
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
-MODULE_LICENSE("GPL");
-
-#ifdef POLLED_MODE
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8
-wait_interrupt(struct keywest_iface* iface)
-{
-	int i;
-	u8 isr;
-	
-	for (i = 0; i < 200000; i++) {
-		isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK;
-		if (isr != 0)
-			return isr;
-		udelay(10);
-	}
-	return isr;
-}
-#endif /* POLLED_MODE */
-
-static void
-do_stop(struct keywest_iface* iface, int result)
-{
-	write_reg(reg_control, KW_I2C_CTL_STOP);
-	iface->state = state_stop;
-	iface->result = result;
-}
-
-/* Main state machine for standard & standard sub mode */
-static void
-handle_interrupt(struct keywest_iface *iface, u8 isr)
-{
-	int ack;
-	
-	if (isr == 0) {
-		if (iface->state != state_stop) {
-			pr_debug("KW: Timeout !\n");
-			do_stop(iface, -EIO);
-		}
-		if (iface->state == state_stop) {
-			ack = read_reg(reg_status);
-			if (!(ack & KW_I2C_STAT_BUSY)) {
-				iface->state = state_idle;
-				write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
-				complete(&iface->complete);
-#endif /* POLLED_MODE */
-			}
-		}
-		return;
-	}
-
-	if (isr & KW_I2C_IRQ_ADDR) {
-		ack = read_reg(reg_status);
-		if (iface->state != state_addr) {
-			write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-			WRONG_STATE("KW_I2C_IRQ_ADDR"); 
-			do_stop(iface, -EIO);
-			return;
-		}
-		if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-			iface->state = state_stop;		     
-			iface->result = -ENODEV;
-			pr_debug("KW: NAK on address\n");
-		} else {
-			/* Handle rw "quick" mode */
-			if (iface->datalen == 0) {
-				do_stop(iface, 0);
-			} else if (iface->read_write == I2C_SMBUS_READ) {
-				iface->state = state_read;
-				if (iface->datalen > 1)
-					write_reg(reg_control, KW_I2C_CTL_AAK);
-			} else {
-				iface->state = state_write;
-				write_reg(reg_data, *(iface->data++));
-				iface->datalen--;
-			}
-		}
-		write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-	}
-
-	if (isr & KW_I2C_IRQ_DATA) {
-		if (iface->state == state_read) {
-			*(iface->data++) = read_reg(reg_data);
-			write_reg(reg_isr, KW_I2C_IRQ_DATA);
-			iface->datalen--;
-			if (iface->datalen == 0)
-				iface->state = state_stop;
-			else if (iface->datalen == 1)
-				write_reg(reg_control, 0);
-		} else if (iface->state == state_write) {
-			/* Check ack status */
-			ack = read_reg(reg_status);
-			if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-				pr_debug("KW: nack on data write (%x): %x\n",
-				    iface->data[-1], ack);
-				do_stop(iface, -EIO);
-			} else if (iface->datalen) {
-				write_reg(reg_data, *(iface->data++));
-				iface->datalen--;
-			} else {
-				write_reg(reg_control, KW_I2C_CTL_STOP);
-				iface->state = state_stop;
-				iface->result = 0;
-			}
-			write_reg(reg_isr, KW_I2C_IRQ_DATA);
-		} else {
-			write_reg(reg_isr, KW_I2C_IRQ_DATA);
-			WRONG_STATE("KW_I2C_IRQ_DATA"); 
-			if (iface->state != state_stop)
-				do_stop(iface, -EIO);
-		}
-	}
-
-	if (isr & KW_I2C_IRQ_STOP) {
-		write_reg(reg_isr, KW_I2C_IRQ_STOP);
-		if (iface->state != state_stop) {
-			WRONG_STATE("KW_I2C_IRQ_STOP");
-			iface->result = -EIO;
-		}
-		iface->state = state_idle;
-		write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
-		complete(&iface->complete);
-#endif /* POLLED_MODE */			
-	}
-
-	if (isr & KW_I2C_IRQ_START)
-		write_reg(reg_isr, KW_I2C_IRQ_START);
-}
-
-#ifndef POLLED_MODE
-
-/* Interrupt handler */
-static irqreturn_t
-keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct keywest_iface *iface = (struct keywest_iface *)dev_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&iface->lock, flags);
-	del_timer(&iface->timeout_timer);
-	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
-		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-		add_timer(&iface->timeout_timer);
-	}
-	spin_unlock_irqrestore(&iface->lock, flags);
-	return IRQ_HANDLED;
-}
-
-static void
-keywest_timeout(unsigned long data)
-{
-	struct keywest_iface *iface = (struct keywest_iface *)data;
-	unsigned long flags;
-
-	pr_debug("timeout !\n");
-	spin_lock_irqsave(&iface->lock, flags);
-	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
-		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-		add_timer(&iface->timeout_timer);
-	}
-	spin_unlock_irqrestore(&iface->lock, flags);
-}
-
-#endif /* POLLED_MODE */
-
-/*
- * SMBUS-type transfer entrypoint
- */
-static s32
-keywest_smbus_xfer(	struct i2c_adapter*	adap,
-			u16			addr,
-			unsigned short		flags,
-			char			read_write,
-			u8			command,
-			int			size,
-			union i2c_smbus_data*	data)
-{
-	struct keywest_chan* chan = i2c_get_adapdata(adap);
-	struct keywest_iface* iface = chan->iface;
-	int len;
-	u8* buffer;
-	u16 cur_word;
-	int rc = 0;
-
-	if (iface->state == state_dead)
-		return -ENXIO;
-		
-	/* Prepare datas & select mode */
-	iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
-	switch (size) {
-        case I2C_SMBUS_QUICK:
-	    	len = 0;
-	    	buffer = NULL;
-	    	iface->cur_mode |= KW_I2C_MODE_STANDARD;
-	    	break;
-        case I2C_SMBUS_BYTE:
-	    	len = 1;
-	    	buffer = &data->byte;
-	    	iface->cur_mode |= KW_I2C_MODE_STANDARD;
-	    	break;
-        case I2C_SMBUS_BYTE_DATA:
-	    	len = 1;
-	    	buffer = &data->byte;
-	    	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
-	    	break;
-        case I2C_SMBUS_WORD_DATA:
-	    	len = 2;
-	    	cur_word = cpu_to_le16(data->word);
-	    	buffer = (u8 *)&cur_word;
-	    	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
-		break;
-        case I2C_SMBUS_BLOCK_DATA:
-	    	len = data->block[0];
-	    	buffer = &data->block[1];
-	    	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
-		break;
-        default:
-	    	return -1;
-	}
-
-	/* Turn a standardsub read into a combined mode access */
- 	if (read_write == I2C_SMBUS_READ
- 	    && (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB) {
- 		iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
- 		iface->cur_mode |= KW_I2C_MODE_COMBINED;
- 	}
-
-	/* Original driver had this limitation */
-	if (len > 32)
-		len = 32;
-
-	if (pmac_low_i2c_lock(iface->node))
-		return -ENXIO;
-
-	pr_debug("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n",
-		chan->chan_no, addr, len, read_write == I2C_SMBUS_READ);
-
-	iface->data = buffer;
-	iface->datalen = len;
-	iface->state = state_addr;
-	iface->result = 0;
-	iface->read_write = read_write;
-	
-	/* Setup channel & clear pending irqs */
-	write_reg(reg_isr, read_reg(reg_isr));
-	write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
-	write_reg(reg_status, 0);
-
-	/* Set up address and r/w bit */
-	write_reg(reg_addr,
-		(addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
-	/* Set up the sub address */
-	if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
-	    || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
-		write_reg(reg_subaddr, command);
-
-#ifndef POLLED_MODE
-	/* Arm timeout */
-	iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-	add_timer(&iface->timeout_timer);
-#endif
-
-	/* Start sending address & enable interrupt*/
-	write_reg(reg_control, KW_I2C_CTL_XADDR);
-	write_reg(reg_ier, KW_I2C_IRQ_MASK);
-
-#ifdef POLLED_MODE
-	pr_debug("using polled mode...\n");
-	/* State machine, to turn into an interrupt handler */
-	while(iface->state != state_idle) {
-		unsigned long flags;
-
-		u8 isr = wait_interrupt(iface);
-		spin_lock_irqsave(&iface->lock, flags);
-		handle_interrupt(iface, isr);
-		spin_unlock_irqrestore(&iface->lock, flags);
-	}
-#else /* POLLED_MODE */
-	pr_debug("using interrupt mode...\n");
-	wait_for_completion(&iface->complete);	
-#endif /* POLLED_MODE */	
-
-	rc = iface->result;	
-	pr_debug("transfer done, result: %d\n", rc);
-
-	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ)
-	    	data->word = le16_to_cpu(cur_word);
-	
-	/* Release sem */
-	pmac_low_i2c_unlock(iface->node);
-	
-	return rc;
-}
-
-/*
- * Generic i2c master transfer entrypoint
- */
-static int
-keywest_xfer(	struct i2c_adapter *adap,
-		struct i2c_msg *msgs, 
-		int num)
-{
-	struct keywest_chan* chan = i2c_get_adapdata(adap);
-	struct keywest_iface* iface = chan->iface;
-	struct i2c_msg *pmsg;
-	int i, completed;
-	int rc = 0;
-
-	if (iface->state == state_dead)
-		return -ENXIO;
-
-	if (pmac_low_i2c_lock(iface->node))
-		return -ENXIO;
-
-	/* Set adapter to standard mode */
-	iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
-	iface->cur_mode |= KW_I2C_MODE_STANDARD;
-
-	completed = 0;
-	for (i = 0; rc >= 0 && i < num;) {
-		u8 addr;
-		
-		pmsg = &msgs[i++];
-		addr = pmsg->addr;
-		if (pmsg->flags & I2C_M_TEN) {
-			printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n");
-			rc = -EINVAL;
-			break;
-		}
-		pr_debug("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n",
-		     chan->chan_no,
-		     pmsg->flags & I2C_M_RD ? "read" : "write",
-                     pmsg->len, addr, i, num);
-    
-		/* Setup channel & clear pending irqs */
-		write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
-		write_reg(reg_isr, read_reg(reg_isr));
-		write_reg(reg_status, 0);
-		
-		iface->data = pmsg->buf;
-		iface->datalen = pmsg->len;
-		iface->state = state_addr;
-		iface->result = 0;
-		if (pmsg->flags & I2C_M_RD)
-			iface->read_write = I2C_SMBUS_READ;
-		else
-			iface->read_write = I2C_SMBUS_WRITE;
-
-		/* Set up address and r/w bit */
-		if (pmsg->flags & I2C_M_REV_DIR_ADDR)
-			addr ^= 1;		
-		write_reg(reg_addr,
-			(addr << 1) |
-			((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
-#ifndef POLLED_MODE
-		/* Arm timeout */
-		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-		add_timer(&iface->timeout_timer);
-#endif
-
-		/* Start sending address & enable interrupt*/
-		write_reg(reg_ier, KW_I2C_IRQ_MASK);
-		write_reg(reg_control, KW_I2C_CTL_XADDR);
-
-#ifdef POLLED_MODE
-		pr_debug("using polled mode...\n");
-		/* State machine, to turn into an interrupt handler */
-		while(iface->state != state_idle) {
-			u8 isr = wait_interrupt(iface);
-			handle_interrupt(iface, isr);
-		}
-#else /* POLLED_MODE */
-		pr_debug("using interrupt mode...\n");
-		wait_for_completion(&iface->complete);	
-#endif /* POLLED_MODE */	
-
-		rc = iface->result;
-		if (rc == 0)
-			completed++;
-		pr_debug("transfer done, result: %d\n", rc);
-	}
-
-	/* Release sem */
-	pmac_low_i2c_unlock(iface->node);
-
-	return completed;
-}
-
-static u32
-keywest_func(struct i2c_adapter * adapter)
-{
-	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-	       I2C_FUNC_SMBUS_BLOCK_DATA;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm keywest_algorithm = {
-	.smbus_xfer	= keywest_smbus_xfer,
-	.master_xfer	= keywest_xfer,
-	.functionality	= keywest_func,
-};
-
-
-static int
-create_iface(struct device_node *np, struct device *dev)
-{
-	unsigned long steps;
-	unsigned bsteps, tsize, i, nchan, addroffset;
-	struct keywest_iface* iface;
-	u32 *psteps, *prate;
-	int rc;
-
-	if (np->n_intrs < 1 || np->n_addrs < 1) {
-		printk(KERN_ERR "%s: Missing interrupt or address !\n",
-		       np->full_name);
-		return -ENODEV;
-	}
-	if (pmac_low_i2c_lock(np))
-		return -ENODEV;
-
-	psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
-	steps = psteps ? (*psteps) : 0x10;
-
-	/* Hrm... maybe we can be smarter here */
-	for (bsteps = 0; (steps & 0x01) == 0; bsteps++)
-		steps >>= 1;
-
-	if (np->parent->name[0] == 'u') {
-		nchan = 2;
-		addroffset = 3;
-	} else {
-		addroffset = 0;
-		nchan = 1;
-	}
-
-	tsize = sizeof(struct keywest_iface) +
-		(sizeof(struct keywest_chan) + 4) * nchan;
-	iface = kzalloc(tsize, GFP_KERNEL);
-	if (iface == NULL) {
-		printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n");
-		pmac_low_i2c_unlock(np);
-		return -ENOMEM;
-	}
-	spin_lock_init(&iface->lock);
-	init_completion(&iface->complete);
-	iface->node = of_node_get(np);
-	iface->bsteps = bsteps;
-	iface->chan_count = nchan;
-	iface->state = state_idle;
-	iface->irq = np->intrs[0].line;
-	iface->channels = (struct keywest_chan *)
-		(((unsigned long)(iface + 1) + 3UL) & ~3UL);
-	iface->base = ioremap(np->addrs[0].address + addroffset,
-						np->addrs[0].size);
-	if (!iface->base) {
-		printk(KERN_ERR "i2c-keywest: can't map inteface !\n");
-		kfree(iface);
-		pmac_low_i2c_unlock(np);
-		return -ENOMEM;
-	}
-
-#ifndef POLLED_MODE
-	init_timer(&iface->timeout_timer);
-	iface->timeout_timer.function = keywest_timeout;
-	iface->timeout_timer.data = (unsigned long)iface;
-#endif
-
-	/* Select interface rate */
-	iface->cur_mode = KW_I2C_MODE_100KHZ;
-	prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
-	if (prate) switch(*prate) {
-	case 100:
-		iface->cur_mode = KW_I2C_MODE_100KHZ;
-		break;
-	case 50:
-		iface->cur_mode = KW_I2C_MODE_50KHZ;
-		break;
-	case 25:
-		iface->cur_mode = KW_I2C_MODE_25KHZ;
-		break;
-	default:
-		printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n",
-		       (long)*prate);
-	}
-	
-	/* Select standard mode by default */
-	iface->cur_mode |= KW_I2C_MODE_STANDARD;
-	
-	/* Write mode */
-	write_reg(reg_mode, iface->cur_mode);
-	
-	/* Switch interrupts off & clear them*/
-	write_reg(reg_ier, 0x00);
-	write_reg(reg_isr, KW_I2C_IRQ_MASK);
-
-#ifndef POLLED_MODE
-	/* Request chip interrupt */	
-	rc = request_irq(iface->irq, keywest_irq, SA_INTERRUPT, "keywest i2c", iface);
-	if (rc) {
-		printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq);
-		iounmap(iface->base);
-		kfree(iface);
-		pmac_low_i2c_unlock(np);
-		return -ENODEV;
-	}
-#endif /* POLLED_MODE */
-
-	pmac_low_i2c_unlock(np);
-	dev_set_drvdata(dev, iface);
-	
-	for (i=0; i<nchan; i++) {
-		struct keywest_chan* chan = &iface->channels[i];
-		
-		sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
-		chan->iface = iface;
-		chan->chan_no = i;
-		chan->adapter.algo = &keywest_algorithm;
-		chan->adapter.algo_data = NULL;
-		chan->adapter.client_register = NULL;
-		chan->adapter.client_unregister = NULL;
-		i2c_set_adapdata(&chan->adapter, chan);
-		chan->adapter.dev.parent = dev;
-
-		rc = i2c_add_adapter(&chan->adapter);
-		if (rc) {
-			printk("i2c-keywest.c: Adapter %s registration failed\n",
-				chan->adapter.name);
-			i2c_set_adapdata(&chan->adapter, NULL);
-		}
-	}
-
-	printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
-		np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps);
-		
-	return 0;
-}
-
-static int
-dispose_iface(struct device *dev)
-{
-	struct keywest_iface *iface = dev_get_drvdata(dev);
-	int i, rc;
-	
-	/* Make sure we stop all activity */
-	if (pmac_low_i2c_lock(iface->node))
-		return -ENODEV;
-
-#ifndef POLLED_MODE
-	spin_lock_irq(&iface->lock);
-	while (iface->state != state_idle) {
-		spin_unlock_irq(&iface->lock);
-		msleep(100);
-		spin_lock_irq(&iface->lock);
-	}
-#endif /* POLLED_MODE */
-	iface->state = state_dead;
-#ifndef POLLED_MODE
-	spin_unlock_irq(&iface->lock);
-	free_irq(iface->irq, iface);
-#endif /* POLLED_MODE */
-
-	pmac_low_i2c_unlock(iface->node);
-
-	/* Release all channels */
-	for (i=0; i<iface->chan_count; i++) {
-		struct keywest_chan* chan = &iface->channels[i];
-		if (i2c_get_adapdata(&chan->adapter) == NULL)
-			continue;
-		rc = i2c_del_adapter(&chan->adapter);
-		i2c_set_adapdata(&chan->adapter, NULL);
-		/* We aren't that prepared to deal with this... */
-		if (rc)
-			printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n");
-	}
-	iounmap(iface->base);
-	dev_set_drvdata(dev, NULL);
-	of_node_put(iface->node);
-	kfree(iface);
-
-	return 0;
-}
-
-static int
-create_iface_macio(struct macio_dev* dev, const struct of_device_id *match)
-{
-	return create_iface(dev->ofdev.node, &dev->ofdev.dev);
-}
-
-static int
-dispose_iface_macio(struct macio_dev* dev)
-{
-	return dispose_iface(&dev->ofdev.dev);
-}
-
-static int
-create_iface_of_platform(struct of_device* dev, const struct of_device_id *match)
-{
-	return create_iface(dev->node, &dev->dev);
-}
-
-static int
-dispose_iface_of_platform(struct of_device* dev)
-{
-	return dispose_iface(&dev->dev);
-}
-
-static struct of_device_id i2c_keywest_match[] = 
-{
-	{
-	.type		= "i2c",
-	.compatible	= "keywest"
-	},
-	{},
-};
-
-static struct macio_driver i2c_keywest_macio_driver = 
-{
-	.owner		= THIS_MODULE,
-	.name 		= "i2c-keywest",
-	.match_table	= i2c_keywest_match,
-	.probe		= create_iface_macio,
-	.remove		= dispose_iface_macio
-};
-
-static struct of_platform_driver i2c_keywest_of_platform_driver = 
-{
-	.owner		= THIS_MODULE,
-	.name 		= "i2c-keywest",
-	.match_table	= i2c_keywest_match,
-	.probe		= create_iface_of_platform,
-	.remove		= dispose_iface_of_platform
-};
-
-static int __init
-i2c_keywest_init(void)
-{
-	of_register_driver(&i2c_keywest_of_platform_driver);
-	macio_register_driver(&i2c_keywest_macio_driver);
-
-	return 0;
-}
-
-static void __exit
-i2c_keywest_cleanup(void)
-{
-	of_unregister_driver(&i2c_keywest_of_platform_driver);
-	macio_unregister_driver(&i2c_keywest_macio_driver);
-}
-
-module_init(i2c_keywest_init);
-module_exit(i2c_keywest_cleanup);
diff --git a/drivers/i2c/busses/i2c-keywest.h b/drivers/i2c/busses/i2c-keywest.h
deleted file mode 100644
index c5022e1..0000000
--- a/drivers/i2c/busses/i2c-keywest.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef __I2C_KEYWEST_H__
-#define __I2C_KEYWEST_H__
-
-/* The Tumbler audio equalizer can be really slow sometimes */
-#define POLL_TIMEOUT		(2*HZ)
-
-/* Register indices */
-typedef enum {
-	reg_mode = 0,
-	reg_control,
-	reg_status,
-	reg_isr,
-	reg_ier,
-	reg_addr,
-	reg_subaddr,
-	reg_data
-} reg_t;
-
-
-/* Mode register */
-#define KW_I2C_MODE_100KHZ	0x00
-#define KW_I2C_MODE_50KHZ	0x01
-#define KW_I2C_MODE_25KHZ	0x02
-#define KW_I2C_MODE_DUMB	0x00
-#define KW_I2C_MODE_STANDARD	0x04
-#define KW_I2C_MODE_STANDARDSUB	0x08
-#define KW_I2C_MODE_COMBINED	0x0C
-#define KW_I2C_MODE_MODE_MASK	0x0C
-#define KW_I2C_MODE_CHAN_MASK	0xF0
-
-/* Control register */
-#define KW_I2C_CTL_AAK		0x01
-#define KW_I2C_CTL_XADDR	0x02
-#define KW_I2C_CTL_STOP		0x04
-#define KW_I2C_CTL_START	0x08
-
-/* Status register */
-#define KW_I2C_STAT_BUSY	0x01
-#define KW_I2C_STAT_LAST_AAK	0x02
-#define KW_I2C_STAT_LAST_RW	0x04
-#define KW_I2C_STAT_SDA		0x08
-#define KW_I2C_STAT_SCL		0x10
-
-/* IER & ISR registers */
-#define KW_I2C_IRQ_DATA		0x01
-#define KW_I2C_IRQ_ADDR		0x02
-#define KW_I2C_IRQ_STOP		0x04
-#define KW_I2C_IRQ_START	0x08
-#define KW_I2C_IRQ_MASK		0x0F
-
-/* Physical interface */
-struct keywest_iface
-{
-	struct device_node	*node;
-	void __iomem *		base;
-	unsigned		bsteps;
-	int			irq;
-	spinlock_t		lock;
-	struct keywest_chan	*channels;
-	unsigned		chan_count;
-	u8			cur_mode;
-	char			read_write;
-	u8			*data;
-	unsigned		datalen;
-	int			state;
-	int			result;
-	struct timer_list	timeout_timer;
-	struct completion	complete;
-};
-
-enum {
-	state_idle,
-	state_addr,
-	state_read,
-	state_write,
-	state_stop,
-	state_dead
-};
-
-/* Channel on an interface */
-struct keywest_chan
-{
-	struct i2c_adapter	adapter;
-	struct keywest_iface*	iface;
-	unsigned		chan_no;
-};
-
-/* Register access */
-
-static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg)
-{
-	return in_8(iface->base
-		+ (((unsigned)reg) << iface->bsteps));
-}
-
-static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val)
-{
-	out_8(iface->base
-		+ (((unsigned)reg) << iface->bsteps), val);
-	(void)__read_reg(iface, reg_subaddr);
-}
-
-#define write_reg(reg, val)	__write_reg(iface, reg, val) 
-#define read_reg(reg)		__read_reg(iface, reg) 
-
-
-
-#endif /* __I2C_KEYWEST_H__ */
diff --git a/drivers/i2c/busses/i2c-pmac-smu.c b/drivers/i2c/busses/i2c-pmac-smu.c
deleted file mode 100644
index bfefe7f..0000000
--- a/drivers/i2c/busses/i2c-pmac-smu.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
-    i2c Support for Apple SMU Controller
-
-    Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
-                       <benh@kernel.crashing.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/smu.h>
-
-static int probe;
-
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("I2C driver for Apple's SMU");
-MODULE_LICENSE("GPL");
-module_param(probe, bool, 0);
-
-
-/* Physical interface */
-struct smu_iface
-{
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	u32			busid;
-};
-
-static void smu_i2c_done(struct smu_i2c_cmd *cmd, void *misc)
-{
-	struct smu_iface	*iface = misc;
-	complete(&iface->complete);
-}
-
-/*
- * SMBUS-type transfer entrypoint
- */
-static s32 smu_smbus_xfer(	struct i2c_adapter*	adap,
-				u16			addr,
-				unsigned short		flags,
-				char			read_write,
-				u8			command,
-				int			size,
-				union i2c_smbus_data*	data)
-{
-	struct smu_iface	*iface = i2c_get_adapdata(adap);
-	struct smu_i2c_cmd	cmd;
-	int			rc = 0;
-	int			read = (read_write == I2C_SMBUS_READ);
-
-	cmd.info.bus = iface->busid;
-	cmd.info.devaddr = (addr << 1) | (read ? 0x01 : 0x00);
-
-	/* Prepare datas & select mode */
-	switch (size) {
-        case I2C_SMBUS_QUICK:
-		cmd.info.type = SMU_I2C_TRANSFER_SIMPLE;
-		cmd.info.datalen = 0;
-	    	break;
-        case I2C_SMBUS_BYTE:
-		cmd.info.type = SMU_I2C_TRANSFER_SIMPLE;
-		cmd.info.datalen = 1;
-		if (!read)
-			cmd.info.data[0] = data->byte;
-	    	break;
-        case I2C_SMBUS_BYTE_DATA:
-		cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
-		cmd.info.datalen = 1;
-		cmd.info.sublen = 1;
-		cmd.info.subaddr[0] = command;
-		cmd.info.subaddr[1] = 0;
-		cmd.info.subaddr[2] = 0;
-		if (!read)
-			cmd.info.data[0] = data->byte;
-	    	break;
-        case I2C_SMBUS_WORD_DATA:
-		cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
-		cmd.info.datalen = 2;
-		cmd.info.sublen = 1;
-		cmd.info.subaddr[0] = command;
-		cmd.info.subaddr[1] = 0;
-		cmd.info.subaddr[2] = 0;
-		if (!read) {
-			cmd.info.data[0] = data->byte & 0xff;
-			cmd.info.data[1] = (data->byte >> 8) & 0xff;
-		}
-		break;
-	/* Note that these are broken vs. the expected smbus API where
-	 * on reads, the lenght is actually returned from the function,
-	 * but I think the current API makes no sense and I don't want
-	 * any driver that I haven't verified for correctness to go
-	 * anywhere near a pmac i2c bus anyway ...
-	 */
-        case I2C_SMBUS_BLOCK_DATA:
-		cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
-		cmd.info.datalen = data->block[0] + 1;
-		if (cmd.info.datalen > 6)
-			return -EINVAL;
-		if (!read)
-			memcpy(cmd.info.data, data->block, cmd.info.datalen);
-		cmd.info.sublen = 1;
-		cmd.info.subaddr[0] = command;
-		cmd.info.subaddr[1] = 0;
-		cmd.info.subaddr[2] = 0;
-		break;
-	case I2C_SMBUS_I2C_BLOCK_DATA:
-		cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
-		cmd.info.datalen = data->block[0];
-		if (cmd.info.datalen > 7)
-			return -EINVAL;
-		if (!read)
-			memcpy(cmd.info.data, &data->block[1],
-			       cmd.info.datalen);
-		cmd.info.sublen = 1;
-		cmd.info.subaddr[0] = command;
-		cmd.info.subaddr[1] = 0;
-		cmd.info.subaddr[2] = 0;
-		break;
-
-        default:
-	    	return -EINVAL;
-	}
-
-	/* Turn a standardsub read into a combined mode access */
- 	if (read_write == I2C_SMBUS_READ &&
-	    cmd.info.type == SMU_I2C_TRANSFER_STDSUB)
-		cmd.info.type = SMU_I2C_TRANSFER_COMBINED;
-
-	/* Finish filling command and submit it */
-	cmd.done = smu_i2c_done;
-	cmd.misc = iface;
-	rc = smu_queue_i2c(&cmd);
-	if (rc < 0)
-		return rc;
-	wait_for_completion(&iface->complete);
-	rc = cmd.status;
-
-	if (!read || rc < 0)
-		return rc;
-
-	switch (size) {
-        case I2C_SMBUS_BYTE:
-        case I2C_SMBUS_BYTE_DATA:
-		data->byte = cmd.info.data[0];
-	    	break;
-        case I2C_SMBUS_WORD_DATA:
-		data->word = ((u16)cmd.info.data[1]) << 8;
-		data->word |= cmd.info.data[0];
-		break;
-	/* Note that these are broken vs. the expected smbus API where
-	 * on reads, the lenght is actually returned from the function,
-	 * but I think the current API makes no sense and I don't want
-	 * any driver that I haven't verified for correctness to go
-	 * anywhere near a pmac i2c bus anyway ...
-	 */
-        case I2C_SMBUS_BLOCK_DATA:
-	case I2C_SMBUS_I2C_BLOCK_DATA:
-		memcpy(&data->block[0], cmd.info.data, cmd.info.datalen);
-		break;
-	}
-
-	return rc;
-}
-
-static u32
-smu_smbus_func(struct i2c_adapter * adapter)
-{
-	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-	       I2C_FUNC_SMBUS_BLOCK_DATA;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm smu_algorithm = {
-	.smbus_xfer	= smu_smbus_xfer,
-	.functionality	= smu_smbus_func,
-};
-
-static int create_iface(struct device_node *np, struct device *dev)
-{
-	struct smu_iface* iface;
-	u32 *reg, busid;
-	int rc;
-
-	reg = (u32 *)get_property(np, "reg", NULL);
-	if (reg == NULL) {
-		printk(KERN_ERR "i2c-pmac-smu: can't find bus number !\n");
-		return -ENXIO;
-	}
-	busid = *reg;
-
-	iface = kzalloc(sizeof(struct smu_iface), GFP_KERNEL);
-	if (iface == NULL) {
-		printk(KERN_ERR "i2c-pmac-smu: can't allocate inteface !\n");
-		return -ENOMEM;
-	}
-	init_completion(&iface->complete);
-	iface->busid = busid;
-
-	dev_set_drvdata(dev, iface);
-
-	sprintf(iface->adapter.name, "smu-i2c-%02x", busid);
-	iface->adapter.algo = &smu_algorithm;
-	iface->adapter.algo_data = NULL;
-	iface->adapter.client_register = NULL;
-	iface->adapter.client_unregister = NULL;
-	i2c_set_adapdata(&iface->adapter, iface);
-	iface->adapter.dev.parent = dev;
-
-	rc = i2c_add_adapter(&iface->adapter);
-	if (rc) {
-		printk(KERN_ERR "i2c-pamc-smu.c: Adapter %s registration "
-		       "failed\n", iface->adapter.name);
-		i2c_set_adapdata(&iface->adapter, NULL);
-	}
-
-	if (probe) {
-		unsigned char addr;
-		printk("Probe: ");
-		for (addr = 0x00; addr <= 0x7f; addr++) {
-			if (i2c_smbus_xfer(&iface->adapter,addr,
-					   0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
-				printk("%02x ", addr);
-		}
-		printk("\n");
-	}
-
-	printk(KERN_INFO "SMU i2c bus %x registered\n", busid);
-
-	return 0;
-}
-
-static int dispose_iface(struct device *dev)
-{
-	struct smu_iface *iface = dev_get_drvdata(dev);
-	int rc;
-
-	rc = i2c_del_adapter(&iface->adapter);
-	i2c_set_adapdata(&iface->adapter, NULL);
-	/* We aren't that prepared to deal with this... */
-	if (rc)
-		printk("i2c-pmac-smu.c: Failed to remove bus %s !\n",
-		       iface->adapter.name);
-	dev_set_drvdata(dev, NULL);
-	kfree(iface);
-
-	return 0;
-}
-
-
-static int create_iface_of_platform(struct of_device* dev,
-				    const struct of_device_id *match)
-{
-	return create_iface(dev->node, &dev->dev);
-}
-
-
-static int dispose_iface_of_platform(struct of_device* dev)
-{
-	return dispose_iface(&dev->dev);
-}
-
-
-static struct of_device_id i2c_smu_match[] =
-{
-	{
-		.compatible	= "smu-i2c",
-	},
-	{},
-};
-static struct of_platform_driver i2c_smu_of_platform_driver =
-{
-	.name 		= "i2c-smu",
-	.match_table	= i2c_smu_match,
-	.probe		= create_iface_of_platform,
-	.remove		= dispose_iface_of_platform
-};
-
-
-static int __init i2c_pmac_smu_init(void)
-{
-	of_register_driver(&i2c_smu_of_platform_driver);
-	return 0;
-}
-
-
-static void __exit i2c_pmac_smu_cleanup(void)
-{
-	of_unregister_driver(&i2c_smu_of_platform_driver);
-}
-
-module_init(i2c_pmac_smu_init);
-module_exit(i2c_pmac_smu_cleanup);
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
new file mode 100644
index 0000000..df786eb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -0,0 +1,290 @@
+/*
+    i2c Support for Apple SMU Controller
+
+    Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
+                       <benh@kernel.crashing.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/pmac_low_i2c.h>
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("I2C driver for Apple PowerMac");
+MODULE_LICENSE("GPL");
+
+/*
+ * SMBUS-type transfer entrypoint
+ */
+static s32 i2c_powermac_smbus_xfer(	struct i2c_adapter*	adap,
+					u16			addr,
+					unsigned short		flags,
+					char			read_write,
+					u8			command,
+					int			size,
+					union i2c_smbus_data*	data)
+{
+	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adap);
+	int			rc = 0;
+	int			read = (read_write == I2C_SMBUS_READ);
+	int			addrdir = (addr << 1) | read;
+	u8			local[2];
+
+	rc = pmac_i2c_open(bus, 0);
+	if (rc)
+		return rc;
+
+	switch (size) {
+        case I2C_SMBUS_QUICK:
+		rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+		if (rc)
+			goto bail;
+		rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
+	    	break;
+        case I2C_SMBUS_BYTE:
+		rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+		if (rc)
+			goto bail;
+		rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
+	    	break;
+        case I2C_SMBUS_BYTE_DATA:
+		rc = pmac_i2c_setmode(bus, read ?
+				      pmac_i2c_mode_combined :
+				      pmac_i2c_mode_stdsub);
+		if (rc)
+			goto bail;
+		rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
+	    	break;
+        case I2C_SMBUS_WORD_DATA:
+		rc = pmac_i2c_setmode(bus, read ?
+				      pmac_i2c_mode_combined :
+				      pmac_i2c_mode_stdsub);
+		if (rc)
+			goto bail;
+		if (!read) {
+			local[0] = data->word & 0xff;
+			local[1] = (data->word >> 8) & 0xff;
+		}
+		rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2);
+		if (rc == 0 && read) {
+			data->word = ((u16)local[1]) << 8;
+			data->word |= local[0];
+		}
+	    	break;
+
+	/* Note that these are broken vs. the expected smbus API where
+	 * on reads, the lenght is actually returned from the function,
+	 * but I think the current API makes no sense and I don't want
+	 * any driver that I haven't verified for correctness to go
+	 * anywhere near a pmac i2c bus anyway ...
+	 *
+	 * I'm also not completely sure what kind of phases to do between
+	 * the actual command and the data (what I am _supposed_ to do that
+	 * is). For now, I assume writes are a single stream and reads have
+	 * a repeat start/addr phase (but not stop in between)
+	 */
+        case I2C_SMBUS_BLOCK_DATA:
+		rc = pmac_i2c_setmode(bus, read ?
+				      pmac_i2c_mode_combined :
+				      pmac_i2c_mode_stdsub);
+		if (rc)
+			goto bail;
+		rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
+				   data->block[0] + 1);
+
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		rc = pmac_i2c_setmode(bus, read ?
+				      pmac_i2c_mode_combined :
+				      pmac_i2c_mode_stdsub);
+		if (rc)
+			goto bail;
+		rc = pmac_i2c_xfer(bus, addrdir, 1, command,
+				   read ? data->block : &data->block[1],
+				   data->block[0]);
+		break;
+
+        default:
+	    	rc = -EINVAL;
+	}
+ bail:
+	pmac_i2c_close(bus);
+	return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint. This driver only support single
+ * messages (for "lame i2c" transfers). Anything else should use the smbus
+ * entry point
+ */
+static int i2c_powermac_master_xfer(	struct i2c_adapter *adap,
+					struct i2c_msg *msgs,
+					int num)
+{
+	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adap);
+	int			rc = 0;
+	int			read;
+	int			addrdir;
+
+	if (num != 1)
+		return -EINVAL;
+	if (msgs->flags & I2C_M_TEN)
+		return -EINVAL;
+	read = (msgs->flags & I2C_M_RD) != 0;
+	addrdir = (msgs->addr << 1) | read;
+	if (msgs->flags & I2C_M_REV_DIR_ADDR)
+		addrdir ^= 1;
+
+	rc = pmac_i2c_open(bus, 0);
+	if (rc)
+		return rc;
+	rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+	if (rc)
+		goto bail;
+	rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+ bail:
+	pmac_i2c_close(bus);
+	return rc < 0 ? rc : msgs->len;
+}
+
+static u32 i2c_powermac_func(struct i2c_adapter * adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+		I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;
+}
+
+/* For now, we only handle smbus */
+static struct i2c_algorithm i2c_powermac_algorithm = {
+	.smbus_xfer	= i2c_powermac_smbus_xfer,
+	.master_xfer	= i2c_powermac_master_xfer,
+	.functionality	= i2c_powermac_func,
+};
+
+
+static int i2c_powermac_remove(struct device *dev)
+{
+	struct i2c_adapter	*adapter = dev_get_drvdata(dev);
+	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adapter);
+	int			rc;
+
+	rc = i2c_del_adapter(adapter);
+	pmac_i2c_detach_adapter(bus, adapter);
+	i2c_set_adapdata(adapter, NULL);
+	/* We aren't that prepared to deal with this... */
+	if (rc)
+		printk("i2c-powermac.c: Failed to remove bus %s !\n",
+		       adapter->name);
+	dev_set_drvdata(dev, NULL);
+	kfree(adapter);
+
+	return 0;
+}
+
+
+static int i2c_powermac_probe(struct device *dev)
+{
+	struct pmac_i2c_bus *bus = dev->platform_data;
+	struct device_node *parent = NULL;
+	struct i2c_adapter *adapter;
+	char name[32], *basename;
+	int rc;
+
+	if (bus == NULL)
+		return -EINVAL;
+
+	/* Ok, now we need to make up a name for the interface that will
+	 * match what we used to do in the past, that is basically the
+	 * controller's parent device node for keywest. PMU didn't have a
+	 * naming convention and SMU has a different one
+	 */
+	switch(pmac_i2c_get_type(bus)) {
+	case pmac_i2c_bus_keywest:
+		parent = of_get_parent(pmac_i2c_get_controller(bus));
+		if (parent == NULL)
+			return -EINVAL;
+		basename = parent->name;
+		break;
+	case pmac_i2c_bus_pmu:
+		basename = "pmu";
+		break;
+	case pmac_i2c_bus_smu:
+		/* This is not what we used to do but I'm fixing drivers at
+		 * the same time as this change
+		 */
+		basename = "smu";
+		break;
+	default:
+		return -EINVAL;
+	}
+	snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus));
+	of_node_put(parent);
+
+	adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+	if (adapter == NULL) {
+		printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
+		return -ENOMEM;
+	}
+	dev_set_drvdata(dev, adapter);
+	strcpy(adapter->name, name);
+	adapter->algo = &i2c_powermac_algorithm;
+	i2c_set_adapdata(adapter, bus);
+	adapter->dev.parent = dev;
+	pmac_i2c_attach_adapter(bus, adapter);
+	rc = i2c_add_adapter(adapter);
+	if (rc) {
+		printk(KERN_ERR "i2c-powermac: Adapter %s registration "
+		       "failed\n", name);
+		i2c_set_adapdata(adapter, NULL);
+		pmac_i2c_detach_adapter(bus, adapter);
+	}
+
+	printk(KERN_INFO "PowerMac i2c bus %s registered\n", name);
+	return rc;
+}
+
+
+static struct device_driver i2c_powermac_driver = {
+	.name = "i2c-powermac",
+	.bus = &platform_bus_type,
+	.probe = i2c_powermac_probe,
+	.remove = i2c_powermac_remove,
+};
+
+static int __init i2c_powermac_init(void)
+{
+	driver_register(&i2c_powermac_driver);
+	return 0;
+}
+
+
+static void __exit i2c_powermac_cleanup(void)
+{
+	driver_unregister(&i2c_powermac_driver);
+}
+
+module_init(i2c_powermac_init);
+module_exit(i2c_powermac_cleanup);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index d31117e..e4d55ad 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1332,8 +1332,6 @@
 	if (cdrom_read_from_buffer(drive))
 		return ide_stopped;
 
-	blk_attempt_remerge(drive->queue, rq);
-
 	/* Clear the local sector buffer. */
 	info->nsectors_buffered = 0;
 
@@ -1874,14 +1872,6 @@
 		return ide_stopped;
 	}
 
-	/*
-	 * for dvd-ram and such media, it's a really big deal to get
-	 * big writes all the time. so scour the queue and attempt to
-	 * remerge requests, often the plugging will not have had time
-	 * to do this properly
-	 */
-	blk_attempt_remerge(drive->queue, rq);
-
 	info->nsectors_buffered = 0;
 
 	/* use dma, if possible. we don't need to check more, since we
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index b5dc6df..dea2d4d 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -55,9 +55,22 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
+void ide_softirq_done(struct request *rq)
+{
+	request_queue_t *q = rq->q;
+
+	add_disk_randomness(rq->rq_disk);
+	end_that_request_chunk(rq, rq->errors, rq->data_len);
+
+	spin_lock_irq(q->queue_lock);
+	end_that_request_last(rq, rq->errors);
+	spin_unlock_irq(q->queue_lock);
+}
+
 int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
 		      int nr_sectors)
 {
+	unsigned int nbytes;
 	int ret = 1;
 
 	BUG_ON(!(rq->flags & REQ_STARTED));
@@ -81,17 +94,28 @@
 		HWGROUP(drive)->hwif->ide_dma_on(drive);
 	}
 
-	if (!end_that_request_first(rq, uptodate, nr_sectors)) {
-		add_disk_randomness(rq->rq_disk);
-
-		if (blk_rq_tagged(rq))
-			blk_queue_end_tag(drive->queue, rq);
-
+	/*
+	 * For partial completions (or non fs/pc requests), use the regular
+	 * direct completion path.
+	 */
+	nbytes = nr_sectors << 9;
+	if (rq_all_done(rq, nbytes)) {
+		rq->errors = uptodate;
+		rq->data_len = nbytes;
 		blkdev_dequeue_request(rq);
 		HWGROUP(drive)->rq = NULL;
-		end_that_request_last(rq, uptodate);
+		blk_complete_request(rq);
 		ret = 0;
+	} else {
+		if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+			add_disk_randomness(rq->rq_disk);
+			blkdev_dequeue_request(rq);
+			HWGROUP(drive)->rq = NULL;
+			end_that_request_last(rq, uptodate);
+			ret = 0;
+		}
 	}
+
 	return ret;
 }
 EXPORT_SYMBOL(__ide_end_request);
@@ -113,6 +137,10 @@
 	unsigned long flags;
 	int ret = 1;
 
+	/*
+	 * room for locking improvements here, the calls below don't
+	 * need the queue lock held at all
+	 */
 	spin_lock_irqsave(&ide_lock, flags);
 	rq = HWGROUP(drive)->rq;
 
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 02167a5..1ddaa71 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1011,6 +1011,8 @@
 	blk_queue_max_hw_segments(q, max_sg_entries);
 	blk_queue_max_phys_segments(q, max_sg_entries);
 
+	blk_queue_softirq_done(q, ide_softirq_done);
+
 	/* assign drive queue */
 	drive->queue = q;
 
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 16b2835..5013b12 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1271,7 +1271,7 @@
 pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 {
 	struct device_node *np = pmif->node;
-	int *bidp, i;
+	int *bidp;
 
 	pmif->cable_80 = 0;
 	pmif->broken_dma = pmif->broken_dma_warn = 0;
@@ -1430,7 +1430,7 @@
 	pmif = &pmac_ide[i];
 	hwif = &ide_hwifs[i];
 
-	if (mdev->ofdev.node->n_addrs == 0) {
+	if (macio_resource_count(mdev) == 0) {
 		printk(KERN_WARNING "ide%d: no address for %s\n",
 		       i, mdev->ofdev.node->full_name);
 		return -ENXIO;
@@ -1686,7 +1686,7 @@
 #else
 	macio_register_driver(&pmac_ide_macio_driver);
 	pci_register_driver(&pmac_ide_pci_driver);
-#endif	
+#endif
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a0ea44c..7d4a0ac 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -149,14 +149,14 @@
 
 config THERM_WINDTUNNEL
 	tristate "Support for thermal management on Windtunnel G4s"
-	depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
+	depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
 	help
 	  This driver provides some thermostat and fan control for the desktop
 	  G4 "Windtunnel"
 
 config THERM_ADT746X
 	tristate "Support for thermal mgmnt on laptops with ADT 746x chipset"
-	depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
+	depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
 	help
 	  This driver provides some thermostat and fan control for the
           iBook G4, and the ATI based aluminium PowerBooks, allowing slighlty
@@ -164,7 +164,7 @@
 
 config THERM_PM72
 	tristate "Support for thermal management on PowerMac G5"
-	depends on I2C && I2C_KEYWEST && PPC_PMAC64
+	depends on I2C && I2C_POWERMAC && PPC_PMAC64
 	help
 	  This driver provides thermostat and fan control for the desktop
 	  G5 machines. 
@@ -175,14 +175,14 @@
 config WINDFARM_PM81
 	tristate "Support for thermal management on iMac G5"
 	depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
-	select I2C_PMAC_SMU
+	select I2C_POWERMAC
 	help
 	  This driver provides thermal control for the iMacG5
 
 config WINDFARM_PM91
 	tristate "Support for thermal management on PowerMac9,1"
 	depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
-	select I2C_PMAC_SMU
+	select I2C_POWERMAC
 	help
 	  This driver provides thermal control for the PowerMac9,1
           which is the recent (SMU based) single CPU desktop G5
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 228e185..2a545ce 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -3,6 +3,13 @@
  * a MacIO ASIC. Interface to new driver model mostly
  * stolen from the PCI version.
  * 
+ *  Copyright (C) 2005 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *
  * TODO:
  * 
  *  - Don't probe below media bay by default, but instead provide
@@ -218,12 +225,14 @@
 
 
 /**
- * macio_release_dev - free a macio device structure when all users of it are finished.
+ * macio_release_dev - free a macio device structure when all users of it are
+ * finished.
  * @dev: device that's been disconnected
  *
- * Will be called only by the device core when all users of this macio device are
- * done. This currently means never as we don't hot remove any macio device yet,
- * though that will happen with mediabay based devices in a later implementation.
+ * Will be called only by the device core when all users of this macio device
+ * are done. This currently means never as we don't hot remove any macio
+ * device yet, though that will happen with mediabay based devices in a later
+ * implementation.
  */
 static void macio_release_dev(struct device *dev)
 {
@@ -242,49 +251,114 @@
  * If this routine returns non-null, then the resource is completely
  * skipped.
  */
-static int macio_resource_quirks(struct device_node *np, struct resource *res, int index)
+static int macio_resource_quirks(struct device_node *np, struct resource *res,
+				 int index)
 {
 	if (res->flags & IORESOURCE_MEM) {
 		/* Grand Central has too large resource 0 on some machines */
-		if (index == 0 && !strcmp(np->name, "gc")) {
-			np->addrs[0].size = 0x20000;
+		if (index == 0 && !strcmp(np->name, "gc"))
 			res->end = res->start + 0x1ffff;
-		}
+
 		/* Airport has bogus resource 2 */
 		if (index >= 2 && !strcmp(np->name, "radio"))
 			return 1;
+
+#ifndef CONFIG_PPC64
 		/* DBDMAs may have bogus sizes */
-		if ((res->start & 0x0001f000) == 0x00008000) {
-			np->addrs[index].size = 0x100;
+		if ((res->start & 0x0001f000) == 0x00008000)
 			res->end = res->start + 0xff;
-		}
-		/* ESCC parent eats child resources. We could have added a level of hierarchy,
-		 * but I don't really feel the need for it */
+#endif /* CONFIG_PPC64 */
+
+		/* ESCC parent eats child resources. We could have added a
+		 * level of hierarchy, but I don't really feel the need
+		 * for it
+		 */
 		if (!strcmp(np->name, "escc"))
 			return 1;
+
 		/* ESCC has bogus resources >= 3 */
-		if (index >= 3 && !(strcmp(np->name, "ch-a") && strcmp(np->name, "ch-b")))
+		if (index >= 3 && !(strcmp(np->name, "ch-a") &&
+				    strcmp(np->name, "ch-b")))
 			return 1;
+
 		/* Media bay has too many resources, keep only first one */
 		if (index > 0 && !strcmp(np->name, "media-bay"))
 			return 1;
+
 		/* Some older IDE resources have bogus sizes */
 		if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
 		      strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
-			if (index == 0 && np->addrs[0].size > 0x1000) {
-				np->addrs[0].size = 0x1000;
+			if (index == 0 && (res->end - res->start) > 0xfff)
 				res->end = res->start + 0xfff;
-			}
-			if (index == 1 && np->addrs[1].size > 0x100) {
-				np->addrs[1].size = 0x100;
+			if (index == 1 && (res->end - res->start) > 0xff)
 				res->end = res->start + 0xff;
-			}
 		}
 	}
 	return 0;
 }
 
 
+static void macio_setup_interrupts(struct macio_dev *dev)
+{
+	struct device_node *np = dev->ofdev.node;
+	int i,j;
+
+	/* For now, we use pre-parsed entries in the device-tree for
+	 * interrupt routing and addresses, but we should change that
+	 * to dynamically parsed entries and so get rid of most of the
+	 * clutter in struct device_node
+	 */
+	for (i = j = 0; i < np->n_intrs; i++) {
+		struct resource *res = &dev->interrupt[j];
+
+		if (j >= MACIO_DEV_COUNT_IRQS)
+			break;
+		res->start = np->intrs[i].line;
+		res->flags = IORESOURCE_IO;
+		if (np->intrs[j].sense)
+			res->flags |= IORESOURCE_IRQ_LOWLEVEL;
+		else
+			res->flags |= IORESOURCE_IRQ_HIGHEDGE;
+		res->name = dev->ofdev.dev.bus_id;
+		if (macio_resource_quirks(np, res, i))
+			memset(res, 0, sizeof(struct resource));
+		else
+			j++;
+	}
+	dev->n_interrupts = j;
+}
+
+static void macio_setup_resources(struct macio_dev *dev,
+				  struct resource *parent_res)
+{
+	struct device_node *np = dev->ofdev.node;
+	struct resource r;
+	int index;
+
+	for (index = 0; of_address_to_resource(np, index, &r) == 0; index++) {
+		struct resource *res = &dev->resource[index];
+		if (index >= MACIO_DEV_COUNT_RESOURCES)
+			break;
+		*res = r;
+		res->name = dev->ofdev.dev.bus_id;
+
+		if (macio_resource_quirks(np, res, index)) {
+			memset(res, 0, sizeof(struct resource));
+			continue;
+		}
+		/* Currently, we consider failure as harmless, this may
+		 * change in the future, once I've found all the device
+		 * tree bugs in older machines & worked around them
+		 */
+		if (insert_resource(parent_res, res)) {
+			printk(KERN_WARNING "Can't request resource "
+			       "%d for MacIO device %s\n",
+			       index, dev->ofdev.dev.bus_id);
+		}
+	}
+	dev->n_resources = index;
+}
+
 /**
  * macio_add_one_device - Add one device from OF node to the device tree
  * @chip: pointer to the macio_chip holding the device
@@ -294,12 +368,13 @@
  * When media-bay is changed to hotswap drivers, this function will
  * be exposed to the bay driver some way...
  */
-static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct device *parent,
-					       struct device_node *np, struct macio_dev *in_bay,
+static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
+					       struct device *parent,
+					       struct device_node *np,
+					       struct macio_dev *in_bay,
 					       struct resource *parent_res)
 {
 	struct macio_dev *dev;
-	int i, j;
 	u32 *reg;
 	
 	if (np == NULL)
@@ -326,7 +401,8 @@
 
 	/* MacIO itself has a different reg, we use it's PCI base */
 	if (np == chip->of_node) {
-		sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s", chip->lbus.index,
+		sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s",
+			chip->lbus.index,
 #ifdef CONFIG_PCI
 			pci_resource_start(chip->lbus.pdev, 0),
 #else
@@ -335,57 +411,16 @@
 			MAX_NODE_NAME_SIZE, np->name);
 	} else {
 		reg = (u32 *)get_property(np, "reg", NULL);
-		sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", chip->lbus.index,
+		sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
+			chip->lbus.index,
 			reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
 	}
 
-	/* For now, we use pre-parsed entries in the device-tree for
-	 * interrupt routing and addresses, but we should change that
-	 * to dynamically parsed entries and so get rid of most of the
-	 * clutter in struct device_node
-	 */
-	for (i = j = 0; i < np->n_intrs; i++) {
-		struct resource *res = &dev->interrupt[j];
+	/* Setup interrupts & resources */
+	macio_setup_interrupts(dev);
+	macio_setup_resources(dev, parent_res);
 
-		if (j >= MACIO_DEV_COUNT_IRQS)
-			break;
-		res->start = np->intrs[i].line;
-		res->flags = IORESOURCE_IO;
-		if (np->intrs[j].sense)
-			res->flags |= IORESOURCE_IRQ_LOWLEVEL;
-		else
-			res->flags |= IORESOURCE_IRQ_HIGHEDGE;
-		res->name = dev->ofdev.dev.bus_id;
-		if (macio_resource_quirks(np, res, i))
-			memset(res, 0, sizeof(struct resource));
-		else
-			j++;
-	}
-	dev->n_interrupts = j;
-	for (i = j = 0; i < np->n_addrs; i++) {
-		struct resource *res = &dev->resource[j];
-		
-		if (j >= MACIO_DEV_COUNT_RESOURCES)
-			break;
-		res->start = np->addrs[i].address;
-		res->end = np->addrs[i].address + np->addrs[i].size - 1;
-		res->flags = IORESOURCE_MEM;
-		res->name = dev->ofdev.dev.bus_id;
-		if (macio_resource_quirks(np, res, i))
-			memset(res, 0, sizeof(struct resource));
-		else {
-			j++;
-			/* Currently, we consider failure as harmless, this may
-			 * change in the future, once I've found all the device
-			 * tree bugs in older machines & worked around them
-			 */
-			if (insert_resource(parent_res, res))
-       				printk(KERN_WARNING "Can't request resource %d for MacIO"
-				       " device %s\n", i, dev->ofdev.dev.bus_id);
-		}
-	}
-	dev->n_resources = j;
-
+	/* Register with core */
 	if (of_device_register(&dev->ofdev) != 0) {
 		printk(KERN_DEBUG"macio: device registration error for %s!\n",
 		       dev->ofdev.dev.bus_id);
@@ -442,36 +477,42 @@
 
 	/* First scan 1st level */
 	for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
-		if (!macio_skip_device(np)) {
-			of_node_get(np);
-			mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL, root_res);
-			if (mdev == NULL)
-				of_node_put(np);
-			else if (strncmp(np->name, "media-bay", 9) == 0)
-				mbdev = mdev;
-			else if (strncmp(np->name, "escc", 4) == 0)
-				sdev = mdev;
-		}
+		if (macio_skip_device(np))
+			continue;
+		of_node_get(np);
+		mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL,
+					    root_res);
+		if (mdev == NULL)
+			of_node_put(np);
+		else if (strncmp(np->name, "media-bay", 9) == 0)
+			mbdev = mdev;
+		else if (strncmp(np->name, "escc", 4) == 0)
+			sdev = mdev;
 	}
 
 	/* Add media bay devices if any */
 	if (mbdev)
-		for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np)) != NULL;)
-			if (!macio_skip_device(np)) {
-				of_node_get(np);
-				if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev,
-							 root_res) == NULL)
-					of_node_put(np);
-			}
+		for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np))
+			     != NULL;) {
+			if (macio_skip_device(np))
+				continue;
+			of_node_get(np);
+			if (macio_add_one_device(chip, &mbdev->ofdev.dev, np,
+						 mbdev,  root_res) == NULL)
+				of_node_put(np);
+		}
+
 	/* Add serial ports if any */
 	if (sdev) {
-		for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np)) != NULL;)
-			if (!macio_skip_device(np)) {
-				of_node_get(np);
-				if (macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL,
-							 root_res) == NULL)
-					of_node_put(np);
-			}
+		for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np))
+			     != NULL;) {
+			if (macio_skip_device(np))
+				continue;
+			of_node_get(np);
+			if (macio_add_one_device(chip, &sdev->ofdev.dev, np,
+						 NULL, root_res) == NULL)
+				of_node_put(np);
+		}
 	}
 }
 
@@ -519,7 +560,8 @@
  *	Returns 0 on success, or %EBUSY on error.  A warning
  *	message is also printed on failure.
  */
-int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name)
+int macio_request_resource(struct macio_dev *dev, int resource_no,
+			   const char *name)
 {
 	if (macio_resource_len(dev, resource_no) == 0)
 		return 0;
@@ -606,20 +648,20 @@
 	if (ent->vendor != PCI_VENDOR_ID_APPLE)
 		return -ENODEV;
 
-	/* Note regarding refcounting: We assume pci_device_to_OF_node() is ported
-	 * to new OF APIs and returns a node with refcount incremented. This isn't
-	 * the case today, but on the other hand ppc32 doesn't do refcounting. This
-	 * will have to be fixed when going to ppc64. --BenH.
+	/* Note regarding refcounting: We assume pci_device_to_OF_node() is
+	 * ported to new OF APIs and returns a node with refcount incremented.
 	 */
 	np = pci_device_to_OF_node(pdev);
 	if (np == NULL)
 		return -ENODEV;
 
-	/* This assumption is wrong, fix that here for now until I fix the arch */
+	/* The above assumption is wrong !!!
+	 * fix that here for now until I fix the arch code
+	 */
 	of_node_get(np);
 
-	/* We also assume that pmac_feature will have done a get() on nodes stored
-	 * in the macio chips array
+	/* We also assume that pmac_feature will have done a get() on nodes
+	 * stored in the macio chips array
 	 */
 	chip = macio_find(np, macio_unknown);
        	of_node_put(np);
@@ -639,9 +681,9 @@
 
 	/*
 	 * HACK ALERT: The WallStreet PowerBook and some OHare based machines
-	 * have 2 macio ASICs. I must probe the "main" one first or IDE ordering
-	 * will be incorrect. So I put on "hold" the second one since it seem to
-	 * appear first on PCI
+	 * have 2 macio ASICs. I must probe the "main" one first or IDE
+	 * ordering will be incorrect. So I put on "hold" the second one since
+	 * it seem to appear first on PCI
 	 */
 	if (chip->type == macio_gatwick || chip->type == macio_ohareII)
 		if (macio_chips[0].lbus.pdev == NULL) {
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index b856bb6..8dbf285 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -647,6 +647,7 @@
 	struct media_bay_info* bay;
 	u32 __iomem *regbase;
 	struct device_node *ofnode;
+	unsigned long base;
 	int i;
 
 	ofnode = mdev->ofdev.node;
@@ -656,10 +657,11 @@
 	if (macio_request_resources(mdev, "media-bay"))
 		return -EBUSY;
 	/* Media bay registers are located at the beginning of the
-         * mac-io chip, we get the parent address for now (hrm...)
+         * mac-io chip, for now, we trick and align down the first
+	 * resource passed in
          */
-	regbase = (u32 __iomem *)
-		ioremap(ofnode->parent->addrs[0].address, 0x100);
+	base = macio_resource_start(mdev, 0) & 0xffff0000u;
+	regbase = (u32 __iomem *)ioremap(base, 0x100);
 	if (regbase == NULL) {
 		macio_release_resources(mdev);
 		return -ENOMEM;
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index e837827..db2ae71 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -53,7 +53,7 @@
 #undef DEBUG_SMU
 
 #ifdef DEBUG_SMU
-#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0)
+#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0)
 #else
 #define DPRINTK(fmt, args...) do { } while (0)
 #endif
@@ -94,6 +94,8 @@
 static struct smu_device	*smu;
 static DECLARE_MUTEX(smu_part_access);
 
+static void smu_i2c_retry(unsigned long data);
+
 /*
  * SMU driver low level stuff
  */
@@ -469,7 +471,6 @@
 	smu->of_node = np;
 	smu->db_irq = NO_IRQ;
 	smu->msg_irq = NO_IRQ;
-	init_timer(&smu->i2c_timer);
 
 	/* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a
 	 * 32 bits value safely
@@ -544,6 +545,10 @@
 	if (!smu)
 		return 0;
 
+	init_timer(&smu->i2c_timer);
+	smu->i2c_timer.function = smu_i2c_retry;
+	smu->i2c_timer.data = (unsigned long)smu;
+
 	/*
 	 * Try to request the interrupts
 	 */
@@ -570,7 +575,10 @@
 
 	return 0;
 }
-arch_initcall(smu_late_init);
+/* This has to be before arch_initcall as the low i2c stuff relies on the
+ * above having been done before we reach arch_initcalls
+ */
+core_initcall(smu_late_init);
 
 /*
  * sysfs visibility
@@ -580,20 +588,10 @@
 {
 	struct device_node *np;
 
-	for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) {
-		if (device_is_compatible(np, "smu-i2c")) {
-			char name[32];
-			u32 *reg = (u32 *)get_property(np, "reg", NULL);
-
-			if (reg == NULL)
-				continue;
-			sprintf(name, "smu-i2c-%02x", *reg);
-			of_platform_device_create(np, name, &smu->of_dev->dev);
-		}
+	for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;)
 		if (device_is_compatible(np, "smu-sensors"))
-			of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev);
-	}
-
+			of_platform_device_create(np, "smu-sensors",
+						  &smu->of_dev->dev);
 }
 
 static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs, NULL);
@@ -712,13 +710,13 @@
 
 static void smu_i2c_retry(unsigned long data)
 {
-	struct smu_i2c_cmd	*cmd = (struct smu_i2c_cmd *)data;
+	struct smu_i2c_cmd	*cmd = smu->cmd_i2c_cur;
 
 	DPRINTK("SMU: i2c failure, requeuing...\n");
 
 	/* requeue command simply by resetting reply_len */
 	cmd->pdata[0] = 0xff;
-	cmd->scmd.reply_len = 0x10;
+	cmd->scmd.reply_len = sizeof(cmd->pdata);
 	smu_queue_cmd(&cmd->scmd);
 }
 
@@ -747,10 +745,8 @@
 	 */
 	if (fail && --cmd->retries > 0) {
 		DPRINTK("SMU: i2c failure, starting timer...\n");
-		smu->i2c_timer.function = smu_i2c_retry;
-		smu->i2c_timer.data = (unsigned long)cmd;
-		smu->i2c_timer.expires = jiffies + msecs_to_jiffies(5);
-		add_timer(&smu->i2c_timer);
+		BUG_ON(cmd != smu->cmd_i2c_cur);
+		mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5));
 		return;
 	}
 
@@ -764,7 +760,7 @@
 
 	/* Ok, initial command complete, now poll status */
 	scmd->reply_buf = cmd->pdata;
-	scmd->reply_len = 0x10;
+	scmd->reply_len = sizeof(cmd->pdata);
 	scmd->data_buf = cmd->pdata;
 	scmd->data_len = 1;
 	cmd->pdata[0] = 0;
@@ -786,7 +782,7 @@
 	cmd->scmd.done = smu_i2c_low_completion;
 	cmd->scmd.misc = cmd;
 	cmd->scmd.reply_buf = cmd->pdata;
-	cmd->scmd.reply_len = 0x10;
+	cmd->scmd.reply_len = sizeof(cmd->pdata);
 	cmd->scmd.data_buf = (u8 *)(char *)&cmd->info;
 	cmd->scmd.status = 1;
 	cmd->stage = 0;
@@ -909,10 +905,13 @@
 	struct property *prop;
 
 	/* First query the partition info */
+	DPRINTK("SMU: Query partition infos ... (irq=%d)\n", smu->db_irq);
 	smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
 			 smu_done_complete, &comp,
 			 SMU_CMD_PARTITION_LATEST, id);
 	wait_for_completion(&comp);
+	DPRINTK("SMU: done, status: %d, reply_len: %d\n",
+		cmd.cmd.status, cmd.cmd.reply_len);
 
 	/* Partition doesn't exist (or other error) */
 	if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
@@ -975,6 +974,8 @@
 
 	sprintf(pname, "sdb-partition-%02x", id);
 
+	DPRINTK("smu_get_sdb_partition(%02x)\n", id);
+
 	if (interruptible) {
 		int rc;
 		rc = down_interruptible(&smu_part_access);
@@ -986,6 +987,7 @@
 	part = (struct smu_sdbp_header *)get_property(smu->of_node,
 						      pname, size);
 	if (part == NULL) {
+		DPRINTK("trying to extract from SMU ...\n");
 		part = smu_create_sdb_partition(id);
 		if (part != NULL && size)
 			*size = part->len << 2;
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index d843a6c..2d9d791 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -127,39 +127,34 @@
 #endif /* CONFIG_ADB */
 
 #ifdef CONFIG_PPC
-int __init
-find_via_cuda(void)
+int __init find_via_cuda(void)
 {
-    int err;
     struct adb_request req;
+    phys_addr_t taddr;
+    u32 *reg;
+    int err;
 
     if (vias != 0)
 	return 1;
-    vias = find_devices("via-cuda");
+    vias = of_find_node_by_name(NULL, "via-cuda");
     if (vias == 0)
 	return 0;
-    if (vias->next != 0)
-	printk(KERN_WARNING "Warning: only using 1st via-cuda\n");
 
-#if 0
-    { int i;
-
-    printk("find_via_cuda: node = %p, addrs =", vias->node);
-    for (i = 0; i < vias->n_addrs; ++i)
-	printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
-    printk(", intrs =");
-    for (i = 0; i < vias->n_intrs; ++i)
-	printk(" %x", vias->intrs[i].line);
-    printk("\n"); }
-#endif
-
-    if (vias->n_addrs != 1 || vias->n_intrs != 1) {
-	printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n",
-	       vias->n_addrs, vias->n_intrs);
-	if (vias->n_addrs < 1 || vias->n_intrs < 1)
-	    return 0;
+    reg = (u32 *)get_property(vias, "reg", NULL);
+    if (reg == NULL) {
+	    printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
+	    goto fail;
     }
-    via = ioremap(vias->addrs->address, 0x2000);
+    taddr = of_translate_address(vias, reg);
+    if (taddr == 0) {
+	    printk(KERN_ERR "via-cuda: Can't translate address !\n");
+	    goto fail;
+    }
+    via = ioremap(taddr, 0x2000);
+    if (via == NULL) {
+	    printk(KERN_ERR "via-cuda: Can't map address !\n");
+	    goto fail;
+    }
 
     cuda_state = idle;
     sys_ctrler = SYS_CTRLER_CUDA;
@@ -185,6 +180,11 @@
 	cuda_poll();
 
     return 1;
+
+ fail:
+    of_node_put(vias);
+    vias = NULL;
+    return 0;
 }
 #endif /* CONFIG_PPC */
 
@@ -193,10 +193,6 @@
     if (via == NULL)
 	return -ENODEV;
 
-#ifdef CONFIG_PPC
-    request_OF_resource(vias, 0, NULL);
-#endif
-
     if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
 	printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
 	return -EAGAIN;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 5640435..6eb93e4 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -55,6 +55,8 @@
 #include <asm/sections.h>
 #include <asm/irq.h>
 #include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+#include <asm/pmac_low_i2c.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/cputable.h>
@@ -147,6 +149,7 @@
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
 static int pmu_has_adb;
+static struct device_node *gpio_node;
 static unsigned char __iomem *gpio_reg = NULL;
 static int gpio_irq = -1;
 static int gpio_irq_enabled = -1;
@@ -157,8 +160,8 @@
 static int drop_interrupts;
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 static int option_lid_wakeup = 1;
-static int sleep_in_progress;
 #endif /* CONFIG_PM && CONFIG_PPC32 */
+static int sleep_in_progress;
 static unsigned long async_req_locks;
 static unsigned int pmu_irq_stats[11];
 
@@ -196,7 +199,6 @@
 #endif /* CONFIG_ADB */
 
 static int init_pmu(void);
-static int pmu_queue_request(struct adb_request *req);
 static void pmu_start(void);
 static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
 static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
@@ -295,22 +297,26 @@
 };
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
-int
-find_via_pmu(void)
+int __init find_via_pmu(void)
 {
+	u64 taddr;
+	u32 *reg;
+
 	if (via != 0)
 		return 1;
-	vias = find_devices("via-pmu");
-	if (vias == 0)
+	vias = of_find_node_by_name(NULL, "via-pmu");
+	if (vias == NULL)
 		return 0;
-	if (vias->next != 0)
-		printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
 
-	if (vias->n_addrs < 1 || vias->n_intrs < 1) {
-		printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
-		       vias->n_addrs, vias->n_intrs);
-		if (vias->n_addrs < 1 || vias->n_intrs < 1)
-			return 0;
+	reg = (u32 *)get_property(vias, "reg", NULL);
+	if (reg == NULL) {
+		printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
+		goto fail;
+	}
+	taddr = of_translate_address(vias, reg);
+	if (taddr == OF_BAD_ADDR) {
+		printk(KERN_ERR "via-pmu: Can't translate address !\n");
+		goto fail;
 	}
 
 	spin_lock_init(&pmu_lock);
@@ -331,7 +337,8 @@
 		pmu_kind = PMU_HEATHROW_BASED;
 	else if (device_is_compatible(vias->parent, "Keylargo")
 		 || device_is_compatible(vias->parent, "K2-Keylargo")) {
-		struct device_node *gpio, *gpiop;
+		struct device_node *gpiop;
+		u64 gaddr = OF_BAD_ADDR;
 
 		pmu_kind = PMU_KEYLARGO_BASED;
 		pmu_has_adb = (find_type_devices("adb") != NULL);
@@ -341,19 +348,24 @@
 				PMU_INT_TICK |
 				PMU_INT_ENVIRONMENT;
 		
-		gpiop = find_devices("gpio");
-		if (gpiop && gpiop->n_addrs) {
-			gpio_reg = ioremap(gpiop->addrs->address, 0x10);
-			gpio = find_devices("extint-gpio1");
-			if (gpio == NULL)
-				gpio = find_devices("pmu-interrupt");
-			if (gpio && gpio->parent == gpiop && gpio->n_intrs)
-				gpio_irq = gpio->intrs[0].line;
+		gpiop = of_find_node_by_name(NULL, "gpio");
+		if (gpiop) {
+			reg = (u32 *)get_property(gpiop, "reg", NULL);
+			if (reg)
+				gaddr = of_translate_address(gpiop, reg);
+			if (gaddr != OF_BAD_ADDR)
+				gpio_reg = ioremap(gaddr, 0x10);
 		}
+		if (gpio_reg == NULL)
+			printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n");
 	} else
 		pmu_kind = PMU_UNKNOWN;
 
-	via = ioremap(vias->addrs->address, 0x2000);
+	via = ioremap(taddr, 0x2000);
+	if (via == NULL) {
+		printk(KERN_ERR "via-pmu: Can't map address !\n");
+		goto fail;
+	}
 	
 	out_8(&via[IER], IER_CLR | 0x7f);	/* disable all intrs */
 	out_8(&via[IFR], 0x7f);			/* clear IFR */
@@ -365,23 +377,25 @@
 		return 0;
 	}
 
-	printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n",
+	printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
 	       PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
 	       
 	sys_ctrler = SYS_CTRLER_PMU;
 	
 	return 1;
+ fail:
+	of_node_put(vias);
+	vias = NULL;
+	return 0;
 }
 
 #ifdef CONFIG_ADB
-static int
-pmu_probe(void)
+static int pmu_probe(void)
 {
 	return vias == NULL? -ENODEV: 0;
 }
 
-static int __init
-pmu_init(void)
+static int __init pmu_init(void)
 {
 	if (vias == NULL)
 		return -ENODEV;
@@ -405,7 +419,7 @@
 	bright_req_2.complete = 1;
 	batt_req.complete = 1;
 
-#if defined(CONFIG_PPC32) && !defined(CONFIG_PPC_MERGE)
+#ifndef CONFIG_PPC_MERGE
 	if (pmu_kind == PMU_KEYLARGO_BASED)
 		openpic_set_irq_priority(vias->intrs[0].line,
 					 OPENPIC_PRIORITY_DEFAULT + 1);
@@ -418,10 +432,22 @@
 		return -EAGAIN;
 	}
 
-	if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {
-		if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1 ADB", (void *)0))
-			printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);
-		gpio_irq_enabled = 1;
+	if (pmu_kind == PMU_KEYLARGO_BASED) {
+		gpio_node = of_find_node_by_name(NULL, "extint-gpio1");
+		if (gpio_node == NULL)
+			gpio_node = of_find_node_by_name(NULL,
+							 "pmu-interrupt");
+		if (gpio_node && gpio_node->n_intrs > 0)
+			gpio_irq = gpio_node->intrs[0].line;
+
+		if (gpio_irq != -1) {
+			if (request_irq(gpio_irq, gpio1_interrupt, 0,
+					"GPIO1 ADB", (void *)0))
+				printk(KERN_ERR "pmu: can't get irq %d"
+				       " (GPIO1)\n", gpio_irq);
+			else
+				gpio_irq_enabled = 1;
+		}
 	}
 
 	/* Enable interrupts */
@@ -454,9 +480,6 @@
 	if (vias == NULL)
 		return -ENODEV;
 
-#ifndef CONFIG_PPC64
-	request_OF_resource(vias, 0, NULL);
-#endif
 #ifdef CONFIG_PMAC_BACKLIGHT
 	/* Enable backlight */
 	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
@@ -1371,7 +1394,6 @@
 			}
 			pmu_done(req);
 		} else {
-#if defined(CONFIG_XMON) && !defined(CONFIG_PPC64)
 			if (len == 4 && data[1] == 0x2c) {
 				extern int xmon_wants_key, xmon_adb_keycode;
 				if (xmon_wants_key) {
@@ -1379,7 +1401,6 @@
 					return;
 				}
 			}
-#endif /* defined(CONFIG_XMON) && !defined(CONFIG_PPC64) */
 #ifdef CONFIG_ADB
 			/*
 			 * XXX On the [23]400 the PMU gives us an up
@@ -1782,258 +1803,6 @@
 	return via != 0;
 }
 
-struct pmu_i2c_hdr {
-	u8	bus;
-	u8	mode;
-	u8	bus2;
-	u8	address;
-	u8	sub_addr;
-	u8	comb_addr;
-	u8	count;
-};
-
-int
-pmu_i2c_combined_read(int bus, int addr, int subaddr,  u8* data, int len)
-{
-	struct adb_request	req;
-	struct pmu_i2c_hdr	*hdr = (struct pmu_i2c_hdr *)&req.data[1];
-	int retry;
-	int rc;
-
-	for (retry=0; retry<16; retry++) {
-		memset(&req, 0, sizeof(req));
-
-		hdr->bus = bus;
-		hdr->address = addr & 0xfe;
-		hdr->mode = PMU_I2C_MODE_COMBINED;
-		hdr->bus2 = 0;
-		hdr->sub_addr = subaddr;
-		hdr->comb_addr = addr | 1;
-		hdr->count = len;
-		
-		req.nbytes = sizeof(struct pmu_i2c_hdr) + 1;
-		req.reply_expected = 0;
-		req.reply_len = 0;
-		req.data[0] = PMU_I2C_CMD;
-		req.reply[0] = 0xff;
-		rc = pmu_queue_request(&req);
-		if (rc)
-			return rc;
-		while(!req.complete)
-			pmu_poll();
-		if (req.reply[0] == PMU_I2C_STATUS_OK)
-			break;
-		mdelay(15);
-	}
-	if (req.reply[0] != PMU_I2C_STATUS_OK)
-		return -1;
-
-	for (retry=0; retry<16; retry++) {
-		memset(&req, 0, sizeof(req));
-
-		mdelay(15);
-
-		hdr->bus = PMU_I2C_BUS_STATUS;
-		req.reply[0] = 0xff;
-		
-		req.nbytes = 2;
-		req.reply_expected = 0;
-		req.reply_len = 0;
-		req.data[0] = PMU_I2C_CMD;
-		rc = pmu_queue_request(&req);
-		if (rc)
-			return rc;
-		while(!req.complete)
-			pmu_poll();
-		if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) {
-			memcpy(data, &req.reply[1], req.reply_len - 1);
-			return req.reply_len - 1;
-		}
-	}
-	return -1;
-}
-
-int
-pmu_i2c_stdsub_write(int bus, int addr, int subaddr,  u8* data, int len)
-{
-	struct adb_request	req;
-	struct pmu_i2c_hdr	*hdr = (struct pmu_i2c_hdr *)&req.data[1];
-	int retry;
-	int rc;
-
-	for (retry=0; retry<16; retry++) {
-		memset(&req, 0, sizeof(req));
-
-		hdr->bus = bus;
-		hdr->address = addr & 0xfe;
-		hdr->mode = PMU_I2C_MODE_STDSUB;
-		hdr->bus2 = 0;
-		hdr->sub_addr = subaddr;
-		hdr->comb_addr = addr & 0xfe;
-		hdr->count = len;
-
-		req.data[0] = PMU_I2C_CMD;
-		memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len);
-		req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1;
-		req.reply_expected = 0;
-		req.reply_len = 0;
-		req.reply[0] = 0xff;
-		rc = pmu_queue_request(&req);
-		if (rc)
-			return rc;
-		while(!req.complete)
-			pmu_poll();
-		if (req.reply[0] == PMU_I2C_STATUS_OK)
-			break;
-		mdelay(15);
-	}
-	if (req.reply[0] != PMU_I2C_STATUS_OK)
-		return -1;
-
-	for (retry=0; retry<16; retry++) {
-		memset(&req, 0, sizeof(req));
-
-		mdelay(15);
-
-		hdr->bus = PMU_I2C_BUS_STATUS;
-		req.reply[0] = 0xff;
-		
-		req.nbytes = 2;
-		req.reply_expected = 0;
-		req.reply_len = 0;
-		req.data[0] = PMU_I2C_CMD;
-		rc = pmu_queue_request(&req);
-		if (rc)
-			return rc;
-		while(!req.complete)
-			pmu_poll();
-		if (req.reply[0] == PMU_I2C_STATUS_OK)
-			return len;
-	}
-	return -1;
-}
-
-int
-pmu_i2c_simple_read(int bus, int addr,  u8* data, int len)
-{
-	struct adb_request	req;
-	struct pmu_i2c_hdr	*hdr = (struct pmu_i2c_hdr *)&req.data[1];
-	int retry;
-	int rc;
-
-	for (retry=0; retry<16; retry++) {
-		memset(&req, 0, sizeof(req));
-
-		hdr->bus = bus;
-		hdr->address = addr | 1;
-		hdr->mode = PMU_I2C_MODE_SIMPLE;
-		hdr->bus2 = 0;
-		hdr->sub_addr = 0;
-		hdr->comb_addr = 0;
-		hdr->count = len;
-
-		req.data[0] = PMU_I2C_CMD;
-		req.nbytes = sizeof(struct pmu_i2c_hdr) + 1;
-		req.reply_expected = 0;
-		req.reply_len = 0;
-		req.reply[0] = 0xff;
-		rc = pmu_queue_request(&req);
-		if (rc)
-			return rc;
-		while(!req.complete)
-			pmu_poll();
-		if (req.reply[0] == PMU_I2C_STATUS_OK)
-			break;
-		mdelay(15);
-	}
-	if (req.reply[0] != PMU_I2C_STATUS_OK)
-		return -1;
-
-	for (retry=0; retry<16; retry++) {
-		memset(&req, 0, sizeof(req));
-
-		mdelay(15);
-
-		hdr->bus = PMU_I2C_BUS_STATUS;
-		req.reply[0] = 0xff;
-		
-		req.nbytes = 2;
-		req.reply_expected = 0;
-		req.reply_len = 0;
-		req.data[0] = PMU_I2C_CMD;
-		rc = pmu_queue_request(&req);
-		if (rc)
-			return rc;
-		while(!req.complete)
-			pmu_poll();
-		if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) {
-			memcpy(data, &req.reply[1], req.reply_len - 1);
-			return req.reply_len - 1;
-		}
-	}
-	return -1;
-}
-
-int
-pmu_i2c_simple_write(int bus, int addr,  u8* data, int len)
-{
-	struct adb_request	req;
-	struct pmu_i2c_hdr	*hdr = (struct pmu_i2c_hdr *)&req.data[1];
-	int retry;
-	int rc;
-
-	for (retry=0; retry<16; retry++) {
-		memset(&req, 0, sizeof(req));
-
-		hdr->bus = bus;
-		hdr->address = addr & 0xfe;
-		hdr->mode = PMU_I2C_MODE_SIMPLE;
-		hdr->bus2 = 0;
-		hdr->sub_addr = 0;
-		hdr->comb_addr = 0;
-		hdr->count = len;
-
-		req.data[0] = PMU_I2C_CMD;
-		memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len);
-		req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1;
-		req.reply_expected = 0;
-		req.reply_len = 0;
-		req.reply[0] = 0xff;
-		rc = pmu_queue_request(&req);
-		if (rc)
-			return rc;
-		while(!req.complete)
-			pmu_poll();
-		if (req.reply[0] == PMU_I2C_STATUS_OK)
-			break;
-		mdelay(15);
-	}
-	if (req.reply[0] != PMU_I2C_STATUS_OK)
-		return -1;
-
-	for (retry=0; retry<16; retry++) {
-		memset(&req, 0, sizeof(req));
-
-		mdelay(15);
-
-		hdr->bus = PMU_I2C_BUS_STATUS;
-		req.reply[0] = 0xff;
-		
-		req.nbytes = 2;
-		req.reply_expected = 0;
-		req.reply_len = 0;
-		req.data[0] = PMU_I2C_CMD;
-		rc = pmu_queue_request(&req);
-		if (rc)
-			return rc;
-		while(!req.complete)
-			pmu_poll();
-		if (req.reply[0] == PMU_I2C_STATUS_OK)
-			return len;
-	}
-	return -1;
-}
-
 #ifdef CONFIG_PM
 
 static LIST_HEAD(sleep_notifiers);
@@ -2338,8 +2107,9 @@
 		return -EBUSY;
 	}
 
-	/* Disable clock spreading on some machines */
-	pmac_tweak_clock_spreading(0);
+	/* Call platform functions marked "on sleep" */
+	pmac_pfunc_i2c_suspend();
+	pmac_pfunc_base_suspend();
 
 	/* Stop preemption */
 	preempt_disable();
@@ -2411,8 +2181,9 @@
 	mdelay(10);
 	preempt_enable();
 
-	/* Re-enable clock spreading on some machines */
-	pmac_tweak_clock_spreading(1);
+	/* Call platform functions marked "on wake" */
+	pmac_pfunc_base_resume();
+	pmac_pfunc_i2c_resume();
 
 	/* Resume devices */
 	device_resume();
@@ -3130,16 +2901,13 @@
 subsys_initcall(init_pmu_sysfs);
 
 EXPORT_SYMBOL(pmu_request);
+EXPORT_SYMBOL(pmu_queue_request);
 EXPORT_SYMBOL(pmu_poll);
 EXPORT_SYMBOL(pmu_poll_adb);
 EXPORT_SYMBOL(pmu_wait_complete);
 EXPORT_SYMBOL(pmu_suspend);
 EXPORT_SYMBOL(pmu_resume);
 EXPORT_SYMBOL(pmu_unlock);
-EXPORT_SYMBOL(pmu_i2c_combined_read);
-EXPORT_SYMBOL(pmu_i2c_stdsub_write);
-EXPORT_SYMBOL(pmu_i2c_simple_read);
-EXPORT_SYMBOL(pmu_i2c_simple_write);
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 EXPORT_SYMBOL(pmu_enable_irled);
 EXPORT_SYMBOL(pmu_battery_count);
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 57460e4..906d3ec 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -21,6 +21,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/sections.h>
+#include <asm/pmac_low_i2c.h>
 
 #include "windfarm.h"
 
@@ -157,53 +158,21 @@
 
 static int wf_lm75_attach(struct i2c_adapter *adapter)
 {
-	u8 bus_id;
-	struct device_node *smu, *bus, *dev;
-
-	/* We currently only deal with LM75's hanging off the SMU
-	 * i2c busses. If we extend that driver to other/older
-	 * machines, we should split this function into SMU-i2c,
-	 * keywest-i2c, PMU-i2c, ...
-	 */
+	struct device_node *busnode, *dev;
+	struct pmac_i2c_bus *bus;
 
 	DBG("wf_lm75: adapter %s detected\n", adapter->name);
 
-	if (strncmp(adapter->name, "smu-i2c-", 8) != 0)
-		return 0;
-	smu = of_find_node_by_type(NULL, "smu");
-	if (smu == NULL)
-		return 0;
-
-	/* Look for the bus in the device-tree */
-	bus_id = (u8)simple_strtoul(adapter->name + 8, NULL, 16);
-
-	DBG("wf_lm75: bus ID is %x\n", bus_id);
-
-	/* Look for sensors subdir */
-	for (bus = NULL;
-	     (bus = of_get_next_child(smu, bus)) != NULL;) {
-		u32 *reg;
-
-		if (strcmp(bus->name, "i2c"))
-			continue;
-		reg = (u32 *)get_property(bus, "reg", NULL);
-		if (reg == NULL)
-			continue;
-		if (bus_id == *reg)
-			break;
-	}
-	of_node_put(smu);
-	if (bus == NULL) {
-		printk(KERN_WARNING "windfarm: SMU i2c bus 0x%x not found"
-		       " in device-tree !\n", bus_id);
-		return 0;
-	}
+	bus = pmac_i2c_adapter_to_bus(adapter);
+	if (bus == NULL)
+		return -ENODEV;
+	busnode = pmac_i2c_get_bus_node(bus);
 
 	DBG("wf_lm75: bus found, looking for device...\n");
 
 	/* Now look for lm75(s) in there */
 	for (dev = NULL;
-	     (dev = of_get_next_child(bus, dev)) != NULL;) {
+	     (dev = of_get_next_child(busnode, dev)) != NULL;) {
 		const char *loc =
 			get_property(dev, "hwsensor-location", NULL);
 		u32 *reg = (u32 *)get_property(dev, "reg", NULL);
@@ -217,9 +186,6 @@
 		else if (device_is_compatible(dev, "ds1775"))
 			wf_lm75_create(adapter, *reg, 1, loc);
 	}
-
-	of_node_put(bus);
-
 	return 0;
 }
 
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 8d67228..ec4e641 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -501,7 +501,8 @@
 	case ID_VP310:
 	// For now we will do this only for the VP310.
 	// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
-		if ((ret = mt312_readreg(state, CONFIG, &config_val) < 0))
+		ret = mt312_readreg(state, CONFIG, &config_val);
+		if (ret < 0)
 			return ret;
 		if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
 		{
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 5c5eebd..dcc98af 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -148,14 +148,6 @@
     return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: el2_close() handles free_irq */
-	release_region(dev->base_addr, EL2_IO_EXTENT);
-	if (ei_status.mem)
-		iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init el2_probe(int unit)
 {
@@ -726,6 +718,14 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	/* NB: el2_close() handles free_irq */
+	release_region(dev->base_addr, EL2_IO_EXTENT);
+	if (ei_status.mem)
+		iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1960961..733bc25 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -129,7 +129,7 @@
 
 	  If you don't have this card, of course say N.
 
-	source "drivers/net/arcnet/Kconfig"
+source "drivers/net/arcnet/Kconfig"
 
 source "drivers/net/phy/Kconfig"
 
@@ -844,7 +844,7 @@
 
 config DM9000
 	tristate "DM9000 support"
-	depends on ARM && NET_ETHERNET
+	depends on (ARM || MIPS) && NET_ETHERNET
 	select CRC32
 	select MII
 	---help---
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 8a0af54..7952dc6 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -123,14 +123,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	/* Someday free_irq may be in ac_close_card() */
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, AC_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init ac3200_probe(int unit)
 {
@@ -406,6 +398,14 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	/* Someday free_irq may be in ac_close_card() */
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, AC_IO_EXTENT);
+	iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 015c7f1..f20bb85 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -205,7 +205,7 @@
  *
  * Caller must hold bond lock for read
  */
-extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev)
+static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev)
 {
 	struct slave *slave = NULL;
 	int i;
@@ -219,7 +219,7 @@
 	return slave;
 }
 
-extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
+static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
 {
 	if (!slave || !slave->dev->master) {
 		return NULL;
@@ -228,13 +228,13 @@
 	return (struct bonding *)slave->dev->master->priv;
 }
 
-extern inline void bond_set_slave_inactive_flags(struct slave *slave)
+static inline void bond_set_slave_inactive_flags(struct slave *slave)
 {
 	slave->state = BOND_STATE_BACKUP;
 	slave->dev->flags |= IFF_NOARP;
 }
 
-extern inline void bond_set_slave_active_flags(struct slave *slave)
+static inline void bond_set_slave_active_flags(struct slave *slave)
 {
 	slave->state = BOND_STATE_ACTIVE;
 	slave->dev->flags &= ~IFF_NOARP;
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index 38695d5..ccbbe5a 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -545,7 +545,7 @@
 static void __devinit
 e1000_check_copper_options(struct e1000_adapter *adapter)
 {
-	int speed, dplx;
+	int speed, dplx, an;
 	int bd = adapter->bd_number;
 
 	{ /* Speed */
@@ -641,8 +641,12 @@
 					 .p = an_list }}
 		};
 
-		int an = AutoNeg[bd];
-		e1000_validate_option(&an, &opt, adapter);
+		if (num_AutoNeg > bd) {
+			an = AutoNeg[bd];
+			e1000_validate_option(&an, &opt, adapter);
+		} else {
+			an = opt.def;
+		}
 		adapter->hw.autoneg_advertised = an;
 	}
 
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index f5a4dd7..e5c5cd2 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -140,13 +140,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: e21_close() handles free_irq */
-	iounmap(ei_status.mem);
-	release_region(dev->base_addr, E21_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init e2100_probe(int unit)
 {
@@ -463,6 +456,13 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	/* NB: e21_close() handles free_irq */
+	iounmap(ei_status.mem);
+	release_region(dev->base_addr, E21_IO_EXTENT);
+}
+
 void
 cleanup_module(void)
 {
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 50f8e23..6b0ab1e 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -155,13 +155,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, ES_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init es_probe(int unit)
 {
@@ -456,6 +449,13 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, ES_IO_EXTENT);
+	iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index c39344a..3682ec6 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -101,6 +101,7 @@
  *	0.46: 20 Oct 2005: Add irq optimization modes.
  *	0.47: 26 Oct 2005: Add phyaddr 0 in phy scan.
  *	0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single
+ *	0.49: 10 Dec 2005: Fix tso for large buffers.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -112,7 +113,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION		"0.48"
+#define FORCEDETH_VERSION		"0.49"
 #define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
@@ -349,6 +350,8 @@
 #define NV_TX2_VALID		(1<<31)
 #define NV_TX2_TSO		(1<<28)
 #define NV_TX2_TSO_SHIFT	14
+#define NV_TX2_TSO_MAX_SHIFT	14
+#define NV_TX2_TSO_MAX_SIZE	(1<<NV_TX2_TSO_MAX_SHIFT)
 #define NV_TX2_CHECKSUM_L3	(1<<27)
 #define NV_TX2_CHECKSUM_L4	(1<<26)
 
@@ -408,15 +411,15 @@
 #define NV_WATCHDOG_TIMEO	(5*HZ)
 
 #define RX_RING		128
-#define TX_RING		64
+#define TX_RING		256
 /* 
  * If your nic mysteriously hangs then try to reduce the limits
  * to 1/0: It might be required to set NV_TX_LASTPACKET in the
  * last valid ring entry. But this would be impossible to
  * implement - probably a disassembly error.
  */
-#define TX_LIMIT_STOP	63
-#define TX_LIMIT_START	62
+#define TX_LIMIT_STOP	255
+#define TX_LIMIT_START	254
 
 /* rx/tx mac addr + type + vlan + align + slack*/
 #define NV_RX_HEADERS		(64)
@@ -535,6 +538,7 @@
 	unsigned int next_tx, nic_tx;
 	struct sk_buff *tx_skbuff[TX_RING];
 	dma_addr_t tx_dma[TX_RING];
+	unsigned int tx_dma_len[TX_RING];
 	u32 tx_flags;
 };
 
@@ -935,6 +939,7 @@
 	        else
 			np->tx_ring.ex[i].FlagLen = 0;
 		np->tx_skbuff[i] = NULL;
+		np->tx_dma[i] = 0;
 	}
 }
 
@@ -945,30 +950,27 @@
 	return nv_alloc_rx(dev);
 }
 
-static void nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
 {
 	struct fe_priv *np = netdev_priv(dev);
-	struct sk_buff *skb = np->tx_skbuff[skbnr];
-	unsigned int j, entry, fragments;
-			
-	dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n",
-		dev->name, skbnr, np->tx_skbuff[skbnr]);
-	
-	entry = skbnr;
-	if ((fragments = skb_shinfo(skb)->nr_frags) != 0) {
-		for (j = fragments; j >= 1; j--) {
-			skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1];
-			pci_unmap_page(np->pci_dev, np->tx_dma[entry],
-				       frag->size,
-				       PCI_DMA_TODEVICE);
-			entry = (entry - 1) % TX_RING;
-		}
+
+	dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
+		dev->name, skbnr);
+
+	if (np->tx_dma[skbnr]) {
+		pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
+			       np->tx_dma_len[skbnr],
+			       PCI_DMA_TODEVICE);
+		np->tx_dma[skbnr] = 0;
 	}
-	pci_unmap_single(np->pci_dev, np->tx_dma[entry],
-			 skb->len - skb->data_len,
-			 PCI_DMA_TODEVICE);
-	dev_kfree_skb_irq(skb);
-	np->tx_skbuff[skbnr] = NULL;
+
+	if (np->tx_skbuff[skbnr]) {
+		dev_kfree_skb_irq(np->tx_skbuff[skbnr]);
+		np->tx_skbuff[skbnr] = NULL;
+		return 1;
+	} else {
+		return 0;
+	}
 }
 
 static void nv_drain_tx(struct net_device *dev)
@@ -981,10 +983,8 @@
 			np->tx_ring.orig[i].FlagLen = 0;
 		else
 			np->tx_ring.ex[i].FlagLen = 0;
-		if (np->tx_skbuff[i]) {
-			nv_release_txskb(dev, i);
+		if (nv_release_txskb(dev, i))
 			np->stats.tx_dropped++;
-		}
 	}
 }
 
@@ -1021,68 +1021,105 @@
 static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct fe_priv *np = netdev_priv(dev);
+	u32 tx_flags = 0;
 	u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
 	unsigned int fragments = skb_shinfo(skb)->nr_frags;
-	unsigned int nr = (np->next_tx + fragments) % TX_RING;
+	unsigned int nr = (np->next_tx - 1) % TX_RING;
+	unsigned int start_nr = np->next_tx % TX_RING;
 	unsigned int i;
+	u32 offset = 0;
+	u32 bcnt;
+	u32 size = skb->len-skb->data_len;
+	u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+
+	/* add fragments to entries count */
+	for (i = 0; i < fragments; i++) {
+		entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+			   ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+	}
 
 	spin_lock_irq(&np->lock);
 
-	if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) {
+	if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) {
 		spin_unlock_irq(&np->lock);
 		netif_stop_queue(dev);
 		return NETDEV_TX_BUSY;
 	}
 
-	np->tx_skbuff[nr] = skb;
-	
-	if (fragments) {
-		dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments);
-		/* setup descriptors in reverse order */
-		for (i = fragments; i >= 1; i--) {
-			skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
-			np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size,
-							PCI_DMA_TODEVICE);
+	/* setup the header buffer */
+	do {
+		bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+		nr = (nr + 1) % TX_RING;
+
+		np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+						PCI_DMA_TODEVICE);
+		np->tx_dma_len[nr] = bcnt;
+
+		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+			np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+			np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+		} else {
+			np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+			np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+			np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+		}
+		tx_flags = np->tx_flags;
+		offset += bcnt;
+		size -= bcnt;
+	} while(size);
+
+	/* setup the fragments */
+	for (i = 0; i < fragments; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+		u32 size = frag->size;
+		offset = 0;
+
+		do {
+			bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+			nr = (nr + 1) % TX_RING;
+
+			np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+						      PCI_DMA_TODEVICE);
+			np->tx_dma_len[nr] = bcnt;
 
 			if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 				np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-				np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+				np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
 			} else {
 				np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
 				np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-				np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+				np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
 			}
-			
-			nr = (nr - 1) % TX_RING;
-
-			if (np->desc_ver == DESC_VER_1)
-				tx_flags_extra &= ~NV_TX_LASTPACKET;
-			else
-				tx_flags_extra &= ~NV_TX2_LASTPACKET;		
-		}
+			offset += bcnt;
+			size -= bcnt;
+		} while (size);
 	}
 
+	/* set last fragment flag  */
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+		np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+	} else {
+		np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+	}
+
+	np->tx_skbuff[nr] = skb;
+
 #ifdef NETIF_F_TSO
 	if (skb_shinfo(skb)->tso_size)
-		tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
 	else
 #endif
-	tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+	tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
 
-	np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len,
-					PCI_DMA_TODEVICE);
-	
+	/* set tx flags */
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-		np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+		np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
 	} else {
-		np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-		np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-		np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+		np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
 	}	
 
-	dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n",
-				dev->name, np->next_tx, tx_flags_extra);
+	dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
+		dev->name, np->next_tx, entries, tx_flags_extra);
 	{
 		int j;
 		for (j=0; j<64; j++) {
@@ -1093,7 +1130,7 @@
 		dprintk("\n");
 	}
 
-	np->next_tx += 1 + fragments;
+	np->next_tx += entries;
 
 	dev->trans_start = jiffies;
 	spin_unlock_irq(&np->lock);
@@ -1140,7 +1177,6 @@
 					np->stats.tx_packets++;
 					np->stats.tx_bytes += skb->len;
 				}
-				nv_release_txskb(dev, i);
 			}
 		} else {
 			if (Flags & NV_TX2_LASTPACKET) {
@@ -1156,9 +1192,9 @@
 					np->stats.tx_packets++;
 					np->stats.tx_bytes += skb->len;
 				}				
-				nv_release_txskb(dev, i);
 			}
 		}
+		nv_release_txskb(dev, i);
 		np->nic_tx++;
 	}
 	if (np->next_tx - np->nic_tx < TX_LIMIT_START)
@@ -2456,7 +2492,7 @@
 		np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
 		dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
 #ifdef NETIF_F_TSO
-		/* disabled dev->features |= NETIF_F_TSO; */
+		dev->features |= NETIF_F_TSO;
 #endif
  	}
 
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 94a91da..cb9d66ac 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -718,14 +718,14 @@
 	uint32_t msg_enable;
 };
 
-extern inline u32 gfar_read(volatile unsigned *addr)
+static inline u32 gfar_read(volatile unsigned *addr)
 {
 	u32 val;
 	val = in_be32(addr);
 	return val;
 }
 
-extern inline void gfar_write(volatile unsigned *addr, u32 val)
+static inline void gfar_write(volatile unsigned *addr, u32 val)
 {
 	out_be32(addr, val);
 }
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 0abf5dd..74e167e 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -138,12 +138,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: hpp_close() handles free_irq */
-	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init hp_plus_probe(int unit)
 {
@@ -473,6 +467,12 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	/* NB: hpp_close() handles free_irq */
+	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
+}
+
 void
 cleanup_module(void)
 {
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 59cf841..cf9fb36 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -102,12 +102,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init hp_probe(int unit)
 {
@@ -444,6 +438,12 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
+}
+
 void
 cleanup_module(void)
 {
diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h
index 644edbf..c2dae60 100644
--- a/drivers/net/ibm_emac/ibm_emac.h
+++ b/drivers/net/ibm_emac/ibm_emac.h
@@ -110,6 +110,7 @@
 #define EMAC_MR1_TFS_2K			0x00080000
 #define EMAC_MR1_TR0_MULT		0x00008000
 #define EMAC_MR1_JPSM			0x00000000
+#define EMAC_MR1_MWSW_001		0x00000000
 #define EMAC_MR1_BASE(opb)		(EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT)
 #else
 #define EMAC_MR1_RFS_4K			0x00180000
@@ -130,7 +131,7 @@
 					 (freq) <= 83  ? EMAC_MR1_OBCI_83 : \
 					 (freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P)
 #define EMAC_MR1_BASE(opb)		(EMAC_MR1_TFS_2K | EMAC_MR1_TR | \
-					 EMAC_MR1_MWSW_001 | EMAC_MR1_OBCI(opb))
+					 EMAC_MR1_OBCI(opb))
 #endif
 
 /* EMACx_TMR0 */
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index 1da8a66..591c586 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -408,7 +408,7 @@
 	/* Mode register */
 	r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST;
 	if (dev->phy.duplex == DUPLEX_FULL)
-		r |= EMAC_MR1_FDE;
+		r |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;
 	dev->stop_timeout = STOP_TIMEOUT_10;
 	switch (dev->phy.speed) {
 	case SPEED_1000:
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 1d75ca0..d1d714f 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -309,17 +309,6 @@
 
 
 
-static void cleanup_card(struct net_device *dev)
-{
-	struct lance_private *lp = dev->priv;
-	if (dev->dma != 4)
-		free_dma(dev->dma);
-	release_region(dev->base_addr, LANCE_TOTAL_SIZE);
-	kfree(lp->tx_bounce_buffs);
-	kfree((void*)lp->rx_buffs);
-	kfree(lp);
-}
-
 #ifdef MODULE
 #define MAX_CARDS		8	/* Max number of interfaces (cards) per module */
 
@@ -367,6 +356,17 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	struct lance_private *lp = dev->priv;
+	if (dev->dma != 4)
+		free_dma(dev->dma);
+	release_region(dev->base_addr, LANCE_TOTAL_SIZE);
+	kfree(lp->tx_bounce_buffs);
+	kfree((void*)lp->rx_buffs);
+	kfree(lp);
+}
+
 void cleanup_module(void)
 {
 	int this_dev;
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 309d254..646e89f 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -145,13 +145,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, LNE390_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init lne390_probe(int unit)
 {
@@ -440,6 +433,13 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, LNE390_IO_EXTENT);
+	iounmap(ei_status.mem);
+}
+
 void cleanup_module(void)
 {
 	int this_dev;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 3cb9b3f..22c3a37 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -6,7 +6,7 @@
  * Copyright (C) 2002 rabeeh@galileo.co.il
  *
  * Copyright (C) 2003 PMC-Sierra, Inc.,
- *	written by Manish Lachwani (lachwani@pmc-sierra.com)
+ *	written by Manish Lachwani
  *
  * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org>
  *
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 0de8fdd..94f782d 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -212,15 +212,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
-	if (idev)
-		pnp_device_detach(idev);
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, NE_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init ne_probe(int unit)
 {
@@ -859,6 +850,15 @@
 	return -ENODEV;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+	if (idev)
+		pnp_device_detach(idev);
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, NE_IO_EXTENT);
+}
+
 void cleanup_module(void)
 {
 	int this_dev;
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 6d62ada..e6df375 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -278,14 +278,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	mca_mark_as_unused(ei_status.priv);
-	mca_set_adapter_procfn( ei_status.priv, NULL, NULL);
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, NE_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init ne2_probe(int unit)
 {
@@ -812,6 +804,14 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	mca_mark_as_unused(ei_status.priv);
+	mca_set_adapter_procfn( ei_status.priv, NULL, NULL);
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, NE_IO_EXTENT);
+}
+
 void cleanup_module(void)
 {
 	int this_dev;
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 9a76ac1..197edd7 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -282,26 +282,22 @@
  * Description:
  *	This function initialize the PCI resources and IO
  *
- * Returns: N/A
- *	
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
  */
-int SkGeInitPCI(SK_AC *pAC)
+static __devinit int SkGeInitPCI(SK_AC *pAC)
 {
 	struct SK_NET_DEVICE *dev = pAC->dev[0];
 	struct pci_dev *pdev = pAC->PciDev;
 	int retval;
 
-	if (pci_enable_device(pdev) != 0) {
-		return 1;
-	}
-
 	dev->mem_start = pci_resource_start (pdev, 0);
 	pci_set_master(pdev);
 
-	if (pci_request_regions(pdev, "sk98lin") != 0) {
-		retval = 2;
-		goto out_disable;
-	}
+	retval = pci_request_regions(pdev, "sk98lin");
+	if (retval)
+		goto out;
 
 #ifdef SK_BIG_ENDIAN
 	/*
@@ -320,9 +316,8 @@
 	 * Remap the regs into kernel space.
 	 */
 	pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000);
-
-	if (!pAC->IoBase){
-		retval = 3;
+	if (!pAC->IoBase) {
+		retval = -EIO;
 		goto out_release;
 	}
 
@@ -330,8 +325,7 @@
 
  out_release:
 	pci_release_regions(pdev);
- out_disable:
-	pci_disable_device(pdev);
+ out:
 	return retval;
 }
 
@@ -492,7 +486,7 @@
  *	0, if everything is ok
  *	!=0, on error
  */
-static int __init SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
+static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
 {
 short	i;
 unsigned long Flags;
@@ -529,7 +523,7 @@
 	if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) {
 		printk("HWInit (0) failed.\n");
 		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
-		return(-EAGAIN);
+		return -EIO;
 	}
 	SkI2cInit(  pAC, pAC->IoBase, SK_INIT_DATA);
 	SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA);
@@ -551,7 +545,7 @@
 	if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
 		printk("sk98lin: HWInit (1) failed.\n");
 		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
-		return(-EAGAIN);
+		return -EIO;
 	}
 	SkI2cInit(  pAC, pAC->IoBase, SK_INIT_IO);
 	SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
@@ -583,20 +577,20 @@
 	} else {
 		printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n",
 		       pAC->GIni.GIMacsFound);
-		return -EAGAIN;
+		return -EIO;
 	}
 
 	if (Ret) {
 		printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n",
 		       dev->irq);
-		return -EAGAIN;
+		return Ret;
 	}
 	pAC->AllocFlag |= SK_ALLOC_IRQ;
 
 	/* Alloc memory for this board (Mem for RxD/TxD) : */
 	if(!BoardAllocMem(pAC)) {
 		printk("No memory for descriptor rings.\n");
-       		return(-EAGAIN);
+		return -ENOMEM;
 	}
 
 	BoardInitMem(pAC);
@@ -612,7 +606,7 @@
 		DualNet)) {
 		BoardFreeMem(pAC);
 		printk("sk98lin: SkGeInitAssignRamToQueues failed.\n");
-		return(-EAGAIN);
+		return -EIO;
 	}
 
 	return (0);
@@ -633,8 +627,7 @@
  *	SK_TRUE, if all memory could be allocated
  *	SK_FALSE, if not
  */
-static SK_BOOL BoardAllocMem(
-SK_AC	*pAC)
+static __devinit SK_BOOL BoardAllocMem(SK_AC	*pAC)
 {
 caddr_t		pDescrMem;	/* pointer to descriptor memory area */
 size_t		AllocLength;	/* length of complete descriptor area */
@@ -727,8 +720,7 @@
  *
  * Returns:	N/A
  */
-static void BoardInitMem(
-SK_AC	*pAC)	/* pointer to adapter context */
+static __devinit void BoardInitMem(SK_AC *pAC)
 {
 int	i;		/* loop counter */
 int	RxDescrSize;	/* the size of a rx descriptor rounded up to alignment*/
@@ -4776,32 +4768,47 @@
 	struct net_device	*dev = NULL;
 	static int boards_found = 0;
 	int error = -ENODEV;
+	int using_dac = 0;
 	char DeviceStr[80];
 
 	if (pci_enable_device(pdev))
 		goto out;
  
 	/* Configure DMA attributes. */
-	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
-	    pci_set_dma_mask(pdev, DMA_32BIT_MASK))
-		goto out_disable_device;
+	if (sizeof(dma_addr_t) > sizeof(u32) &&
+	    !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+		using_dac = 1;
+		error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+		if (error < 0) {
+			printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA "
+			       "for consistent allocations\n", pci_name(pdev));
+			goto out_disable_device;
+		}
+	} else {
+		error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (error) {
+			printk(KERN_ERR "sk98lin %s no usable DMA configuration\n",
+			       pci_name(pdev));
+			goto out_disable_device;
+		}
+	}
 
-
-	if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) {
-		printk(KERN_ERR "Unable to allocate etherdev "
+ 	error = -ENOMEM;
+ 	dev = alloc_etherdev(sizeof(DEV_NET));
+ 	if (!dev) {
+		printk(KERN_ERR "sk98lin: unable to allocate etherdev "
 		       "structure!\n");
 		goto out_disable_device;
 	}
 
 	pNet = netdev_priv(dev);
-	pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL);
+	pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL);
 	if (!pNet->pAC) {
-		printk(KERN_ERR "Unable to allocate adapter "
+		printk(KERN_ERR "sk98lin: unable to allocate adapter "
 		       "structure!\n");
 		goto out_free_netdev;
 	}
 
-	memset(pNet->pAC, 0, sizeof(SK_AC));
 	pAC = pNet->pAC;
 	pAC->PciDev = pdev;
 
@@ -4810,6 +4817,7 @@
 	pAC->CheckQueue = SK_FALSE;
 
 	dev->irq = pdev->irq;
+
 	error = SkGeInitPCI(pAC);
 	if (error) {
 		printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error);
@@ -4844,19 +4852,25 @@
 #endif
 	}
 
+	if (using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
+
 	pAC->Index = boards_found++;
 
-	if (SkGeBoardInit(dev, pAC))
+	error = SkGeBoardInit(dev, pAC);
+	if (error)
 		goto out_free_netdev;
 
 	/* Read Adapter name from VPD */
 	if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) {
+		error = -EIO;
 		printk(KERN_ERR "sk98lin: Could not read VPD data.\n");
 		goto out_free_resources;
 	}
 
 	/* Register net device */
-	if (register_netdev(dev)) {
+	error = register_netdev(dev);
+	if (error) {
 		printk(KERN_ERR "sk98lin: Could not register device.\n");
 		goto out_free_resources;
 	}
@@ -4883,15 +4897,17 @@
 
 	boards_found++;
 
+	pci_set_drvdata(pdev, dev);
+
 	/* More then one port found */
 	if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
-		if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) {
-			printk(KERN_ERR "Unable to allocate etherdev "
+		dev = alloc_etherdev(sizeof(DEV_NET));
+		if (!dev) {
+			printk(KERN_ERR "sk98lin: unable to allocate etherdev "
 				"structure!\n");
-			goto out;
+			goto single_port;
 		}
 
-		pAC->dev[1]   = dev;
 		pNet          = netdev_priv(dev);
 		pNet->PortNr  = 1;
 		pNet->NetNr   = 1;
@@ -4920,20 +4936,28 @@
 #endif
 		}
 
-		if (register_netdev(dev)) {
-			printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n");
+		if (using_dac)
+			dev->features |= NETIF_F_HIGHDMA;
+
+		error = register_netdev(dev);
+		if (error) {
+			printk(KERN_ERR "sk98lin: Could not register device"
+			       " for second port. (%d)\n", error);
 			free_netdev(dev);
-			pAC->dev[1] = pAC->dev[0];
-		} else {
-			memcpy(&dev->dev_addr,
-					&pAC->Addr.Net[1].CurrentMacAddress, 6);
-			memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-	
-			printk("%s: %s\n", dev->name, DeviceStr);
-			printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
+			goto single_port;
 		}
+
+		pAC->dev[1]   = dev;
+		memcpy(&dev->dev_addr,
+		       &pAC->Addr.Net[1].CurrentMacAddress, 6);
+		memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+		printk("%s: %s\n", dev->name, DeviceStr);
+		printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
 	}
 
+single_port:
+
 	/* Save the hardware revision */
 	pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
 		(pAC->GIni.GIPciHwRev & 0x0F);
@@ -4945,7 +4969,6 @@
 	memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA));
 	memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA));
 
-	pci_set_drvdata(pdev, dev);
 	return 0;
 
  out_free_resources:
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index ba8593a..3db30cd 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -168,18 +168,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: ultra_close_card() does free_irq */
-#ifdef __ISAPNP__
-	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
-	if (idev)
-		pnp_device_detach(idev);
-#endif
-	release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init ultra_probe(int unit)
 {
@@ -594,6 +582,18 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	/* NB: ultra_close_card() does free_irq */
+#ifdef __ISAPNP__
+	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+	if (idev)
+		pnp_device_detach(idev);
+#endif
+	release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
+	iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 125ed00..c67c912 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1564,7 +1564,7 @@
 			    dev->dev_addr, 6);
 		}
 #endif
-#if defined(__i386__)		/* Patch up x86 BIOS bug. */
+#if defined(__i386__) || defined(__x86_64__)	/* Patch up x86 BIOS bug. */
 		if (last_irq)
 			irq = last_irq;
 #endif
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index b03feae..7caa8dc 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -127,13 +127,6 @@
 	return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init wd_probe(int unit)
 {
@@ -538,6 +531,13 @@
 	return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
+	iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 44cd3fc..cf05661 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -7153,7 +7153,7 @@
 
 	/* Set the Wireless Extension versions */
 	range->we_version_compiled = WIRELESS_EXT;
-	range->we_version_source = 16;
+	range->we_version_source = 18;
 
 //      range->retry_capa;      /* What retry options are supported */
 //      range->retry_flags;     /* How to decode max/min retry limit */
@@ -7184,6 +7184,9 @@
 				IW_EVENT_CAPA_MASK(SIOCGIWAP));
 	range->event_capa[1] = IW_EVENT_CAPA_K_1;
 
+	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+		IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
 	IPW_DEBUG_WX("GET Range\n");
 
 	return 0;
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 932dcf0..311a412 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -432,11 +432,12 @@
 	struct Scsi_Host *host;
 	void *dma_cmd_space;
 	unsigned char *clkprop;
-	int proplen;
+	int proplen, rc = -ENODEV;
 
 	if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
-		printk(KERN_ERR "mac53c94: expected 2 addrs and intrs (got %d/%d)\n",
-		       node->n_addrs, node->n_intrs);
+		printk(KERN_ERR "mac53c94: expected 2 addrs and intrs"
+		       " (got %d/%d)\n",
+		       macio_resource_count(mdev), macio_irq_count(mdev));
 		return -ENODEV;
 	}
 
@@ -448,6 +449,7 @@
        	host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state));
 	if (host == NULL) {
 		printk(KERN_ERR "mac53c94: couldn't register host");
+		rc = -ENOMEM;
 		goto out_release;
 	}
 
@@ -486,6 +488,7 @@
        	if (dma_cmd_space == 0) {
        		printk(KERN_ERR "mac53c94: couldn't allocate dma "
        		       "command space for %s\n", node->full_name);
+		rc = -ENOMEM;
        		goto out_free;
        	}
 	state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space);
@@ -495,18 +498,21 @@
 
 	mac53c94_init(state);
 
-	if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94", state)) {
+	if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94",state)) {
 		printk(KERN_ERR "mac53C94: can't get irq %d for %s\n",
 		       state->intr, node->full_name);
 		goto out_free_dma;
 	}
 
-	/* XXX FIXME: handle failure */
-	scsi_add_host(host, &mdev->ofdev.dev);
-	scsi_scan_host(host);
+	rc = scsi_add_host(host, &mdev->ofdev.dev);
+	if (rc != 0)
+		goto out_release_irq;
 
+	scsi_scan_host(host);
 	return 0;
 
+ out_release_irq:
+	free_irq(state->intr, state);
  out_free_dma:
 	kfree(state->dma_cmd_space);
  out_free:
@@ -518,7 +524,7 @@
  out_release:
 	macio_release_resources(mdev);
 
-	return  -ENODEV;
+	return rc;
 }
 
 static int mac53c94_remove(struct macio_dev *mdev)
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index bdccf73..d6d2125 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1869,7 +1869,8 @@
 
 	if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
        		printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
-	       	       " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs);
+	       	       " (got %d,%d)\n", macio_resource_count(mdev),
+		       macio_irq_count(mdev));
 		return -ENODEV;
 	}
 
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index c0cf52c..bbbb55e 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -29,6 +29,12 @@
  *  NV-specific details such as register offsets, SATA phy location,
  *  hotplug info, etc.
  *
+ *  0.10
+ *     - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB
+ *       drive.  Also made the check_hotplug() callbacks return whether there
+ *       was a hotplug interrupt or not.  This was not the source of the
+ *       spurious interrupts, but is the right thing to do anyway.
+ *
  *  0.09
  *     - Fixed bug introduced by 0.08's MCP51 and MCP55 support.
  *
@@ -124,10 +130,10 @@
 static void nv_host_stop (struct ata_host_set *host_set);
 static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
 static void nv_disable_hotplug(struct ata_host_set *host_set);
-static void nv_check_hotplug(struct ata_host_set *host_set);
+static int nv_check_hotplug(struct ata_host_set *host_set);
 static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
 static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
-static void nv_check_hotplug_ck804(struct ata_host_set *host_set);
+static int nv_check_hotplug_ck804(struct ata_host_set *host_set);
 
 enum nv_host_type
 {
@@ -176,7 +182,7 @@
 	enum nv_host_type	host_type;
 	void			(*enable_hotplug)(struct ata_probe_ent *probe_ent);
 	void			(*disable_hotplug)(struct ata_host_set *host_set);
-	void			(*check_hotplug)(struct ata_host_set *host_set);
+	int			(*check_hotplug)(struct ata_host_set *host_set);
 
 };
 static struct nv_host_desc nv_device_tbl[] = {
@@ -309,12 +315,16 @@
 			qc = ata_qc_from_tag(ap, ap->active_tag);
 			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
 				handled += ata_host_intr(ap, qc);
+			else
+				// No request pending?  Clear interrupt status
+				// anyway, in case there's one pending.
+				ap->ops->check_status(ap);
 		}
 
 	}
 
 	if (host->host_desc->check_hotplug)
-		host->host_desc->check_hotplug(host_set);
+		handled += host->host_desc->check_hotplug(host_set);
 
 	spin_unlock_irqrestore(&host_set->lock, flags);
 
@@ -497,7 +507,7 @@
 	outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
 }
 
-static void nv_check_hotplug(struct ata_host_set *host_set)
+static int nv_check_hotplug(struct ata_host_set *host_set)
 {
 	u8 intr_status;
 
@@ -522,7 +532,11 @@
 		if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
 			printk(KERN_WARNING "nv_sata: "
 				"Secondary device removed\n");
+
+		return 1;
 	}
+
+	return 0;
 }
 
 static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
@@ -560,7 +574,7 @@
 	pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
 }
 
-static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
+static int nv_check_hotplug_ck804(struct ata_host_set *host_set)
 {
 	u8 intr_status;
 
@@ -585,7 +599,11 @@
 		if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
 			printk(KERN_WARNING "nv_sata: "
 				"Secondary device removed\n");
+
+		return 1;
 	}
+
+	return 0;
 }
 
 static int __init nv_init(void)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 180676d..ee5f4df 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -69,7 +69,6 @@
 #include "scsi_logging.h"
 
 static void scsi_done(struct scsi_cmnd *cmd);
-static int scsi_retry_command(struct scsi_cmnd *cmd);
 
 /*
  * Definitions and constants.
@@ -752,7 +751,7 @@
  * isn't running --- used by scsi_times_out */
 void __scsi_done(struct scsi_cmnd *cmd)
 {
-	unsigned long flags;
+	struct request *rq = cmd->request;
 
 	/*
 	 * Set the serial numbers back to zero
@@ -763,71 +762,14 @@
 	if (cmd->result)
 		atomic_inc(&cmd->device->ioerr_cnt);
 
+	BUG_ON(!rq);
+
 	/*
-	 * Next, enqueue the command into the done queue.
-	 * It is a per-CPU queue, so we just disable local interrupts
-	 * and need no spinlock.
+	 * The uptodate/nbytes values don't matter, as we allow partial
+	 * completes and thus will check this in the softirq callback
 	 */
-	local_irq_save(flags);
-	list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q));
-	raise_softirq_irqoff(SCSI_SOFTIRQ);
-	local_irq_restore(flags);
-}
-
-/**
- * scsi_softirq - Perform post-interrupt processing of finished SCSI commands.
- *
- * This is the consumer of the done queue.
- *
- * This is called with all interrupts enabled.  This should reduce
- * interrupt latency, stack depth, and reentrancy of the low-level
- * drivers.
- */
-static void scsi_softirq(struct softirq_action *h)
-{
-	int disposition;
-	LIST_HEAD(local_q);
-
-	local_irq_disable();
-	list_splice_init(&__get_cpu_var(scsi_done_q), &local_q);
-	local_irq_enable();
-
-	while (!list_empty(&local_q)) {
-		struct scsi_cmnd *cmd = list_entry(local_q.next,
-						   struct scsi_cmnd, eh_entry);
-		/* The longest time any command should be outstanding is the
-		 * per command timeout multiplied by the number of retries.
-		 *
-		 * For a typical command, this is 2.5 minutes */
-		unsigned long wait_for 
-			= cmd->allowed * cmd->timeout_per_command;
-		list_del_init(&cmd->eh_entry);
-
-		disposition = scsi_decide_disposition(cmd);
-		if (disposition != SUCCESS &&
-		    time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
-			sdev_printk(KERN_ERR, cmd->device,
-				    "timing out command, waited %lus\n",
-				    wait_for/HZ);
-			disposition = SUCCESS;
-		}
-			
-		scsi_log_completion(cmd, disposition);
-		switch (disposition) {
-		case SUCCESS:
-			scsi_finish_command(cmd);
-			break;
-		case NEEDS_RETRY:
-			scsi_retry_command(cmd);
-			break;
-		case ADD_TO_MLQUEUE:
-			scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
-			break;
-		default:
-			if (!scsi_eh_scmd_add(cmd, 0))
-				scsi_finish_command(cmd);
-		}
-	}
+	rq->completion_data = cmd;
+	blk_complete_request(rq);
 }
 
 /*
@@ -840,7 +782,7 @@
  *              level drivers should not become re-entrant as a result of
  *              this.
  */
-static int scsi_retry_command(struct scsi_cmnd *cmd)
+int scsi_retry_command(struct scsi_cmnd *cmd)
 {
 	/*
 	 * Restore the SCSI command state.
@@ -1273,38 +1215,6 @@
 }
 EXPORT_SYMBOL(scsi_device_cancel);
 
-#ifdef CONFIG_HOTPLUG_CPU
-static int scsi_cpu_notify(struct notifier_block *self,
-			   unsigned long action, void *hcpu)
-{
-	int cpu = (unsigned long)hcpu;
-
-	switch(action) {
-	case CPU_DEAD:
-		/* Drain scsi_done_q. */
-		local_irq_disable();
-		list_splice_init(&per_cpu(scsi_done_q, cpu),
-				 &__get_cpu_var(scsi_done_q));
-		raise_softirq_irqoff(SCSI_SOFTIRQ);
-		local_irq_enable();
-		break;
-	default:
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block __devinitdata scsi_cpu_nb = {
-	.notifier_call	= scsi_cpu_notify,
-};
-
-#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb)
-#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb)
-#else
-#define register_scsi_cpu()
-#define unregister_scsi_cpu()
-#endif /* CONFIG_HOTPLUG_CPU */
-
 MODULE_DESCRIPTION("SCSI core");
 MODULE_LICENSE("GPL");
 
@@ -1338,8 +1248,6 @@
 		INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
 
 	devfs_mk_dir("scsi");
-	open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
-	register_scsi_cpu();
 	printk(KERN_NOTICE "SCSI subsystem initialized\n");
 	return 0;
 
@@ -1367,7 +1275,6 @@
 	devfs_remove("scsi");
 	scsi_exit_procfs();
 	scsi_exit_queue();
-	unregister_scsi_cpu();
 }
 
 subsys_initcall(init_scsi);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ba93d6e..00c9bf3 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1493,6 +1493,41 @@
 	__scsi_done(cmd);
 }
 
+static void scsi_softirq_done(struct request *rq)
+{
+	struct scsi_cmnd *cmd = rq->completion_data;
+	unsigned long wait_for = cmd->allowed * cmd->timeout_per_command;
+	int disposition;
+
+	INIT_LIST_HEAD(&cmd->eh_entry);
+
+	disposition = scsi_decide_disposition(cmd);
+	if (disposition != SUCCESS &&
+	    time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
+		sdev_printk(KERN_ERR, cmd->device,
+			    "timing out command, waited %lus\n",
+			    wait_for/HZ);
+		disposition = SUCCESS;
+	}
+			
+	scsi_log_completion(cmd, disposition);
+
+	switch (disposition) {
+		case SUCCESS:
+			scsi_finish_command(cmd);
+			break;
+		case NEEDS_RETRY:
+			scsi_retry_command(cmd);
+			break;
+		case ADD_TO_MLQUEUE:
+			scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+			break;
+		default:
+			if (!scsi_eh_scmd_add(cmd, 0))
+				scsi_finish_command(cmd);
+	}
+}
+
 /*
  * Function:    scsi_request_fn()
  *
@@ -1667,6 +1702,7 @@
 	blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
 	blk_queue_segment_boundary(q, shost->dma_boundary);
 	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+	blk_queue_softirq_done(q, scsi_softirq_done);
 
 	if (!shost->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index f04e7e1..14a6198 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -44,6 +44,7 @@
 		struct scsi_request *sreq);
 extern void __scsi_release_request(struct scsi_request *sreq);
 extern void __scsi_done(struct scsi_cmnd *cmd);
+extern int scsi_retry_command(struct scsi_cmnd *cmd);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 221e96e..78aad95 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -2493,7 +2493,7 @@
 	}
 	if (resp) {
 		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-			memset(resp, 0, resSz);
+			memset(page_address(resp), 0, resSz);
 		if (retSzp)
 			*retSzp = resSz;
 	}
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 987d22b..16af562 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -608,7 +608,7 @@
 
 		p = cpm2cpu_addr(bdp->cbd_bufaddr);
 
-		*p++ = xmit->buf[xmit->tail];
+		*p++ = port->x_char;
 		bdp->cbd_datlen = 1;
 		bdp->cbd_sc |= BD_SC_READY;
 		/* Get next BD. */
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 5ddd8ab..ea24129 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1431,11 +1431,14 @@
 		char	name[1];
 	} *slots;
 	int len;
+	struct resource r_ports, r_rxdma, r_txdma;
 
 	/*
 	 * Request & map chip registers
 	 */
-	uap->port.mapbase = np->addrs[0].address;
+	if (of_address_to_resource(np, 0, &r_ports))
+		return -ENODEV;
+	uap->port.mapbase = r_ports.start;
 	uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
       
 	uap->control_reg = uap->port.membase;
@@ -1445,16 +1448,20 @@
 	 * Request & map DBDMA registers
 	 */
 #ifdef HAS_DBDMA
-	if (np->n_addrs >= 3 && np->n_intrs >= 3)
+	if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
+	    of_address_to_resource(np, 2, &r_rxdma) == 0)
 		uap->flags |= PMACZILOG_FLAG_HAS_DMA;
+#else
+	memset(&r_txdma, 0, sizeof(struct resource));
+	memset(&r_rxdma, 0, sizeof(struct resource));
 #endif	
 	if (ZS_HAS_DMA(uap)) {
-		uap->tx_dma_regs = ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
+		uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
 		if (uap->tx_dma_regs == NULL) {	
 			uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
 			goto no_dma;
 		}
-		uap->rx_dma_regs = ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
+		uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
 		if (uap->rx_dma_regs == NULL) {	
 			iounmap(uap->tx_dma_regs);
 			uap->tx_dma_regs = NULL;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index cc8e3bf..3f04427 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1151,7 +1151,7 @@
 
 config FB_CYBLA
 	tristate "Cyberblade/i1 support"
-	depends on FB && PCI
+	depends on FB && PCI && X86_32 && !64BIT
 	select FB_CFB_IMAGEBLIT
 	select VIDEO_SELECT
 	---help---
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 403d173..03798e9 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -133,12 +133,6 @@
 static int controlfb_set_par (struct fb_info *info);
 static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
 
-/*
- * inititialization
- */
-int control_init(void);
-void control_setup(char *);
-
 /******************** Prototypes for internal functions **********************/
 
 static void set_control_clock(unsigned char *params);
@@ -550,9 +544,46 @@
 
 
 /*
- * Called from fbmem.c for probing & initializing
+ * Parse user speficied options (`video=controlfb:')
  */
-int __init control_init(void)
+static void __init control_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "vmode:", 6)) {
+			int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX &&
+			    control_mac_modes[vmode - 1].m[1] >= 0)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			int depth = simple_strtoul(this_opt+6, NULL, 0);
+			switch (depth) {
+			 case CMODE_8:
+			 case CMODE_16:
+			 case CMODE_32:
+			 	default_cmode = depth;
+			 	break;
+			 case 8:
+				default_cmode = CMODE_8;
+				break;
+			 case 15:
+			 case 16:
+				default_cmode = CMODE_16;
+				break;
+			 case 24:
+			 case 32:
+				default_cmode = CMODE_32;
+				break;
+			}
+		}
+	}
+}
+
+static int __init control_init(void)
 {
 	struct device_node *dp;
 	char *option = NULL;
@@ -651,15 +682,16 @@
 static int __init control_of_init(struct device_node *dp)
 {
 	struct fb_info_control	*p;
-	unsigned long		addr;
-	int			i;
+	struct resource		fb_res, reg_res;
 
 	if (control_fb) {
 		printk(KERN_ERR "controlfb: only one control is supported\n");
 		return -ENXIO;
 	}
-	if(dp->n_addrs != 2) {
-		printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs);
+
+	if (of_pci_address_to_resource(dp, 2, &fb_res) ||
+	    of_pci_address_to_resource(dp, 1, &reg_res)) {
+		printk(KERN_ERR "can't get 2 addresses for control\n");
 		return -ENXIO;
 	}
 	p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -669,18 +701,12 @@
 	memset(p, 0, sizeof(*p));
 
 	/* Map in frame buffer and registers */
-	for (i = 0; i < dp->n_addrs; ++i) {
-		addr = dp->addrs[i].address;
-		if (dp->addrs[i].size >= 0x800000) {
-			p->fb_orig_base = addr;
-			p->fb_orig_size = dp->addrs[i].size;
-			/* use the big-endian aperture (??) */
-			p->frame_buffer_phys = addr + 0x800000;
-		} else {
-			p->control_regs_phys = addr;
-			p->control_regs_size = dp->addrs[i].size;
-		}
-	}
+	p->fb_orig_base = fb_res.start;
+	p->fb_orig_size = fb_res.end - fb_res.start + 1;
+	/* use the big-endian aperture (??) */
+	p->frame_buffer_phys = fb_res.start + 0x800000;
+	p->control_regs_phys = reg_res.start;
+	p->control_regs_size = reg_res.end - reg_res.start + 1;
 
 	if (!p->fb_orig_base ||
 	    !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) {
@@ -1059,43 +1085,3 @@
 }
 
 
-/*
- * Parse user speficied options (`video=controlfb:')
- */
-void __init control_setup(char *options)
-{
-	char *this_opt;
-
-	if (!options || !*options)
-		return;
-
-	while ((this_opt = strsep(&options, ",")) != NULL) {
-		if (!strncmp(this_opt, "vmode:", 6)) {
-			int vmode = simple_strtoul(this_opt+6, NULL, 0);
-			if (vmode > 0 && vmode <= VMODE_MAX &&
-			    control_mac_modes[vmode - 1].m[1] >= 0)
-				default_vmode = vmode;
-		} else if (!strncmp(this_opt, "cmode:", 6)) {
-			int depth = simple_strtoul(this_opt+6, NULL, 0);
-			switch (depth) {
-			 case CMODE_8:
-			 case CMODE_16:
-			 case CMODE_32:
-			 	default_cmode = depth;
-			 	break;
-			 case 8:
-				default_cmode = CMODE_8;
-				break;
-			 case 15:
-			 case 16:
-				default_cmode = CMODE_16;
-				break;
-			 case 24:
-			 case 32:
-				default_cmode = CMODE_32;
-				break;
-			}
-		}
-	}
-}
-
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
index 03fbe83..e9f5dee 100644
--- a/drivers/video/cyblafb.c
+++ b/drivers/video/cyblafb.c
@@ -7,11 +7,12 @@
  *	tridentfb.c by Jani Monoses
  *	see files above for further credits
  *
- * TODO:
- *
  */
 
 #define CYBLAFB_DEBUG 0
+#define CYBLAFB_KD_GRAPHICS_QUIRK 1
+
+#define CYBLAFB_PIXMAPSIZE 8192
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -22,7 +23,7 @@
 #include <asm/types.h>
 #include <video/cyblafb.h>
 
-#define VERSION "0.54"
+#define VERSION "0.62"
 
 struct cyblafb_par {
 	u32 pseudo_pal[16];
@@ -32,7 +33,9 @@
 static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
 	.id = "CyBla",
 	.type = FB_TYPE_PACKED_PIXELS,
+	.xpanstep = 1,
 	.ypanstep = 1,
+	.ywrapstep = 1,
 	.visual = FB_VISUAL_PSEUDOCOLOR,
 	.accel = FB_ACCEL_NONE,
 };
@@ -43,8 +46,9 @@
 static int fp __devinitdata;
 static int crt __devinitdata;
 static int memsize __devinitdata;
-static int vesafb __devinitdata;
 
+static int basestride;
+static int vesafb;
 static int nativex;
 static int center;
 static int stretch;
@@ -52,26 +56,50 @@
 static int pcirb = 1;
 static int pciwr = 1;
 static int pcirr = 1;
+static int disabled;
 static int verbosity;
 static int displaytype;
 
-static void __iomem * io_virt; // iospace virtual memory address
+static void __iomem *io_virt;	// iospace virtual memory address
 
-module_param(mode,charp,0);
-module_param(bpp,int,0);
-module_param(ref,int,0);
-module_param(fp,int,0);
-module_param(crt,int,0);
-module_param(nativex,int,0);
-module_param(center,int,0);
-module_param(stretch,int,0);
-module_param(pciwb,int,0);
-module_param(pcirb,int,0);
-module_param(pciwr,int,0);
-module_param(pcirr,int,0);
-module_param(memsize,int,0);
-module_param(verbosity,int,0);
-module_param(vesafb,int,0);
+module_param(mode, charp, 0);
+module_param(bpp, int, 0);
+module_param(ref, int, 0);
+module_param(fp, int, 0);
+module_param(crt, int, 0);
+module_param(nativex, int, 0);
+module_param(center, int, 0);
+module_param(stretch, int, 0);
+module_param(pciwb, int, 0);
+module_param(pcirb, int, 0);
+module_param(pciwr, int, 0);
+module_param(pcirr, int, 0);
+module_param(memsize, int, 0);
+module_param(verbosity, int, 0);
+
+//=========================================
+//
+// Well, we have to fix the upper layers.
+// Until this has been done, we work around
+// the bugs.
+//
+//=========================================
+
+#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
+	if (disabled) { \
+		printk("********\n");\
+		dump_stack();\
+		return val;\
+	}
+
+#elif CYBLAFB_KD_GRAPHICS_QUIRK
+#define KD_GRAPHICS_RETURN(val)\
+	if (disabled) {\
+		return val;\
+	}
+#else
+#define KD_GRAPHICS_RETURN(val)
+#endif
 
 //=========================================
 //
@@ -79,10 +107,10 @@
 //
 //=========================================
 
-#define out8(r,v) writeb(v,io_virt+r)
-#define out32(r,v) writel(v,io_virt+r)
-#define in8(r) readb(io_virt+r)
-#define in32(r) readl(io_virt+r)
+#define out8(r, v) writeb(v, io_virt + r)
+#define out32(r, v) writel(v, io_virt + r)
+#define in8(r) readb(io_virt + r)
+#define in32(r) readl(io_virt + r)
 
 //======================================
 //
@@ -90,47 +118,47 @@
 //
 //======================================
 
-static inline unsigned char read3X4(int reg)
+static inline u8 read3X4(u32 reg)
 {
-	out8(0x3D4,reg);
+	out8(0x3D4, reg);
 	return in8(0x3D5);
 }
 
-static inline unsigned char read3C4(int reg)
+static inline u8 read3C4(u32 reg)
 {
-	out8(0x3C4,reg);
+	out8(0x3C4, reg);
 	return in8(0x3C5);
 }
 
-static inline unsigned char read3CE(int reg)
+static inline u8 read3CE(u32 reg)
 {
-	out8(0x3CE,reg);
+	out8(0x3CE, reg);
 	return in8(0x3CF);
 }
 
-static inline void write3X4(int reg,unsigned char val)
+static inline void write3X4(u32 reg, u8 val)
 {
-	out8(0x3D4,reg);
-	out8(0x3D5,val);
+	out8(0x3D4, reg);
+	out8(0x3D5, val);
 }
 
-static inline void write3C4(int reg,unsigned char val)
+static inline void write3C4(u32 reg, u8 val)
 {
-	out8(0x3C4,reg);
-	out8(0x3C5,val);
+	out8(0x3C4, reg);
+	out8(0x3C5, val);
 }
 
-static inline void write3CE(int reg,unsigned char val)
+static inline void write3CE(u32 reg, u8 val)
 {
-	out8(0x3CE,reg);
-	out8(0x3CF,val);
+	out8(0x3CE, reg);
+	out8(0x3CF, val);
 }
 
-static inline void write3C0(int reg,unsigned char val)
+static inline void write3C0(u32 reg, u8 val)
 {
-	in8(0x3DA);	// read to reset index
-	out8(0x3C0,reg);
-	out8(0x3C0,val);
+	in8(0x3DA);		// read to reset index
+	out8(0x3C0, reg);
+	out8(0x3C0, val);
 }
 
 //=================================================
@@ -139,58 +167,62 @@
 //
 //=================================================
 
-static inline void enable_mmio(void)
+static void enable_mmio(void)
 {
-	int tmp;
+	u8 tmp;
 
-	outb(0x0B,0x3C4);
+	outb(0x0B, 0x3C4);
 	inb(0x3C5);		// Set NEW mode
-	outb(SR0E,0x3C4);	// write enable a lot of extended ports
-	outb(0x80,0x3C5);
+	outb(SR0E, 0x3C4);	// write enable a lot of extended ports
+	outb(0x80, 0x3C5);
 
-	outb(SR11,0x3C4);	// write enable those extended ports that
-	outb(0x87,0x3C5);	// are not affected by SR0E_New
+	outb(SR11, 0x3C4);	// write enable those extended ports that
+	outb(0x87, 0x3C5);	// are not affected by SR0E_New
 
-	outb(CR1E,0x3d4);	// clear write protect bit for port 0x3c2
-	tmp=inb(0x3d5) & 0xBF;
-	outb(CR1E,0x3d4);
-	outb(tmp,0x3d5);
+	outb(CR1E, 0x3d4);	// clear write protect bit for port 0x3c2
+	tmp = inb(0x3d5) & 0xBF;
+	outb(CR1E, 0x3d4);
+	outb(tmp, 0x3d5);
 
-	outb(CR39,0x3D4);
-	outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched
+	outb(CR39, 0x3D4);
+	outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
 }
 
 //=================================================
 //
 // Set pixel clock VCLK1
-//   - multipliers set elswhere
-//   - freq in units of 0.01 MHz
+// - multipliers set elswhere
+// - freq in units of 0.01 MHz
+//
+// Hardware bug: SR18 >= 250 is broken for the
+//		 cyberblade/i1
 //
 //=================================================
 
 static void set_vclk(struct cyblafb_par *par, int freq)
 {
-	u32 m,n,k;
-	int f,fi,d,di;
-	u8 lo=0,hi=0;
+	u32 m, n, k;
+	int f, fi, d, di;
+	u8 lo = 0, hi = 0;
 
 	d = 2000;
 	k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
-	for(m = 0;m<64;m++)
-	for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 !
-		fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12);
-		if ((di = abs(fi - freq)) < d) {
-			d = di;
-			f = fi;
-			lo = (u8) n;
-			hi = (u8) ((k<<6) | m);
+	for (m = 0; m < 64; m++)
+		for (n = 0; n < 250; n++) {
+			fi = (int)(((5864727 * (n + 8)) /
+				    ((m + 2) * (1 << k))) >> 12);
+			if ((di = abs(fi - freq)) < d) {
+				d = di;
+				f = fi;
+				lo = (u8) n;
+				hi = (u8) ((k << 6) | m);
+			}
 		}
-	}
-	write3C4(SR19,hi);
-	write3C4(SR18,lo);
-	if(verbosity > 1)
+	write3C4(SR19, hi);
+	write3C4(SR18, lo);
+	if (verbosity > 0)
 		output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
-		freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo);
+		       freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
 }
 
 //================================================
@@ -199,83 +231,83 @@
 //
 //================================================
 
-static void cyblafb_setup_GE(int pitch,int bpp)
+static void cyblafb_setup_GE(int pitch, int bpp)
 {
-	int base = (pitch>>3)<<20;
+	KD_GRAPHICS_RETURN();
 
 	switch (bpp) {
-		case  8: base |= (0<<29); break;
-		case 15: base |= (5<<29); break;
-		case 16: base |= (1<<29); break;
-		case 24:
-		case 32: base |= (2<<29); break;
+	case 8:
+		basestride = ((pitch >> 3) << 20) | (0 << 29);
+		break;
+	case 15:
+		basestride = ((pitch >> 3) << 20) | (5 << 29);
+		break;
+	case 16:
+		basestride = ((pitch >> 3) << 20) | (1 << 29);
+		break;
+	case 24:
+	case 32:
+		basestride = ((pitch >> 3) << 20) | (2 << 29);
+		break;
 	}
 
-	write3X4(CR36,0x90);	// reset GE
-	write3X4(CR36,0x80);	// enable GE
-
-	out32(GE24,1<<7);	// reset all GE pointers
-	out32(GE24,0);
-
-	write3X4(CR2D,0x00);	// GE Timinigs, no delays
-
-	out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133
-	out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133
-	out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133
-	out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133
-	out32(GEC8,base); // Source Stride / Buffer Base 0, p 133
-	out32(GECC,base); // Source Stride / Buffer Base 1, p 133
-	out32(GED0,base); // Source Stride / Buffer Base 2, p 133
-	out32(GED4,base); // Source Stride / Buffer Base 3, p 133
-	out32(GE6C,0);	  // Pattern and Style, p 129, ok
+	write3X4(CR36, 0x90);	// reset GE
+	write3X4(CR36, 0x80);	// enable GE
+	out32(GE24, 1 << 7);	// reset all GE pointers by toggling
+	out32(GE24, 0); 	//   d7 of GE24
+	write3X4(CR2D, 0x00);	// GE Timinigs, no delays
+	out32(GE6C, 0); 	// Pattern and Style, p 129, ok
 }
 
 //=====================================================================
 //
-// Although this is a .fb_sync function that could be enabled in
-// cyblafb_ops, we do not include it there. We sync immediately before
-// new GE operations to improve performance.
+// Cyberblade specific syncing
+//
+//   A timeout might be caused by disabled mmio.
+//   Cause:
+//     - bit CR39 & 1 == 0 upon return, X trident driver bug
+//     - kdm bug (KD_GRAPHICS not set on first switch)
+//     - kernel design flaw (it believes in the correctness
+//	 of kdm/X
+//   First we try to sync ignoring that problem, as most of the
+//   time that will succeed immediately and the enable_mmio()
+//   would only degrade performance.
 //
 //=====================================================================
 
 static int cyblafb_sync(struct fb_info *info)
 {
-	int status, i=100000;
-	while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
+	u32 status, i = 100000;
+
+	KD_GRAPHICS_RETURN(0);
+
+	while (((status = in32(GE20)) & 0xFe800000) && i != 0)
 		i--;
 
 	if (i == 0) {
-		// The timeout might be caused by disabled mmio.
-		// Cause:
-		//   - bit CR39 & 1 == 0 upon return, X trident driver bug
-		//   - kdm bug (KD_GRAPHICS not set on first switch)
-		//   - kernel design flaw (it believes in the correctness
-		//     of kdm/X
-		// So we make sure that mmio is enabled first ...
 		enable_mmio();
-//		show_trace(NULL,&status);
-		i=1000000;
-		while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
+		i = 1000000;
+		while (((status = in32(GE20)) & 0xFA800000) && i != 0)
 			i--;
 		if (i == 0) {
-			output("GE Timeout, status: %x\n",status);
-			if(status & 0x80000000)
+			output("GE Timeout, status: %x\n", status);
+			if (status & 0x80000000)
 				output("Bresenham Engine : Busy\n");
-			if(status & 0x40000000)
+			if (status & 0x40000000)
 				output("Setup Engine     : Busy\n");
-			if(status & 0x20000000)
+			if (status & 0x20000000)
 				output("SP / DPE         : Busy\n");
-			if(status & 0x10000000)
+			if (status & 0x10000000)
 				output("Memory Interface : Busy\n");
-			if(status & 0x08000000)
+			if (status & 0x08000000)
 				output("Com Lst Proc     : Busy\n");
-			if(status & 0x04000000)
+			if (status & 0x04000000)
 				output("Block Write      : Busy\n");
-			if(status & 0x02000000)
+			if (status & 0x02000000)
 				output("Command Buffer   : Full\n");
-			if(status & 0x01000000)
+			if (status & 0x01000000)
 				output("RESERVED         : Busy\n");
-			if(status & 0x00800000)
+			if (status & 0x00800000)
 				output("PCI Write Buffer : Busy\n");
 			cyblafb_setup_GE(info->var.xres,
 					 info->var.bits_per_pixel);
@@ -291,142 +323,193 @@
 //
 //==============================
 
-static void cyblafb_fillrect(struct fb_info * info,
-			     const struct fb_fillrect *fr)
+static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
 {
-	int bpp = info->var.bits_per_pixel;
-	int col;
+	u32 bpp = info->var.bits_per_pixel, col, desty, height;
+
+	KD_GRAPHICS_RETURN();
 
 	switch (bpp) {
-		default:
-		case 8: col = fr->color;
-			col |= col <<8;
-			col |= col <<16;
-			break;
-		case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
-			 col |= col <<16;
-			 break;
-		case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
-			 break;
+	default:
+	case 8:
+		col = fr->color;
+		col |= col << 8;
+		col |= col << 16;
+		break;
+	case 16:
+		col = ((u32 *) (info->pseudo_palette))[fr->color];
+		col |= col << 16;
+		break;
+	case 32:
+		col = ((u32 *) (info->pseudo_palette))[fr->color];
+		break;
 	}
 
-	cyblafb_sync(info);
-
-	out32(GE60,col);
-	out32(GE48,fr->rop ? 0x66:ROP_S);
-	out32(GE44,0x20000000|1<<19|1<<4|2<<2);
-	out32(GE08,point(fr->dx,fr->dy));
-	out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1));
-
+	desty = fr->dy;
+	height = fr->height;
+	while (height) {
+		out32(GEB8, basestride | ((desty * info->var.xres_virtual *
+					   bpp) >> 6));
+		out32(GE60, col);
+		out32(GE48, fr->rop ? 0x66 : ROP_S);
+		out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
+		out32(GE08, point(fr->dx, 0));
+		out32(GE0C, point(fr->dx + fr->width - 1,
+				  height > 4096 ? 4095 : height - 1));
+		if (likely(height <= 4096))
+			return;
+		desty += 4096;
+		height -= 4096;
+	}
 }
 
-//==============================
+//================================================
 //
 // Cyberblade specific copyarea
 //
-//==============================
+// This function silently assumes that it never
+// will be called with width or height exceeding
+// 4096.
+//
+//================================================
 
-static void cyblafb_copyarea(struct fb_info *info,
-			     const struct fb_copyarea *ca)
+static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
 {
-	__u32 s1,s2,d1,d2;
-	int direction;
+	u32 s1, s2, d1, d2, direction;
 
-	s1 = point(ca->sx,ca->sy);
-	s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1);
-	d1 = point(ca->dx,ca->dy);
-	d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1);
+	KD_GRAPHICS_RETURN();
+
+	s1 = point(ca->sx, 0);
+	s2 = point(ca->sx + ca->width - 1, ca->height - 1);
+	d1 = point(ca->dx, 0);
+	d2 = point(ca->dx + ca->width - 1, ca->height - 1);
+
 	if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
 		direction = 0;
 	else
 		direction = 2;
 
-	cyblafb_sync(info);
-
-	out32(GE44,0xa0000000|1<<19|1<<2|direction);
-	out32(GE00,direction?s2:s1);
-	out32(GE04,direction?s1:s2);
-	out32(GE08,direction?d2:d1);
-	out32(GE0C,direction?d1:d2);
-
+	out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
+				   info->var.bits_per_pixel) >> 6));
+	out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
+				   info->var.bits_per_pixel) >> 6));
+	out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
+	out32(GE00, direction ? s2 : s1);
+	out32(GE04, direction ? s1 : s2);
+	out32(GE08, direction ? d2 : d1);
+	out32(GE0C, direction ? d1 : d2);
 }
 
 //=======================================================================
 //
 // Cyberblade specific imageblit
 //
-// Accelerated for the most usual case, blitting 1-bit deep character
-// character images. Everything else is passed to the generic imageblit.
+// Accelerated for the most usual case, blitting 1 - bit deep
+// character images. Everything else is passed to the generic imageblit
+// unless it is so insane that it is better to printk an alert.
+//
+// Hardware bug: _Never_ blit across pixel column 2048, that will lock
+// the system. We split those blit requests into three blitting
+// operations.
 //
 //=======================================================================
 
 static void cyblafb_imageblit(struct fb_info *info,
 			      const struct fb_image *image)
 {
-
 	u32 fgcol, bgcol;
+	u32 *pd = (u32 *) image->data;
+	u32 bpp = info->var.bits_per_pixel;
 
-	int i;
-	int bpp = info->var.bits_per_pixel;
-	int index = 0;
-	int index_end=image->height * image->width / 8;
-	int width_dds=image->width / 32;
-	int width_dbs=image->width % 32;
+	KD_GRAPHICS_RETURN();
 
-	if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 ||
-	    image->width % 8 != 0 || image->width == 0 || image->height == 0) {
-		cfb_imageblit(info,image);
+	// Used only for drawing the penguine (image->depth > 1)
+	if (image->depth != 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+	// That should never happen, but it would be fatal
+	if (image->width == 0 || image->height == 0) {
+		output("imageblit: width/height 0 detected\n");
 		return;
 	}
 
 	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
-		fgcol = ((u32*)(info->pseudo_palette))[image->fg_color];
-		bgcol = ((u32*)(info->pseudo_palette))[image->bg_color];
+		fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
+		bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
 	} else {
 		fgcol = image->fg_color;
 		bgcol = image->bg_color;
 	}
 
 	switch (bpp) {
-		case 8:
-			fgcol |= fgcol <<8; fgcol |= fgcol <<16;
-			bgcol |= bgcol <<8; bgcol |= bgcol <<16;
-			break;
-		case 16:
-			fgcol |= fgcol <<16;
-			bgcol |= bgcol <<16;
-			break;
-		default:
-			 break;
+	case 8:
+		fgcol |= fgcol << 8;
+		bgcol |= bgcol << 8;
+	case 16:
+		fgcol |= fgcol << 16;
+		bgcol |= bgcol << 16;
+	default:
+		break;
 	}
 
-	cyblafb_sync(info);
+	out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
+				   bpp) >> 6));
+	out32(GE60, fgcol);
+	out32(GE64, bgcol);
 
-	out32(GE60,fgcol);
-	out32(GE64,bgcol);
-	out32(GE44,0xa0000000 | 1<<20 | 1<<19);
-	out32(GE08,point(image->dx,image->dy));
-	out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1));
+	if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
+		u32 dds = ((image->width + 31) >> 5) * image->height;
+		out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+		out32(GE08, point(image->dx, 0));
+		out32(GE0C, point(image->dx + image->width - 1,
+				  image->height - 1));
+		while (dds--)
+			out32(GE9C, *pd++);
+	} else {
+		int i, j;
+		u32 ddstotal = (image->width + 31) >> 5;
+		u32 ddsleft = (2048 - image->dx + 31) >> 5;
+		u32 skipleft = ddstotal - ddsleft;
 
-	while(index < index_end) {
-		const char *p = image->data + index;
-		for(i=0;i<width_dds;i++) {
-			out32(GE9C,*(u32*)p);
-			p+=4;
-			index+=4;
+		out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+		out32(GE08, point(image->dx, 0));
+		out32(GE0C, point(2048 - 1, image->height - 1));
+		for (i = 0; i < image->height; i++) {
+			for (j = 0; j < ddsleft; j++)
+				out32(GE9C, *pd++);
+			pd += skipleft;
 		}
-		switch(width_dbs) {
-		case 0: break;
-		case 8:	out32(GE9C,*(u8*)p);
-			index+=1;
-			break;
-		case 16: out32(GE9C,*(u16*)p);
-			index+=2;
-			break;
-		case 24: out32(GE9C,*(u16*)p | *(u8*)(p+2)<<16);
-			index+=3;
-			break;
+
+		if (image->dx % 32) {
+			out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+			out32(GE08, point(2048, 0));
+			if (image->width > ddsleft << 5)
+				out32(GE0C, point(image->dx + (ddsleft << 5) -
+						  1, image->height - 1));
+			else
+				out32(GE0C, point(image->dx + image->width - 1,
+						  image->height - 1));
+			pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
+			for (i = 0; i < image->height; i++) {
+				out32(GE9C, swab32(swab32(*pd) << ((32 -
+					    (image->dx & 31)) & 31)));
+				pd += ddstotal;
+			}
+		}
+
+		if (skipleft) {
+			out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+			out32(GE08, point(image->dx + (ddsleft << 5), 0));
+			out32(GE0C, point(image->dx + image->width - 1,
+					  image->height - 1));
+			pd = (u32 *) image->data;
+			for (i = 0; i < image->height; i++) {
+				pd += ddsleft;
+				for (j = 0; j < skipleft; j++)
+					out32(GE9C, *pd++);
+			}
 		}
 	}
 }
@@ -443,7 +526,6 @@
 			     struct fb_info *info)
 {
 	int bpp = var->bits_per_pixel;
-	int s,t,maxvyres;
 
 	//
 	// we try to support 8, 16, 24 and 32 bpp modes,
@@ -453,9 +535,9 @@
 	// (This is what tridentfb does ... will be changed in the future)
 	//
 	//
-	if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
+	if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
 		bpp = 8;
-	if (bpp == 24 )
+	if (bpp == 24)
 		bpp = var->bits_per_pixel = 32;
 
 	//
@@ -472,65 +554,93 @@
 		return -EINVAL;
 
 	//
-	// xres != xres_virtual is broken, fail if such an
-	// unusual mode is requested
+	// we do not allow vclk to exceed 230 MHz. If the requested
+	// vclk is too high, we default to 200 MHz
 	//
-	if (var->xres != var->xres_virtual)
-		return -EINVAL;
+	if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
+		var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
 
 	//
-	// we do not allow vclk to exceed 230 MHz
+	// enforce (h|v)sync_len limits
 	//
-	if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
-		return -EINVAL;
+	var->hsync_len &= ~7;
+	if(var->hsync_len > 248)
+		var->hsync_len = 248;
+
+	var->vsync_len &= 15;
 
 	//
-	// calc max yres_virtual that would fit in memory
-	// and max yres_virtual that could be used for scrolling
-	// and use minimum of the results as maxvyres
+	// Enforce horizontal and vertical hardware limits.
+	// 1600x1200 is mentioned as a maximum, but higher resolutions could
+	// work with slow refresh, small margins and short sync.
 	//
-	// adjust vyres_virtual to maxvyres if necessary
-	// fail if requested yres is bigger than maxvyres
-	//
-	s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
-	t = info->fix.smem_len / (var->xres * bpp/8);
-	maxvyres = t < s ? t : s;
-	if (maxvyres < var->yres_virtual)
-		var->yres_virtual=maxvyres;
-	if (maxvyres < var->yres)
+	var->xres &= ~7;
+
+	if (((var->xres + var->left_margin + var->right_margin +
+			var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
+			((var->yres + var->upper_margin + var->lower_margin +
+			var->vsync_len) > 2047))
 		return -EINVAL;
 
-	switch (bpp) {
-		case 8:
-			var->red.offset = 0;
-			var->green.offset = 0;
-			var->blue.offset = 0;
-			var->red.length = 6;
-			var->green.length = 6;
-			var->blue.length = 6;
-			break;
-		case 16:
-			var->red.offset = 11;
-			var->green.offset = 5;
-			var->blue.offset = 0;
-			var->red.length = 5;
-			var->green.length = 6;
-			var->blue.length = 5;
-			break;
-		case 32:
-			var->red.offset = 16;
-			var->green.offset = 8;
-			var->blue.offset = 0;
-			var->red.length = 8;
-			var->green.length = 8;
-			var->blue.length = 8;
-			break;
-		default:
+	if ((var->xres > 1600) || (var->yres > 1200))
+		output("Mode %dx%d exceeds documented limits.\n",
+					   var->xres, var->yres);
+	//
+	// try to be smart about (x|y)res_virtual problems.
+	//
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+
+	if (bpp == 8 || bpp == 16) {
+		if (var->xres_virtual > 4088)
+			var->xres_virtual = 4088;
+	} else {
+		if (var->xres_virtual > 2040)
+			var->xres_virtual = 2040;
+	}
+	var->xres_virtual &= ~7;
+	while (var->xres_virtual * var->yres_virtual * bpp / 8 >
+	       info->fix.smem_len) {
+		if (var->yres_virtual > var->yres)
+			var->yres_virtual--;
+		else if (var->xres_virtual > var->xres)
+			var->xres_virtual -= 8;
+		else
 			return -EINVAL;
 	}
 
-	return 0;
+	switch (bpp) {
+	case 8:
+		var->red.offset = 0;
+		var->green.offset = 0;
+		var->blue.offset = 0;
+		var->red.length = 6;
+		var->green.length = 6;
+		var->blue.length = 6;
+		break;
+	case 16:
+		var->red.offset = 11;
+		var->green.offset = 5;
+		var->blue.offset = 0;
+		var->red.length = 5;
+		var->green.length = 6;
+		var->blue.length = 5;
+		break;
+	case 32:
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
 
+	return 0;
 }
 
 //=====================================================================
@@ -543,23 +653,25 @@
 // it, so it is also safe to be used here. BTW: datasheet CR0E on page
 // 90 really is CR1E, the real CRE is documented on page 72.
 //
+// BUT:
+//
+// As of internal version 0.60 we do not use vga panning any longer.
+// Vga panning did not allow us the use of all available video memory
+// and thus prevented ywrap scrolling. We do use the "right view"
+// register now.
+//
+//
 //=====================================================================
 
 static int cyblafb_pan_display(struct fb_var_screeninfo *var,
 			       struct fb_info *info)
 {
-	unsigned int offset;
+	KD_GRAPHICS_RETURN(0);
 
-	offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
 	info->var.xoffset = var->xoffset;
 	info->var.yoffset = var->yoffset;
-
-	write3X4(CR0D,offset & 0xFF);
-	write3X4(CR0C,(offset & 0xFF00) >> 8);
-	write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
-	write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
-	write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
-
+	out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
+		    var->xres_virtual)) * var->bits_per_pixel / 32));
 	return 0;
 }
 
@@ -578,59 +690,99 @@
 		return;
 
 	printk("\n");
-	for(i=0; i<=0xff; i++) {
-		outb(i,0x3d4);
-		printk("CR%02x=%02x ",i,inb(0x3d5));
-		if (i%16==15)
+	for (i = 0; i <= 0xff; i++) {
+		outb(i, 0x3d4);
+		printk("CR%02x=%02x ", i, inb(0x3d5));
+		if (i % 16 == 15)
 			printk("\n");
 	}
 
-	outb(0x30,0x3ce);
-	outb(inb(0x3cf) | 0x40,0x3cf);
-	for(i=0; i<=0x1f; i++) {
-		if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
-			outb(i,0x3d4);
-			printk("CR%02x=%02x ",i,inb(0x3d5));
+	outb(0x30, 0x3ce);
+	outb(inb(0x3cf) | 0x40, 0x3cf);
+	for (i = 0; i <= 0x1f; i++) {
+		if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
+		    || i == 0x16) {
+			outb(i, 0x3d4);
+			printk("CR%02x=%02x ", i, inb(0x3d5));
 		} else
 			printk("------- ");
-		if (i%16==15)
+		if (i % 16 == 15)
 			printk("\n");
 	}
-	outb(0x30,0x3ce);
-	outb(inb(0x3cf) & 0xbf,0x3cf);
+	outb(0x30, 0x3ce);
+	outb(inb(0x3cf) & 0xbf, 0x3cf);
 
 	printk("\n");
-	for(i=0; i<=0x7f; i++) {
-		outb(i,0x3ce);
-		printk("GR%02x=%02x ",i,inb(0x3cf));
-		if (i%16==15)
+	for (i = 0; i <= 0x7f; i++) {
+		outb(i, 0x3ce);
+		printk("GR%02x=%02x ", i, inb(0x3cf));
+		if (i % 16 == 15)
 			printk("\n");
 	}
 
 	printk("\n");
-	for(i=0; i<=0xff; i++) {
-		outb(i,0x3c4);
-		printk("SR%02x=%02x ",i,inb(0x3c5));
-		if (i%16==15)
+	for (i = 0; i <= 0xff; i++) {
+		outb(i, 0x3c4);
+		printk("SR%02x=%02x ", i, inb(0x3c5));
+		if (i % 16 == 15)
 			printk("\n");
 	}
 
 	printk("\n");
-	for(i=0; i <= 0x1F; i++) {
-		inb(0x3da); // next access is index!
-		outb(i,0x3c0);
-		printk("AR%02x=%02x ",i,inb(0x3c1));
-		if (i%16==15)
+	for (i = 0; i <= 0x1F; i++) {
+		inb(0x3da);	// next access is index!
+		outb(i, 0x3c0);
+		printk("AR%02x=%02x ", i, inb(0x3c1));
+		if (i % 16 == 15)
 			printk("\n");
 	}
 	printk("\n");
 
-	inb(0x3DA);			// reset internal flag to 3c0 index
-	outb(0x20,0x3C0);		// enable attr
+	inb(0x3DA);		// reset internal flag to 3c0 index
+	outb(0x20, 0x3C0);	// enable attr
 
 	return;
 }
 
+//=======================================================================
+//
+// Save State
+//
+// This function is called while a switch to KD_TEXT is in progress,
+// before any of the other functions are called.
+//
+//=======================================================================
+
+static void cyblafb_save_state(struct fb_info *info)
+{
+	struct cyblafb_par *par = info->par;
+	if (verbosity > 0)
+		output("Switching to KD_TEXT\n");
+	disabled = 0;
+	regdump(par);
+	enable_mmio();
+	return;
+}
+
+//=======================================================================
+//
+// Restore State
+//
+// This function is called while a switch to KD_GRAPHICS is in progress,
+// We have to turn on vga style panning registers again because the
+// trident driver of X does not know about GE10.
+//
+//=======================================================================
+
+static void cyblafb_restore_state(struct fb_info *info)
+{
+	if (verbosity > 0)
+		output("Switching to KD_GRAPHICS\n");
+	out32(GE10, 0);
+	disabled = 1;
+	return;
+}
+
 //======================================
 //
 // Set hardware to requested video mode
@@ -640,32 +792,34 @@
 static int cyblafb_set_par(struct fb_info *info)
 {
 	struct cyblafb_par *par = info->par;
-	u32
-	htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
-		vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
+	u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
+	    hblankend, preendfetch, vtotal, vdispend, vsyncstart,
+	    vsyncend, vblankstart, vblankend;
 	struct fb_var_screeninfo *var = &info->var;
 	int bpp = var->bits_per_pixel;
 	int i;
 
+	KD_GRAPHICS_RETURN(0);
+
 	if (verbosity > 0)
 		output("Switching to new mode: "
 		       "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
-			var->xres,var->yres,var->xres_virtual,
-			var->yres_virtual,var->bits_per_pixel,var->pixclock,
-			var->left_margin,var->right_margin,var->upper_margin,
-			var->lower_margin,var->hsync_len,var->vsync_len);
+		       var->xres, var->yres, var->xres_virtual,
+		       var->yres_virtual, var->bits_per_pixel, var->pixclock,
+		       var->left_margin, var->right_margin, var->upper_margin,
+		       var->lower_margin, var->hsync_len, var->vsync_len);
 
 	htotal = (var->xres + var->left_margin + var->right_margin +
-						 var->hsync_len) / 8 - 5;
-	hdispend = var->xres/8 - 1;
-	hsyncstart = (var->xres + var->right_margin)/8;
-	hsyncend = var->hsync_len/8;
+		  var->hsync_len) / 8 - 5;
+	hdispend = var->xres / 8 - 1;
+	hsyncstart = (var->xres + var->right_margin) / 8;
+	hsyncend = var->hsync_len / 8;
 	hblankstart = hdispend + 1;
 	hblankend = htotal + 3; // should be htotal + 5, bios does it this way
-	preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
+	preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
 
 	vtotal = var->yres + var->upper_margin + var->lower_margin +
-						 var->vsync_len - 2;
+							var->vsync_len - 2;
 	vdispend = var->yres - 1;
 	vsyncstart = var->yres + var->lower_margin;
 	vblankstart = var->yres;
@@ -674,101 +828,99 @@
 
 	enable_mmio();		// necessary! ... check X ...
 
-	write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
+	write3X4(CR11, read3X4(CR11) & 0x7F);	// unlock cr00 .. cr07
 
-	write3CE(GR30,8);
+	write3CE(GR30, 8);
 
 	if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
 
 		// stretch or center ?
 
-		out8(0x3C2,0xEB);
+		out8(0x3C2, 0xEB);
 
-		write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
+		write3CE(GR30, read3CE(GR30) | 0x81);	// shadow mode on
 
 		if (center) {
-			write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
-			write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
-		}
-		else if (stretch) {
-			write3CE(GR5D,0);
-			write3CE(GR52,(read3CE(GR52) & 0x7C) | 1);
-			write3CE(GR53,(read3CE(GR53) & 0x7C) | 1);
+			write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
+			write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
+		} else if (stretch) {
+			write3CE(GR5D, 0);
+			write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
+			write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
 		}
 
 	} else {
-		out8(0x3C2,0x2B);
-		write3CE(GR30,8);
+		out8(0x3C2, 0x2B);
+		write3CE(GR30, 8);
 	}
 
 	//
 	// Setup CRxx regs
 	//
 
-	write3X4(CR00,htotal & 0xFF);
-	write3X4(CR01,hdispend & 0xFF);
-	write3X4(CR02,hblankstart & 0xFF);
-	write3X4(CR03,hblankend & 0x1F);
-	write3X4(CR04,hsyncstart & 0xFF);
-	write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
-	write3X4(CR06,vtotal & 0xFF);
-	write3X4(CR07,(vtotal & 0x100) >> 8 |
-		      (vdispend & 0x100) >> 7 |
-		      (vsyncstart & 0x100) >> 6 |
-		      (vblankstart & 0x100) >> 5 |
-		      0x10 |
-		      (vtotal & 0x200) >> 4 |
-		      (vdispend & 0x200) >> 3 |
-		      (vsyncstart & 0x200) >> 2);
-	write3X4(CR08,0);
-	write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 |  // FIX !!!
-		      ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
-	write3X4(CR0A,0);  // Init to some reasonable default
-	write3X4(CR0B,0);  // Init to some reasonable default
-	write3X4(CR0C,0);  // Offset 0
-	write3X4(CR0D,0);  // Offset 0
-	write3X4(CR0E,0);  // Init to some reasonable default
-	write3X4(CR0F,0);  // Init to some reasonable default
-	write3X4(CR10,vsyncstart & 0xFF);
-	write3X4(CR11,(vsyncend & 0x0F));
-	write3X4(CR12,vdispend & 0xFF);
-	write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF);
-	write3X4(CR14,0x40);  // double word mode
-	write3X4(CR15,vblankstart & 0xFF);
-	write3X4(CR16,vblankend & 0xFF);
-	write3X4(CR17,0xC3);
-	write3X4(CR18,0xFF);
+	write3X4(CR00, htotal & 0xFF);
+	write3X4(CR01, hdispend & 0xFF);
+	write3X4(CR02, hblankstart & 0xFF);
+	write3X4(CR03, hblankend & 0x1F);
+	write3X4(CR04, hsyncstart & 0xFF);
+	write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
+	write3X4(CR06, vtotal & 0xFF);
+	write3X4(CR07, (vtotal & 0x100) >> 8 |
+		       (vdispend & 0x100) >> 7 |
+		       (vsyncstart & 0x100) >> 6 |
+		       (vblankstart & 0x100) >> 5 |
+		       0x10 |
+		       (vtotal & 0x200) >> 4 |
+		       (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
+	write3X4(CR08, 0);
+	write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 |	// FIX !!!
+		       ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
+	write3X4(CR0A, 0);	// Init to some reasonable default
+	write3X4(CR0B, 0);	// Init to some reasonable default
+	write3X4(CR0C, 0);	// Offset 0
+	write3X4(CR0D, 0);	// Offset 0
+	write3X4(CR0E, 0);	// Init to some reasonable default
+	write3X4(CR0F, 0);	// Init to some reasonable default
+	write3X4(CR10, vsyncstart & 0xFF);
+	write3X4(CR11, (vsyncend & 0x0F));
+	write3X4(CR12, vdispend & 0xFF);
+	write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
+	write3X4(CR14, 0x40);	// double word mode
+	write3X4(CR15, vblankstart & 0xFF);
+	write3X4(CR16, vblankend & 0xFF);
+	write3X4(CR17, 0xE3);
+	write3X4(CR18, 0xFF);
 	//	 CR19: needed for interlaced modes ... ignore it for now
-	write3X4(CR1A,0x07); // Arbitration Control Counter 1
-	write3X4(CR1B,0x07); // Arbitration Control Counter 2
-	write3X4(CR1C,0x07); // Arbitration Control Counter 3
-	write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-)
-	write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
+	write3X4(CR1A, 0x07);	// Arbitration Control Counter 1
+	write3X4(CR1B, 0x07);	// Arbitration Control Counter 2
+	write3X4(CR1C, 0x07);	// Arbitration Control Counter 3
+	write3X4(CR1D, 0x00);	// Don't know, doesn't hurt ; -)
+	write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
 	//	 CR1F: do not set, contains BIOS info about memsize
-	write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode
-	write3X4(CR21,0x20); // enable linear memory access
+	write3X4(CR20, 0x20);	// enabe wr buf, disable 16bit planar mode
+	write3X4(CR21, 0x20);	// enable linear memory access
 	//	 CR22: RO cpu latch readback
 	//	 CR23: ???
 	//	 CR24: RO AR flag state
 	//	 CR25: RAMDAC rw timing, pclk buffer tristate control ????
 	//	 CR26: ???
-	write3X4(CR27,(vdispend & 0x400) >> 6 |
-		      (vsyncstart & 0x400) >> 5 |
-		      (vblankstart & 0x400) >> 4 |
-		      (vtotal & 0x400) >> 3 |
-		      0x8);
+	write3X4(CR27, (vdispend & 0x400) >> 6 |
+		       (vsyncstart & 0x400) >> 5 |
+		       (vblankstart & 0x400) >> 4 |
+		       (vtotal & 0x400) >> 3 |
+		       0x8);
 	//	 CR28: ???
-	write3X4(CR29,(read3X4(CR29) & 0xCF) |
-		      ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4));
-	write3X4(CR2A,read3X4(CR2A) | 0x40);
-	write3X4(CR2B,(htotal & 0x100) >> 8 |
-		      (hdispend & 0x100) >> 7 |
-		      // (0x00 & 0x100) >> 6 |	 hinterlace para bit 8 ???
-		      (hsyncstart & 0x100) >> 5 |
-		      (hblankstart & 0x100) >> 4);
+	write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
+			bpp) / (4 * 16)) & 0x300) >> 4));
+	write3X4(CR2A, read3X4(CR2A) | 0x40);
+	write3X4(CR2B, (htotal & 0x100) >> 8 |
+		       (hdispend & 0x100) >> 7 |
+		       // (0x00 & 0x100) >> 6 |   hinterlace para bit 8 ???
+		       (hsyncstart & 0x100) >> 5 |
+		       (hblankstart & 0x100) >> 4);
 	//	 CR2C: ???
 	//	 CR2D: initialized in cyblafb_setup_GE()
-	write3X4(CR2F,0x92); // conservative, better signal quality
+	write3X4(CR2F, 0x92);	// conservative, better signal quality
 	//	 CR30: reserved
 	//	 CR31: reserved
 	//	 CR32: reserved
@@ -777,96 +929,116 @@
 	//	 CR35: disabled in CR36
 	//	 CR36: initialized in cyblafb_setup_GE
 	//	 CR37: i2c, ignore for now
-	write3X4(CR38,(bpp == 8) ? 0x00 :	//
-		      (bpp == 16) ? 0x05 :	// highcolor
-		      (bpp == 24) ? 0x29 :	// packed 24bit truecolor
-		      (bpp == 32) ? 0x09 : 0);	// truecolor, 16 bit pixelbus
-	write3X4(CR39,0x01 |			// MMIO enable
-		      (pcirb ? 0x02 : 0) | // pci read burst enable
-		      (pciwb ? 0x04 : 0)); // pci write burst enable
-	write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase
-		      (pcirr ? 0x40 : 0) | // pci read retry enable
-		      (pciwr ? 0x80 : 0)); // pci write retry enable
-	write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0);
-	write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
-	write3X4(CR58,0x82);	// Bios does this .... don't know more
+	write3X4(CR38, (bpp == 8) ? 0x00 :	//
+		       (bpp == 16) ? 0x05 :	// highcolor
+		       (bpp == 24) ? 0x29 :	// packed 24bit truecolor
+		       (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
+	write3X4(CR39, 0x01 |	// MMIO enable
+		       (pcirb ? 0x02 : 0) |	// pci read burst enable
+		       (pciwb ? 0x04 : 0));	// pci write burst enable
+	write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
+		       (pcirr ? 0x40 : 0) |	// pci read retry enable
+		       (pciwr ? 0x80 : 0));	// pci write retry enable
+	write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
+					    : 0);
+	write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
+	write3X4(CR58, 0x82);	// Bios does this .... don't know more
 	//
 	// Setup SRxx regs
 	//
-	write3C4(SR00,3);
-	write3C4(SR01,1);	//set char clock 8 dots wide
-	write3C4(SR02,0x0F);	//enable 4 maps needed in chain4 mode
-	write3C4(SR03,0);	//no character map select
-	write3C4(SR04,0x0E);	//memory mode: ext mem, even, chain4
+	write3C4(SR00, 3);
+	write3C4(SR01, 1);	//set char clock 8 dots wide
+	write3C4(SR02, 0x0F);	//enable 4 maps needed in chain4 mode
+	write3C4(SR03, 0);	//no character map select
+	write3C4(SR04, 0x0E);	//memory mode: ext mem, even, chain4
 
-	out8(0x3C4,0x0b);
+	out8(0x3C4, 0x0b);
 	in8(0x3C5);		// Set NEW mode
-	write3C4(SR0D,0x00);	// test ... check
+	write3C4(SR0D, 0x00);	// test ... check
 
-	set_vclk(par,(bpp==32 ? 200000000 : 100000000)/
-		 info->var.pixclock); //SR18,SR19
+	set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
+					/ info->var.pixclock);	//SR18, SR19
 
 	//
 	// Setup GRxx regs
 	//
-	write3CE(GR00,0x00);	// test ... check
-	write3CE(GR01,0x00);	// test ... check
-	write3CE(GR02,0x00);	// test ... check
-	write3CE(GR03,0x00);	// test ... check
-	write3CE(GR04,0x00);	// test ... check
-	write3CE(GR05,0x40);	// no CGA compat,allow 256 col
-	write3CE(GR06,0x05);	// graphics mode
-	write3CE(GR07,0x0F);	// planes?
-	write3CE(GR08,0xFF);	// test ... check
-	write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4
-	write3CE(GR20,0xC0);	// test ... check
-	write3CE(GR2F,0xA0);	// PCLK = VCLK, no skew,
+	write3CE(GR00, 0x00);	// test ... check
+	write3CE(GR01, 0x00);	// test ... check
+	write3CE(GR02, 0x00);	// test ... check
+	write3CE(GR03, 0x00);	// test ... check
+	write3CE(GR04, 0x00);	// test ... check
+	write3CE(GR05, 0x40);	// no CGA compat, allow 256 col
+	write3CE(GR06, 0x05);	// graphics mode
+	write3CE(GR07, 0x0F);	// planes?
+	write3CE(GR08, 0xFF);	// test ... check
+	write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
+	write3CE(GR20, 0xC0);	// test ... check
+	write3CE(GR2F, 0xA0);	// PCLK = VCLK, no skew,
 
 	//
 	// Setup ARxx regs
 	//
-	for(i = 0;i < 0x10;i++) // set AR00 .. AR0f
-		write3C0(i,i);
-	write3C0(AR10,0x41);	// graphics mode and support 256 color modes
-	write3C0(AR12,0x0F);	// planes
-	write3C0(AR13,0);	// horizontal pel panning
+	for (i = 0; i < 0x10; i++)	// set AR00 .. AR0f
+		write3C0(i, i);
+	write3C0(AR10, 0x41);	// graphics mode and support 256 color modes
+	write3C0(AR12, 0x0F);	// planes
+	write3C0(AR13, 0);	// horizontal pel panning
 	in8(0x3DA);		// reset internal flag to 3c0 index
-	out8(0x3C0,0x20);	// enable attr
+	out8(0x3C0, 0x20);	// enable attr
 
 	//
 	// Setup hidden RAMDAC command register
 	//
-	in8(0x3C8);  // these reads are
-	in8(0x3C6);  // necessary to
-	in8(0x3C6);  // unmask the RAMDAC
-	in8(0x3C6);  // command reg, otherwise
-	in8(0x3C6);  // we would write the pixelmask reg!
-	out8(0x3C6,(bpp ==  8) ? 0x00 : 	// 256 colors
-		   (bpp == 15) ? 0x10 : 	//
-		   (bpp == 16) ? 0x30 : 	// hicolor
-		   (bpp == 24) ? 0xD0 : 	// truecolor
-		   (bpp == 32) ? 0xD0 : 0);	// truecolor
+	in8(0x3C8);		// these reads are
+	in8(0x3C6);		// necessary to
+	in8(0x3C6);		// unmask the RAMDAC
+	in8(0x3C6);		// command reg, otherwise
+	in8(0x3C6);		// we would write the pixelmask reg!
+	out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
+	     (bpp == 15) ? 0x10 :	//
+	     (bpp == 16) ? 0x30 :	// hicolor
+	     (bpp == 24) ? 0xD0 :	// truecolor
+	     (bpp == 32) ? 0xD0 : 0);	// truecolor
 	in8(0x3C8);
 
 	//
 	// GR31 is not mentioned in the datasheet
 	//
 	if (displaytype == DISPLAY_FP)
-		write3CE(GR31,(read3CE(GR31) & 0x8F) |
+		write3CE(GR31, (read3CE(GR31) & 0x8F) |
 			 ((info->var.yres > 1024) ? 0x50 :
-			 (info->var.yres >   768) ? 0x30 :
-			 (info->var.yres >   600) ? 0x20 :
-			 (info->var.yres >   480) ? 0x10 : 0));
+			  (info->var.yres > 768) ? 0x30 :
+			  (info->var.yres > 600) ? 0x20 :
+			  (info->var.yres > 480) ? 0x10 : 0));
 
 	info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
 				      : FB_VISUAL_TRUECOLOR;
-	info->fix.line_length = info->var.xres * (bpp >> 3);
-	info->cmap.len = (bpp == 8) ? 256: 16;
+	info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
+	info->cmap.len = (bpp == 8) ? 256 : 16;
 
 	//
 	// init acceleration engine
 	//
-	cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel);
+	cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
+
+	//
+	// Set/clear flags to allow proper scroll mode selection.
+	//
+	if (var->xres == var->xres_virtual)
+		info->flags &= ~FBINFO_HWACCEL_XPAN;
+	else
+		info->flags |= FBINFO_HWACCEL_XPAN;
+
+	if (var->yres == var->yres_virtual)
+		info->flags &= ~FBINFO_HWACCEL_YPAN;
+	else
+		info->flags |= FBINFO_HWACCEL_YPAN;
+
+	if (info->fix.smem_len !=
+	    var->xres_virtual * var->yres_virtual * bpp / 8)
+		info->flags &= ~FBINFO_HWACCEL_YWRAP;
+	else
+		info->flags |= FBINFO_HWACCEL_YWRAP;
 
 	regdump(par);
 
@@ -885,27 +1057,27 @@
 {
 	int bpp = info->var.bits_per_pixel;
 
+	KD_GRAPHICS_RETURN(0);
+
 	if (regno >= info->cmap.len)
 		return 1;
 
 	if (bpp == 8) {
-		out8(0x3C6,0xFF);
-		out8(0x3C8,regno);
-		out8(0x3C9,red>>10);
-		out8(0x3C9,green>>10);
-		out8(0x3C9,blue>>10);
+		out8(0x3C6, 0xFF);
+		out8(0x3C8, regno);
+		out8(0x3C9, red >> 10);
+		out8(0x3C9, green >> 10);
+		out8(0x3C9, blue >> 10);
 
-	} else if (bpp == 16)				// RGB 565
-		((u32*)info->pseudo_palette)[regno] =
-			(red & 0xF800) |
-			((green & 0xFC00) >> 5) |
-			((blue & 0xF800) >> 11);
-	else if (bpp == 32)				// ARGB 8888
-		((u32*)info->pseudo_palette)[regno] =
-			((transp & 0xFF00) <<16) |
-			((red & 0xFF00) << 8) |
-			((green & 0xFF00)) |
-			((blue & 0xFF00)>>8);
+	} else if (bpp == 16)	// RGB 565
+		((u32 *) info->pseudo_palette)[regno] =
+		    (red & 0xF800) |
+		    ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+	else if (bpp == 32)	// ARGB 8888
+		((u32 *) info->pseudo_palette)[regno] =
+		    ((transp & 0xFF00) << 16) |
+		    ((red & 0xFF00) << 8) |
+		    ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
 
 	return 0;
 }
@@ -918,40 +1090,41 @@
 
 static int cyblafb_blank(int blank_mode, struct fb_info *info)
 {
-	unsigned char PMCont,DPMSCont;
+	unsigned char PMCont, DPMSCont;
+
+	KD_GRAPHICS_RETURN(0);
 
 	if (displaytype == DISPLAY_FP)
 		return 0;
 
-	out8(0x83C8,0x04); 		// DPMS Control
+	out8(0x83C8, 0x04);	// DPMS Control
 	PMCont = in8(0x83C6) & 0xFC;
 
 	DPMSCont = read3CE(GR23) & 0xFC;
 
-	switch (blank_mode)
-	{
-	case FB_BLANK_UNBLANK:       // Screen: On, HSync: On, VSync: On
-	case FB_BLANK_NORMAL:	     // Screen: Off, HSync: On, VSync: On
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:	// Screen: On, HSync: On, VSync: On
+	case FB_BLANK_NORMAL:	// Screen: Off, HSync: On, VSync: On
 		PMCont |= 0x03;
 		DPMSCont |= 0x00;
 		break;
-	case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
+	case FB_BLANK_HSYNC_SUSPEND:	// Screen: Off, HSync: Off, VSync: On
 		PMCont |= 0x02;
 		DPMSCont |= 0x01;
 		break;
-	case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
+	case FB_BLANK_VSYNC_SUSPEND:	// Screen: Off, HSync: On, VSync: Off
 		PMCont |= 0x02;
 		DPMSCont |= 0x02;
 		break;
-	case FB_BLANK_POWERDOWN:     // Screen: Off, HSync: Off, VSync: Off
+	case FB_BLANK_POWERDOWN:	// Screen: Off, HSync: Off, VSync: Off
 		PMCont |= 0x00;
 		DPMSCont |= 0x03;
 		break;
 	}
 
-	write3CE(GR23,DPMSCont);
-	out8(0x83C8,4);
-	out8(0x83C6,PMCont);
+	write3CE(GR23, DPMSCont);
+	out8(0x83C8, 4);
+	out8(0x83C6, PMCont);
 	//
 	// let fbcon do a softblank for us
 	//
@@ -959,15 +1132,18 @@
 }
 
 static struct fb_ops cyblafb_ops __devinitdata = {
-	.owner	= THIS_MODULE,
+	.owner = THIS_MODULE,
 	.fb_setcolreg = cyblafb_setcolreg,
 	.fb_pan_display = cyblafb_pan_display,
 	.fb_blank = cyblafb_blank,
 	.fb_check_var = cyblafb_check_var,
 	.fb_set_par = cyblafb_set_par,
 	.fb_fillrect = cyblafb_fillrect,
-	.fb_copyarea= cyblafb_copyarea,
+	.fb_copyarea = cyblafb_copyarea,
 	.fb_imageblit = cyblafb_imageblit,
+	.fb_sync = cyblafb_sync,
+	.fb_restore_state = cyblafb_restore_state,
+	.fb_save_state = cyblafb_save_state,
 };
 
 //==========================================================================
@@ -986,74 +1162,89 @@
 
 static int __devinit getstartupmode(struct fb_info *info)
 {
-	u32	htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
-		vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend,
-		cr00,cr01,cr02,cr03,cr04,cr05,cr2b,
-		cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27,
-		cr38,
-		sr0d,sr18,sr19,
-		gr0f,
-		fi,pxclkdiv,vclkdiv,tmp,i;
+	u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
+	    vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
+	    cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
+	    cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
+	    cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
 
 	struct modus {
-		int xres; int yres; int vyres; int bpp; int pxclk;
-		int left_margin; int right_margin; int upper_margin;
-		int lower_margin; int hsync_len; int vsync_len;
-	}  modedb[5] = {
-		{   0,	  0, 8000, 0, 0,   0,  0,  0, 0,   0,  0},
-		{ 640,	480, 3756, 0, 0, -40, 24, 17, 0, 216,  3},
-		{ 800,	600, 3221, 0, 0,  96, 24, 14, 0, 136, 11},
-		{1024,	768, 2815, 0, 0, 144, 24, 29, 0, 120,  3},
-		{1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160,  3}
+		int xres; int vxres; int yres; int vyres;
+		int bpp; int pxclk;
+		int left_margin; int right_margin;
+		int upper_margin; int lower_margin;
+		int hsync_len; int vsync_len;
+	} modedb[5] = {
+		{
+		0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
+		640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
+		800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
+		1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
+		1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
 	};
 
-	outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5);
-	outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5);
-	outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5);
-	outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5);
-	outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5);
-	outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5);
-	outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5);
-	outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5);
-	outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5);
-	outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5);
-	outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf);
+	outb(0x00, 0x3d4); cr00 = inb(0x3d5);
+	outb(0x01, 0x3d4); cr01 = inb(0x3d5);
+	outb(0x02, 0x3d4); cr02 = inb(0x3d5);
+	outb(0x03, 0x3d4); cr03 = inb(0x3d5);
+	outb(0x04, 0x3d4); cr04 = inb(0x3d5);
+	outb(0x05, 0x3d4); cr05 = inb(0x3d5);
+	outb(0x06, 0x3d4); cr06 = inb(0x3d5);
+	outb(0x07, 0x3d4); cr07 = inb(0x3d5);
+	outb(0x09, 0x3d4); cr09 = inb(0x3d5);
+	outb(0x10, 0x3d4); cr10 = inb(0x3d5);
+	outb(0x11, 0x3d4); cr11 = inb(0x3d5);
+	outb(0x12, 0x3d4); cr12 = inb(0x3d5);
+	outb(0x15, 0x3d4); cr15 = inb(0x3d5);
+	outb(0x16, 0x3d4); cr16 = inb(0x3d5);
+	outb(0x27, 0x3d4); cr27 = inb(0x3d5);
+	outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
+	outb(0x38, 0x3d4); cr38 = inb(0x3d5);
 
-	htotal	    = cr00 | (cr2b & 0x01) << 8;
-	hdispend    = cr01 | (cr2b & 0x02) << 7;
+	outb(0x0b, 0x3c4);
+	inb(0x3c5);
+
+	outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
+	outb(0x18, 0x3c4); sr18 = inb(0x3c5);
+	outb(0x19, 0x3c4); sr19 = inb(0x3c5);
+	outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
+
+	htotal = cr00 | (cr2b & 0x01) << 8;
+	hdispend = cr01 | (cr2b & 0x02) << 7;
 	hblankstart = cr02 | (cr2b & 0x10) << 4;
-	hblankend   = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
-	hsyncstart  = cr04 | (cr2b & 0x08) << 5;
-	hsyncend    = cr05 & 0x1f;
+	hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
+	hsyncstart = cr04 | (cr2b & 0x08) << 5;
+	hsyncend = cr05 & 0x1f;
 
 	modedb[0].xres = hblankstart * 8;
 	modedb[0].hsync_len = hsyncend * 8;
 	modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
 	modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
-		modedb[0].right_margin - modedb[0].hsync_len;
+	    modedb[0].right_margin - modedb[0].hsync_len;
 
-	vtotal	    = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
-			   | (cr27 & 0x80) << 3;
-	vdispend    = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
-			   | (cr27 & 0x10) << 6;
-	vsyncstart  = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
-			   | (cr27 & 0x20) << 5;
-	vsyncend    = cr11 & 0x0f;
+	vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
+	    | (cr27 & 0x80) << 3;
+	vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
+	    | (cr27 & 0x10) << 6;
+	vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
+	    | (cr27 & 0x20) << 5;
+	vsyncend = cr11 & 0x0f;
 	vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
-			   | (cr27 & 0x40) << 4;
-	vblankend   = cr16;
+	    | (cr27 & 0x40) << 4;
+	vblankend = cr16;
 
-	modedb[0].yres	       = vdispend + 1;
-	modedb[0].vsync_len    = vsyncend;
+	modedb[0].yres = vdispend + 1;
+	modedb[0].vsync_len = vsyncend;
 	modedb[0].lower_margin = vsyncstart - modedb[0].yres;
 	modedb[0].upper_margin = vtotal - modedb[0].yres -
-		modedb[0].lower_margin - modedb[0].vsync_len + 2;
+	    modedb[0].lower_margin - modedb[0].vsync_len + 2;
 
 	tmp = cr38 & 0x3c;
 	modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
-			tmp == 8 ? 32 : 8;
+	    tmp == 8 ? 32 : 8;
 
-	fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12;
+	fi = ((5864727 * (sr18 + 8)) /
+	      (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
 	pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
 	tmp = sr0d & 0x06;
 	vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
@@ -1062,10 +1253,10 @@
 	if (verbosity > 0)
 		output("detected startup mode: "
 		       "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
-		       modedb[0].xres,modedb[0].yres,modedb[0].xres,
-		       modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin,
-		       modedb[0].right_margin,modedb[0].upper_margin,
-		       modedb[0].lower_margin,modedb[0].hsync_len,
+		       modedb[0].xres, modedb[0].yres, modedb[0].xres,
+		       modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
+		       modedb[0].right_margin, modedb[0].upper_margin,
+		       modedb[0].lower_margin, modedb[0].hsync_len,
 		       modedb[0].vsync_len);
 
 	//
@@ -1073,36 +1264,39 @@
 	// do not want to do it in another way!
 	//
 
-	tryagain:
+      tryagain:
 
 	i = (mode == NULL) ? 0 :
-	    !strncmp(mode,"640x480",7) ? 1 :
-	    !strncmp(mode,"800x600",7) ? 2 :
-	    !strncmp(mode,"1024x768",8) ? 3 :
-	    !strncmp(mode,"1280x1024",9) ? 4 : 0;
+	    !strncmp(mode, "640x480", 7) ? 1 :
+	    !strncmp(mode, "800x600", 7) ? 2 :
+	    !strncmp(mode, "1024x768", 8) ? 3 :
+	    !strncmp(mode, "1280x1024", 9) ? 4 : 0;
 
 	ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
 
-	if(i==0) {
+	if (i == 0) {
 		info->var.pixclock = modedb[i].pxclk;
 		info->var.bits_per_pixel = modedb[i].bpp;
 	} else {
 		info->var.pixclock = (100000000 /
-			((modedb[i].left_margin + modedb[i].xres +
-			  modedb[i].right_margin + modedb[i].hsync_len
-			 ) * (
-			  modedb[i].upper_margin + modedb[i].yres +
-			  modedb[i].lower_margin + modedb[i].vsync_len
-			 ) *
-			  ref / 10000
-			));
+				      ((modedb[i].left_margin +
+					modedb[i].xres +
+					modedb[i].right_margin +
+					modedb[i].hsync_len) *
+				       (modedb[i].upper_margin +
+					modedb[i].yres +
+					modedb[i].lower_margin +
+					modedb[i].vsync_len) * ref / 10000));
 		info->var.bits_per_pixel = bpp;
 	}
 
 	info->var.left_margin = modedb[i].left_margin;
 	info->var.right_margin = modedb[i].right_margin;
 	info->var.xres = modedb[i].xres;
-	info->var.xres_virtual = modedb[i].xres;
+	if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
+		info->var.xres_virtual = modedb[i].vxres;
+	else
+		info->var.xres_virtual = modedb[i].xres;
 	info->var.xoffset = 0;
 	info->var.hsync_len = modedb[i].hsync_len;
 	info->var.upper_margin = modedb[i].upper_margin;
@@ -1114,33 +1308,32 @@
 	info->var.sync = 0;
 	info->var.vmode = FB_VMODE_NONINTERLACED;
 
-	if(cyblafb_check_var(&info->var,info)) {
-		// 640x480-8@75 should really never fail. One case would
+	if (cyblafb_check_var(&info->var, info)) {
+		// 640x480 - 8@75 should really never fail. One case would
 		// be fp == 1 and nativex < 640 ... give up then
-		if(i==1 && bpp == 8 && ref == 75){
+		if (i == 1 && bpp == 8 && ref == 75) {
 			output("Can't find a valid mode :-(\n");
 			return -EINVAL;
 		}
 		// Our detected mode is unlikely to fail. If it does,
-		// try 640x480-8@75 ...
-		if(i==0) {
-			mode="640x480";
-			bpp=8;
-			ref=75;
+		// try 640x480 - 8@75 ...
+		if (i == 0) {
+			mode = "640x480";
+			bpp = 8;
+			ref = 75;
 			output("Detected mode failed check_var! "
-			       "Trying 640x480-8@75\n");
+			       "Trying 640x480 - 8@75\n");
 			goto tryagain;
 		}
 		// A specified video mode failed for some reason.
 		// Try the startup mode first
 		output("Specified mode '%s' failed check! "
-			"Falling back to startup mode.\n",mode);
-		mode=NULL;
+		       "Falling back to startup mode.\n", mode);
+		mode = NULL;
 		goto tryagain;
 	}
 
 	return 0;
-
 }
 
 //========================================================
@@ -1160,21 +1353,28 @@
 	else {
 		tmp = read3X4(CR1F) & 0x0F;
 		switch (tmp) {
-			case 0x03: k = 1 * Mb; break;
-			case 0x07: k = 2 * Mb; break;
-			case 0x0F: k = 4 * Mb; break;
-			case 0x04: k = 8 * Mb; break;
-			default:
-				k = 1 * Mb;
-				output("Unknown memory size code %x in CR1F."
-				       " We default to 1 Mb for now, please"
-				       " do provide a memsize parameter!\n",
-				       tmp);
+		case 0x03:
+			k = 1 * 1024 * 1024;
+			break;
+		case 0x07:
+			k = 2 * 1024 * 1024;
+			break;
+		case 0x0F:
+			k = 4 * 1024 * 1024;
+			break;
+		case 0x04:
+			k = 8 * 1024 * 1024;
+			break;
+		default:
+			k = 1 * 1024 * 1024;
+			output("Unknown memory size code %x in CR1F."
+			       " We default to 1 Mb for now, please"
+			       " do provide a memsize parameter!\n", tmp);
 		}
 	}
 
 	if (verbosity > 0)
-		output("framebuffer size = %d Kb\n",k/Kb);
+		output("framebuffer size = %d Kb\n", k / Kb);
 	return k;
 }
 
@@ -1192,7 +1392,7 @@
 		return DISPLAY_FP;
 	if (crt)
 		return DISPLAY_CRT;
-	return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
+	return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
 }
 
 //=====================================
@@ -1203,7 +1403,7 @@
 
 static int __devinit get_nativex(void)
 {
-	int x,y,tmp;
+	int x, y, tmp;
 
 	if (nativex)
 		return nativex;
@@ -1211,29 +1411,45 @@
 	tmp = (read3CE(GR52) >> 4) & 3;
 
 	switch (tmp) {
-		case 0:  x = 1280; y = 1024; break;
-		case 2:  x = 1024; y = 768;  break;
-		case 3:  x = 800;  y = 600;  break;
-		case 4:  x = 1400; y = 1050; break;
-		case 1:
-		default: x = 640;  y = 480;  break;
+	case 0: x = 1280; y = 1024;
+		break;
+	case 2: x = 1024; y = 768;
+		break;
+	case 3: x = 800;  y = 600;
+		break;
+	case 4: x = 1400; y = 1050;
+		break;
+	case 1:
+	default:
+		x = 640; y = 480;
+		break;
 	}
 
 	if (verbosity > 0)
-		output("%dx%d flat panel found\n",x,y);
+		output("%dx%d flat panel found\n", x, y);
 	return x;
 }
 
-static int __devinit cybla_pci_probe(struct pci_dev * dev,
-				     const struct pci_device_id * id)
+static int __devinit cybla_pci_probe(struct pci_dev *dev,
+				     const struct pci_device_id *id)
 {
 	struct fb_info *info;
 	struct cyblafb_par *par;
 
-	info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev);
-
+	info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
 	if (!info)
-		goto errout_alloc;
+		goto errout_alloc_info;
+
+	info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
+	if (!info->pixmap.addr) {
+		output("allocation of pixmap buffer failed!\n");
+		goto errout_alloc_pixmap;
+	}
+	info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
+	info->pixmap.buf_align = 4;
+	info->pixmap.access_align = 32;
+	info->pixmap.flags = FB_PIXMAP_SYSTEM;
+	info->pixmap.scan_align = 4;
 
 	par = info->par;
 	par->ops = cyblafb_ops;
@@ -1246,26 +1462,31 @@
 		output("could not enable device!\n");
 		goto errout_enable;
 	}
-
 	// might already be requested by vga console or vesafb,
 	// so we do care about success
-	request_region(0x3c0,32,"cyblafb");
+	if (!request_region(0x3c0, 0x20, "cyblafb")) {
+		output("region 0x3c0/0x20 already reserved\n");
+		vesafb |= 1;
 
+	}
 	//
 	// Graphics Engine Registers
 	//
-	request_region(GEBase,0x100,"cyblafb");
+	if (!request_region(GEBase, 0x100, "cyblafb")) {
+		output("region %#x/0x100 already reserved\n", GEBase);
+		vesafb |= 2;
+	}
 
 	regdump(par);
 
 	enable_mmio();
 
 	// setup MMIO region
-	info->fix.mmio_start = pci_resource_start(dev,1);
+	info->fix.mmio_start = pci_resource_start(dev, 1);
 	info->fix.mmio_len = 0x20000;
 
 	if (!request_mem_region(info->fix.mmio_start,
-				info->fix.mmio_len,"cyblafb")) {
+				info->fix.mmio_len, "cyblafb")) {
 		output("request_mem_region failed for mmio region!\n");
 		goto errout_mmio_reqmem;
 	}
@@ -1276,18 +1497,17 @@
 		output("ioremap failed for mmio region\n");
 		goto errout_mmio_remap;
 	}
-
 	// setup framebuffer memory ... might already be requested
 	// by vesafb. Not to fail in case of an unsuccessful request
-	// is useful for the development cycle
-	info->fix.smem_start = pci_resource_start(dev,0);
+	// is useful if both are loaded.
+	info->fix.smem_start = pci_resource_start(dev, 0);
 	info->fix.smem_len = get_memsize();
 
 	if (!request_mem_region(info->fix.smem_start,
-				info->fix.smem_len,"cyblafb")) {
-		output("request_mem_region failed for smem region!\n");
-		if (!vesafb)
-			goto errout_smem_req;
+				info->fix.smem_len, "cyblafb")) {
+		output("region %#lx/%#x already reserved\n",
+		       info->fix.smem_start, info->fix.smem_len);
+		vesafb |= 4;
 	}
 
 	info->screen_base = ioremap_nocache(info->fix.smem_start,
@@ -1300,31 +1520,30 @@
 
 	displaytype = get_displaytype();
 
-	if(displaytype == DISPLAY_FP)
+	if (displaytype == DISPLAY_FP)
 		nativex = get_nativex();
 
-	//
-	// FBINFO_HWACCEL_YWRAP    .... does not work (could be made to work?)
-	// FBINFO_PARTIAL_PAN_OK   .... is not ok
-	// FBINFO_READS_FAST	   .... is necessary for optimal scrolling
-	//
-	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN
-		      | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT
-		      | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST;
+	info->flags = FBINFO_DEFAULT
+		    | FBINFO_HWACCEL_COPYAREA
+		    | FBINFO_HWACCEL_FILLRECT
+		    | FBINFO_HWACCEL_IMAGEBLIT
+		    | FBINFO_READS_FAST
+//		    | FBINFO_PARTIAL_PAN_OK
+		    | FBINFO_MISC_ALWAYS_SETPAR;
 
 	info->pseudo_palette = par->pseudo_pal;
 
-	if(getstartupmode(info))
+	if (getstartupmode(info))
 		goto errout_findmode;
 
-	fb_alloc_cmap(&info->cmap,256,0);
+	fb_alloc_cmap(&info->cmap, 256, 0);
 
 	if (register_framebuffer(info)) {
 		output("Could not register CyBla framebuffer\n");
 		goto errout_register;
 	}
 
-	pci_set_drvdata(dev,info);
+	pci_set_drvdata(dev, info);
 
 	//
 	// normal exit and error paths
@@ -1332,23 +1551,24 @@
 
 	return 0;
 
- errout_register:
- errout_findmode:
+      errout_register:
+      errout_findmode:
 	iounmap(info->screen_base);
- errout_smem_remap:
-	release_mem_region(info->fix.smem_start,
-			   info->fix.smem_len);
- errout_smem_req:
+      errout_smem_remap:
+	if (!(vesafb & 4))
+		release_mem_region(info->fix.smem_start, info->fix.smem_len);
 	iounmap(io_virt);
- errout_mmio_remap:
-	release_mem_region(info->fix.mmio_start,
-			   info->fix.mmio_len);
- errout_mmio_reqmem:
-//	release_region(0x3c0,32);
- errout_enable:
+      errout_mmio_remap:
+	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+      errout_mmio_reqmem:
+	if (!(vesafb & 1))
+		release_region(0x3c0, 32);
+      errout_enable:
+	kfree(info->pixmap.addr);
+      errout_alloc_pixmap:
 	framebuffer_release(info);
- errout_alloc:
-	output("CyblaFB version %s aborting init.\n",VERSION);
+      errout_alloc_info:
+	output("CyblaFB version %s aborting init.\n", VERSION);
 	return -ENODEV;
 }
 
@@ -1359,35 +1579,41 @@
 	unregister_framebuffer(info);
 	iounmap(io_virt);
 	iounmap(info->screen_base);
-	release_mem_region(info->fix.smem_start,info->fix.smem_len);
-	release_mem_region(info->fix.mmio_start,info->fix.mmio_len);
+	if (!(vesafb & 4))
+		release_mem_region(info->fix.smem_start, info->fix.smem_len);
+	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
 	fb_dealloc_cmap(&info->cmap);
+	if (!(vesafb & 2))
+		release_region(GEBase, 0x100);
+	if (!(vesafb & 1))
+		release_region(0x3c0, 32);
+	kfree(info->pixmap.addr);
 	framebuffer_release(info);
-	output("CyblaFB version %s normal exit.\n",VERSION);
+	output("CyblaFB version %s normal exit.\n", VERSION);
 }
 
 //
 // List of boards that we are trying to support
 //
 static struct pci_device_id cybla_devices[] = {
-	{PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0,}
 };
 
-MODULE_DEVICE_TABLE(pci,cybla_devices);
+MODULE_DEVICE_TABLE(pci, cybla_devices);
 
 static struct pci_driver cyblafb_pci_driver = {
-	.name		= "cyblafb",
-	.id_table	= cybla_devices,
-	.probe		= cybla_pci_probe,
-	.remove 	= __devexit_p(cybla_pci_remove)
+	.name = "cyblafb",
+	.id_table = cybla_devices,
+	.probe = cybla_pci_probe,
+	.remove = __devexit_p(cybla_pci_remove)
 };
 
 //=============================================================
 //
 // kernel command line example:
 //
-//	video=cyblafb:1280x1024,bpp=16,ref=50 ...
+//	video=cyblafb:1280x1024, bpp=16, ref=50 ...
 //
 // modprobe command line example:
 //
@@ -1401,45 +1627,44 @@
 	char *options = NULL;
 	char *opt;
 
-	if (fb_get_options("cyblafb",&options))
+	if (fb_get_options("cyblafb", &options))
 		return -ENODEV;
 
 	if (options && *options)
-		while((opt = strsep(&options,",")) != NULL ) {
-			if (!*opt) continue;
-			else if (!strncmp(opt,"bpp=",4))
-				bpp = simple_strtoul(opt+4,NULL,0);
-			else if (!strncmp(opt,"ref=",4))
-				ref = simple_strtoul(opt+4,NULL,0);
-			else if (!strncmp(opt,"fp",2))
+		while ((opt = strsep(&options, ",")) != NULL) {
+			if (!*opt)
+				continue;
+			else if (!strncmp(opt, "bpp=", 4))
+				bpp = simple_strtoul(opt + 4, NULL, 0);
+			else if (!strncmp(opt, "ref=", 4))
+				ref = simple_strtoul(opt + 4, NULL, 0);
+			else if (!strncmp(opt, "fp", 2))
 				displaytype = DISPLAY_FP;
-			else if (!strncmp(opt,"crt",3))
+			else if (!strncmp(opt, "crt", 3))
 				displaytype = DISPLAY_CRT;
-			else if (!strncmp(opt,"nativex=",8))
-				nativex = simple_strtoul(opt+8,NULL,0);
-			else if (!strncmp(opt,"center",6))
+			else if (!strncmp(opt, "nativex=", 8))
+				nativex = simple_strtoul(opt + 8, NULL, 0);
+			else if (!strncmp(opt, "center", 6))
 				center = 1;
-			else if (!strncmp(opt,"stretch",7))
+			else if (!strncmp(opt, "stretch", 7))
 				stretch = 1;
-			else if (!strncmp(opt,"pciwb=",6))
-				pciwb = simple_strtoul(opt+6,NULL,0);
-			else if (!strncmp(opt,"pcirb=",6))
-				pcirb = simple_strtoul(opt+6,NULL,0);
-			else if (!strncmp(opt,"pciwr=",6))
-				pciwr = simple_strtoul(opt+6,NULL,0);
-			else if (!strncmp(opt,"pcirr=",6))
-				pcirr = simple_strtoul(opt+6,NULL,0);
-			else if (!strncmp(opt,"memsize=",8))
-				memsize = simple_strtoul(opt+8,NULL,0);
-			else if (!strncmp(opt,"verbosity=",10))
-				verbosity = simple_strtoul(opt+10,NULL,0);
-			else if (!strncmp(opt,"vesafb",6))
-				vesafb = 1;
+			else if (!strncmp(opt, "pciwb=", 6))
+				pciwb = simple_strtoul(opt + 6, NULL, 0);
+			else if (!strncmp(opt, "pcirb=", 6))
+				pcirb = simple_strtoul(opt + 6, NULL, 0);
+			else if (!strncmp(opt, "pciwr=", 6))
+				pciwr = simple_strtoul(opt + 6, NULL, 0);
+			else if (!strncmp(opt, "pcirr=", 6))
+				pcirr = simple_strtoul(opt + 6, NULL, 0);
+			else if (!strncmp(opt, "memsize=", 8))
+				memsize = simple_strtoul(opt + 8, NULL, 0);
+			else if (!strncmp(opt, "verbosity=", 10))
+				verbosity = simple_strtoul(opt + 10, NULL, 0);
 			else
 				mode = opt;
 		}
 #endif
-	output("CyblaFB version %s initializing\n",VERSION);
+	output("CyblaFB version %s initializing\n", VERSION);
 	return pci_module_init(&cyblafb_pci_driver);
 }
 
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 00d87f5..ad1434e 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -223,6 +223,7 @@
 int __init offb_init(void)
 {
 	struct device_node *dp = NULL, *boot_disp = NULL;
+
 #if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
 	struct device_node *macos_display = NULL;
 #endif
@@ -234,60 +235,54 @@
 	if (boot_infos != 0) {
 		unsigned long addr =
 		    (unsigned long) boot_infos->dispDeviceBase;
+		u32 *addrp;
+		u64 daddr, dsize;
+		unsigned int flags;
+
 		/* find the device node corresponding to the macos display */
 		while ((dp = of_find_node_by_type(dp, "display"))) {
 			int i;
-			/*
-			 * Grrr...  It looks like the MacOS ATI driver
-			 * munges the assigned-addresses property (but
-			 * the AAPL,address value is OK).
-			 */
-			if (strncmp(dp->name, "ATY,", 4) == 0
-			    && dp->n_addrs == 1) {
-				unsigned int *ap =
-				    (unsigned int *) get_property(dp,
-								  "AAPL,address",
-								  NULL);
-				if (ap != NULL) {
-					dp->addrs[0].address = *ap;
-					dp->addrs[0].size = 0x01000000;
-				}
-			}
 
 			/*
-			 * The LTPro on the Lombard powerbook has no addresses
-			 * on the display nodes, they are on their parent.
+			 * Look for an AAPL,address property first.
 			 */
-			if (dp->n_addrs == 0
-			    && device_is_compatible(dp, "ATY,264LTPro")) {
-				int na;
-				unsigned int *ap = (unsigned int *)
-				    get_property(dp, "AAPL,address", &na);
-				if (ap != 0)
-					for (na /= sizeof(unsigned int);
-					     na > 0; --na, ++ap)
-						if (*ap <= addr
-						    && addr <
-						    *ap + 0x1000000)
-							goto foundit;
+			unsigned int na;
+			unsigned int *ap =
+				(unsigned int *)get_property(dp, "AAPL,address",
+							     &na);
+			if (ap != 0) {
+				for (na /= sizeof(unsigned int); na > 0;
+				     --na, ++ap)
+					if (*ap <= addr &&
+					    addr < *ap + 0x1000000) {
+						macos_display = dp;
+						goto foundit;
+					}
 			}
 
 			/*
 			 * See if the display address is in one of the address
 			 * ranges for this display.
 			 */
-			for (i = 0; i < dp->n_addrs; ++i) {
-				if (dp->addrs[i].address <= addr
-				    && addr <
-				    dp->addrs[i].address +
-				    dp->addrs[i].size)
+			i = 0;
+			for (;;) {
+				addrp = of_get_address(dp, i++, &dsize, &flags);
+				if (addrp == NULL)
 					break;
+				if (!(flags & IORESOURCE_MEM))
+					continue;
+				daddr = of_translate_address(dp, addrp);
+				if (daddr == OF_BAD_ADDR)
+					continue;
+				if (daddr <= addr && addr < (daddr + dsize)) {
+					macos_display = dp;
+					goto foundit;
+				}
 			}
-			if (i < dp->n_addrs) {
-			      foundit:
+		foundit:
+			if (macos_display) {
 				printk(KERN_INFO "MacOS display is %s\n",
 				       dp->full_name);
-				macos_display = dp;
 				break;
 			}
 		}
@@ -326,8 +321,10 @@
 	int *pp, i;
 	unsigned int len;
 	int width = 640, height = 480, depth = 8, pitch;
-	unsigned int rsize, *up;
-	unsigned long address = 0;
+	unsigned int flags, rsize, *up;
+	u64 address = OF_BAD_ADDR;
+	u32 *addrp;
+	u64 asize;
 
 	if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
 	    && len == sizeof(int))
@@ -363,7 +360,7 @@
                                break;
 	       }
                if (pdev) {
-                       for (i = 0; i < 6 && address == 0; i++) {
+                       for (i = 0; i < 6 && address == OF_BAD_ADDR; i++) {
                                if ((pci_resource_flags(pdev, i) &
 				    IORESOURCE_MEM) &&
 				   (pci_resource_len(pdev, i) >= rsize))
@@ -374,27 +371,33 @@
         }
 #endif /* CONFIG_PCI */
 
-	if (address == 0 &&
-	    (up = (unsigned *) get_property(dp, "address", &len)) != NULL &&
-	    len == sizeof(unsigned))
-		address = (u_long) * up;
-	if (address == 0) {
-		for (i = 0; i < dp->n_addrs; ++i)
-			if (dp->addrs[i].size >=
-			    pitch * height * depth / 8)
-				break;
-		if (i >= dp->n_addrs) {
+       /* This one is dodgy, we may drop it ... */
+       if (address == OF_BAD_ADDR &&
+	   (up = (unsigned *) get_property(dp, "address", &len)) != NULL &&
+	   len == sizeof(unsigned int))
+	       address = (u64) * up;
+
+       if (address == OF_BAD_ADDR) {
+	       for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
+			    != NULL; i++) {
+		       if (!(flags & IORESOURCE_MEM))
+			       continue;
+		       if (asize >= pitch * height * depth / 8)
+			       break;
+	       }
+		if (addrp == NULL) {
 			printk(KERN_ERR
 			       "no framebuffer address found for %s\n",
 			       dp->full_name);
 			return;
 		}
-
-		address = (u_long) dp->addrs[i].address;
-
-#ifdef CONFIG_PPC64
-		address += ((struct pci_dn *)dp->data)->phb->pci_mem_offset;
-#endif
+		address = of_translate_address(dp, addrp);
+		if (address == OF_BAD_ADDR) {
+			printk(KERN_ERR
+			       "can't translate framebuffer address for %s\n",
+			       dp->full_name);
+			return;
+		}
 
 		/* kludge for valkyrie */
 		if (strcmp(dp->name, "valkyrie") == 0)
@@ -459,7 +462,9 @@
 
 	par->cmap_type = cmap_unknown;
 	if (depth == 8) {
-		/* XXX kludge for ati */
+
+		/* Palette hacks disabled for now */
+#if 0
 		if (dp && !strncmp(name, "ATY,Rage128", 11)) {
 			unsigned long regbase = dp->addrs[2].address;
 			par->cmap_adr = ioremap(regbase, 0x1FFF);
@@ -490,6 +495,7 @@
 			par->cmap_adr = ioremap(regbase + 0x6000, 0x1000);
 			par->cmap_type = cmap_gxt2000;
 		}
+#endif
 		fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
 		    : FB_VISUAL_STATIC_PSEUDOCOLOR;
 	} else
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index ca4082a..335e374 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -69,6 +69,8 @@
 	unsigned long			total_vram;
 	int				clktype;
 	int				dactype;
+
+	struct resource			rsrc_fb, rsrc_reg;
 };
 
 /*
@@ -97,9 +99,6 @@
  * Interface used by the world
  */
 
-int platinumfb_init(void);
-int platinumfb_setup(char*);
-
 static struct fb_ops platinumfb_ops = {
 	.owner =	THIS_MODULE,
 	.fb_check_var	= platinumfb_check_var,
@@ -138,13 +137,15 @@
 
 	init = platinum_reg_init[pinfo->vmode-1];
 	
-	if (pinfo->vmode == 13 && pinfo->cmode > 0)
-		offset = 0x10;
+ 	if ((pinfo->vmode == VMODE_832_624_75) && (pinfo->cmode > CMODE_8))
+  		offset = 0x10;
+
 	info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
 	info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
 	info->fix.visual = (pinfo->cmode == CMODE_8) ?
 		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
-	info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) + offset;
+ 	info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode)
+		+ offset;
 	printk("line_length: %x\n", info->fix.line_length);
 	return 0;
 }
@@ -221,7 +222,9 @@
 static inline int platinum_vram_reqd(int video_mode, int color_mode)
 {
 	return vmode_attrs[video_mode-1].vres *
-	       (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20) +0x1000;
+	       (vmode_attrs[video_mode-1].hres * (1<<color_mode) +
+		((video_mode == VMODE_832_624_75) &&
+		 (color_mode > CMODE_8)) ? 0x10 : 0x20) + 0x1000;
 }
 
 #define STORE_D2(a, d) { \
@@ -481,7 +484,7 @@
 /* 
  * Parse user speficied options (`video=platinumfb:')
  */
-int __init platinumfb_setup(char *options)
+static int __init platinumfb_setup(char *options)
 {
 	char *this_opt;
 
@@ -522,19 +525,15 @@
 #define invalidate_cache(addr)
 #endif
 
-static int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match)
+static int __devinit platinumfb_probe(struct of_device* odev,
+				      const struct of_device_id *match)
 {
 	struct device_node	*dp = odev->node;
 	struct fb_info		*info;
 	struct fb_info_platinum	*pinfo;
-	unsigned long		addr, size;
 	volatile __u8		*fbuffer;
-	int			i, bank0, bank1, bank2, bank3, rc;
+	int			bank0, bank1, bank2, bank3, rc;
 
-	if (dp->n_addrs != 2) {
-		printk(KERN_ERR "expecting 2 address for platinum (got %d)", dp->n_addrs);
-		return -ENXIO;
-	}
 	printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n");
 
 	info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
@@ -542,26 +541,39 @@
 		return -ENOMEM;
 	pinfo = info->par;
 
-	/* Map in frame buffer and registers */
-	for (i = 0; i < dp->n_addrs; ++i) {
-		addr = dp->addrs[i].address;
-		size = dp->addrs[i].size;
-		/* Let's assume we can request either all or nothing */
-		if (!request_mem_region(addr, size, "platinumfb")) {
-			framebuffer_release(info);
-			return -ENXIO;
-		}
-		if (size >= 0x400000) {
-			/* frame buffer - map only 4MB */
-			pinfo->frame_buffer_phys = addr;
-			pinfo->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
-			pinfo->base_frame_buffer = pinfo->frame_buffer;
-		} else {
-			/* registers */
-			pinfo->platinum_regs_phys = addr;
-			pinfo->platinum_regs = ioremap(addr, size);
-		}
+	if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
+	    of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) {
+		printk(KERN_ERR "platinumfb: Can't get resources\n");
+		framebuffer_release(info);
+		return -ENXIO;
 	}
+	if (!request_mem_region(pinfo->rsrc_reg.start,
+				pinfo->rsrc_reg.start -
+				pinfo->rsrc_reg.end + 1,
+				"platinumfb registers")) {
+		framebuffer_release(info);
+		return -ENXIO;
+	}
+	if (!request_mem_region(pinfo->rsrc_fb.start,
+				pinfo->rsrc_fb.start
+				- pinfo->rsrc_fb.end + 1,
+				"platinumfb framebuffer")) {
+		release_mem_region(pinfo->rsrc_reg.start,
+				   pinfo->rsrc_reg.end -
+				   pinfo->rsrc_reg.start + 1);
+		framebuffer_release(info);
+		return -ENXIO;
+	}
+
+	/* frame buffer - map only 4MB */
+	pinfo->frame_buffer_phys = pinfo->rsrc_fb.start;
+	pinfo->frame_buffer = __ioremap(pinfo->rsrc_fb.start, 0x400000,
+					_PAGE_WRITETHRU);
+	pinfo->base_frame_buffer = pinfo->frame_buffer;
+
+	/* registers */
+	pinfo->platinum_regs_phys = pinfo->rsrc_reg.start;
+	pinfo->platinum_regs = ioremap(pinfo->rsrc_reg.start, 0x1000);
 
 	pinfo->cmap_regs_phys = 0xf301b000;	/* XXX not in prom? */
 	request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap");
@@ -624,18 +636,16 @@
 {
 	struct fb_info		*info = dev_get_drvdata(&odev->dev);
 	struct fb_info_platinum	*pinfo = info->par;
-	struct device_node *dp = odev->node;
-	unsigned long addr, size;
-	int i;
 	
         unregister_framebuffer (info);
 	
 	/* Unmap frame buffer and registers */
-	for (i = 0; i < dp->n_addrs; ++i) {
-		addr = dp->addrs[i].address;
-		size = dp->addrs[i].size;
-		release_mem_region(addr, size);
-	}
+	release_mem_region(pinfo->rsrc_fb.start,
+			   pinfo->rsrc_fb.end -
+			   pinfo->rsrc_fb.start + 1);
+	release_mem_region(pinfo->rsrc_reg.start,
+			   pinfo->rsrc_reg.end -
+			   pinfo->rsrc_reg.start + 1);
 	iounmap(pinfo->frame_buffer);
 	iounmap(pinfo->platinum_regs);
 	release_mem_region(pinfo->cmap_regs_phys, 0x1000);
@@ -662,7 +672,7 @@
 	.remove		= platinumfb_remove,
 };
 
-int __init platinumfb_init(void)
+static int __init platinumfb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
@@ -676,7 +686,7 @@
 	return 0;
 }
 
-void __exit platinumfb_exit(void)
+static void __exit platinumfb_exit(void)
 {
 	of_unregister_driver(&platinum_driver);	
 }
diff --git a/drivers/video/platinumfb.h b/drivers/video/platinumfb.h
index 2834fc1..f6bd77c 100644
--- a/drivers/video/platinumfb.h
+++ b/drivers/video/platinumfb.h
@@ -158,7 +158,9 @@
 /* 832x624, 75Hz (13) */
 static struct platinum_regvals platinum_reg_init_13 = {
 	0x70,
-	{ 864, 1680, 3360 },	/* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+	{ 864, 1680, 3344 },	/* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB,
+				 * and we use 3344 instead of 3360 to fit in 2Mb
+				 */
 	{ 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
 	  0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
 	  0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index ce97ec8..2bdeb4b 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -342,19 +342,19 @@
 #else /* ppc (!CONFIG_MAC) */
 	{
 		struct device_node *dp;
+		struct resource r;
 
-		dp = find_devices("valkyrie");
+		dp = of_find_node_by_name(NULL, "valkyrie");
 		if (dp == 0)
 			return 0;
 
-		if (dp->n_addrs != 1) {
-			printk(KERN_ERR "expecting 1 address for valkyrie (got %d)\n",
-			       dp->n_addrs);
+		if (of_address_to_resource(dp, 0, &r)) {
+			printk(KERN_ERR "can't find address for valkyrie\n");
 			return 0;
 		}
 
-		frame_buffer_phys = dp->addrs[0].address;
-		cmap_regs_phys = dp->addrs[0].address+0x304000;
+		frame_buffer_phys = r.start;
+		cmap_regs_phys = r.start + 0x304000;
 		flags = _PAGE_WRITETHRU;
 	}
 #endif /* ppc (!CONFIG_MAC) */
diff --git a/fs/bio.c b/fs/bio.c
index dfe242a..7b30695 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -126,6 +126,7 @@
 inline void bio_init(struct bio *bio)
 {
 	bio->bi_next = NULL;
+	bio->bi_bdev = NULL;
 	bio->bi_flags = 1 << BIO_UPTODATE;
 	bio->bi_rw = 0;
 	bio->bi_vcnt = 0;
diff --git a/include/asm-powerpc/abs_addr.h b/include/asm-powerpc/abs_addr.h
index 1841510..c5c3259 100644
--- a/include/asm-powerpc/abs_addr.h
+++ b/include/asm-powerpc/abs_addr.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_ABS_ADDR_H
 #define _ASM_POWERPC_ABS_ADDR_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 
@@ -70,4 +71,5 @@
 #define iseries_hv_addr(virtaddr)	\
 	(0x8000000000000000 | virt_to_abs(virtaddr))
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_ABS_ADDR_H */
diff --git a/include/asm-powerpc/agp.h b/include/asm-powerpc/agp.h
index 885b463..e5ccaca 100644
--- a/include/asm-powerpc/agp.h
+++ b/include/asm-powerpc/agp.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_AGP_H
 #define _ASM_POWERPC_AGP_H
+#ifdef __KERNEL__
 
 #include <asm/io.h>
 
@@ -18,4 +19,5 @@
 #define free_gatt_pages(table, order)	\
 	free_pages((unsigned long)(table), (order))
 
+#endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_AGP_H */
diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h
index 8b133ef..8e64be0 100644
--- a/include/asm-powerpc/asm-compat.h
+++ b/include/asm-powerpc/asm-compat.h
@@ -1,7 +1,6 @@
 #ifndef _ASM_POWERPC_ASM_COMPAT_H
 #define _ASM_POWERPC_ASM_COMPAT_H
 
-#include <linux/config.h>
 #include <asm/types.h>
 
 #ifdef __ASSEMBLY__
@@ -41,6 +40,7 @@
 
 #endif
 
+#ifdef __KERNEL__
 #ifdef CONFIG_IBM405_ERR77
 /* Erratum #77 on the 405 means we need a sync or dcbt before every
  * stwcx.  The old ATOMIC_SYNC_FIX covered some but not all of this.
@@ -51,5 +51,6 @@
 #define PPC405_ERR77(ra,rb)
 #define PPC405_ERR77_SYNC
 #endif
+#endif
 
 #endif /* _ASM_POWERPC_ASM_COMPAT_H */
diff --git a/include/asm-powerpc/bootx.h b/include/asm-powerpc/bootx.h
new file mode 100644
index 0000000..57b82e3
--- /dev/null
+++ b/include/asm-powerpc/bootx.h
@@ -0,0 +1,171 @@
+/*
+ * This file describes the structure passed from the BootX application
+ * (for MacOS) when it is used to boot Linux.
+ *
+ * Written by Benjamin Herrenschmidt.
+ */
+
+
+#ifndef __ASM_BOOTX_H__
+#define __ASM_BOOTX_H__
+
+#include <asm/types.h>
+
+#ifdef macintosh
+#include <Types.h>
+#include "linux_type_defs.h"
+#endif
+
+#ifdef macintosh
+/* All this requires PowerPC alignment */
+#pragma options align=power
+#endif
+
+/* On kernel entry:
+ *
+ * r3 = 0x426f6f58    ('BooX')
+ * r4 = pointer to boot_infos
+ * r5 = NULL
+ *
+ * Data and instruction translation disabled, interrupts
+ * disabled, kernel loaded at physical 0x00000000 on PCI
+ * machines (will be different on NuBus).
+ */
+
+#define BOOT_INFO_VERSION               5
+#define BOOT_INFO_COMPATIBLE_VERSION    1
+
+/* Bit in the architecture flag mask. More to be defined in
+   future versions. Note that either BOOT_ARCH_PCI or
+   BOOT_ARCH_NUBUS is set. The other BOOT_ARCH_NUBUS_xxx are
+   set additionally when BOOT_ARCH_NUBUS is set.
+ */
+#define BOOT_ARCH_PCI                   0x00000001UL
+#define BOOT_ARCH_NUBUS                 0x00000002UL
+#define BOOT_ARCH_NUBUS_PDM             0x00000010UL
+#define BOOT_ARCH_NUBUS_PERFORMA        0x00000020UL
+#define BOOT_ARCH_NUBUS_POWERBOOK       0x00000040UL
+
+/*  Maximum number of ranges in phys memory map */
+#define MAX_MEM_MAP_SIZE				26
+
+/* This is the format of an element in the physical memory map. Note that
+   the map is optional and current BootX will only build it for pre-PCI
+   machines */
+typedef struct boot_info_map_entry
+{
+    __u32       physAddr;                /* Physical starting address */
+    __u32       size;                    /* Size in bytes */
+} boot_info_map_entry_t;
+
+
+/* Here are the boot informations that are passed to the bootstrap
+ * Note that the kernel arguments and the device tree are appended
+ * at the end of this structure. */
+typedef struct boot_infos
+{
+    /* Version of this structure */
+    __u32       version;
+    /* backward compatible down to version: */
+    __u32       compatible_version;
+
+    /* NEW (vers. 2) this holds the current _logical_ base addr of
+       the frame buffer (for use by early boot message) */
+    __u8*       logicalDisplayBase;
+
+    /* NEW (vers. 4) Apple's machine identification */
+    __u32       machineID;
+
+    /* NEW (vers. 4) Detected hw architecture */
+    __u32       architecture;
+
+    /* The device tree (internal addresses relative to the beginning of the tree,
+     * device tree offset relative to the beginning of this structure).
+     * On pre-PCI macintosh (BOOT_ARCH_PCI bit set to 0 in architecture), this
+     * field is 0.
+     */
+    __u32       deviceTreeOffset;        /* Device tree offset */
+    __u32       deviceTreeSize;          /* Size of the device tree */
+
+    /* Some infos about the current MacOS display */
+    __u32       dispDeviceRect[4];       /* left,top,right,bottom */
+    __u32       dispDeviceDepth;         /* (8, 16 or 32) */
+    __u8*       dispDeviceBase;          /* base address (physical) */
+    __u32       dispDeviceRowBytes;      /* rowbytes (in bytes) */
+    __u32       dispDeviceColorsOffset;  /* Colormap (8 bits only) or 0 (*) */
+    /* Optional offset in the registry to the current
+     * MacOS display. (Can be 0 when not detected) */
+     __u32      dispDeviceRegEntryOffset;
+
+    /* Optional pointer to boot ramdisk (offset from this structure) */
+    __u32       ramDisk;
+    __u32       ramDiskSize;             /* size of ramdisk image */
+
+    /* Kernel command line arguments (offset from this structure) */
+    __u32       kernelParamsOffset;
+
+    /* ALL BELOW NEW (vers. 4) */
+
+    /* This defines the physical memory. Valid with BOOT_ARCH_NUBUS flag
+       (non-PCI) only. On PCI, memory is contiguous and it's size is in the
+       device-tree. */
+    boot_info_map_entry_t
+    	        physMemoryMap[MAX_MEM_MAP_SIZE]; /* Where the phys memory is */
+    __u32       physMemoryMapSize;               /* How many entries in map */
+
+
+    /* The framebuffer size (optional, currently 0) */
+    __u32       frameBufferSize;         /* Represents a max size, can be 0. */
+
+    /* NEW (vers. 5) */
+
+    /* Total params size (args + colormap + device tree + ramdisk) */
+    __u32       totalParamsSize;
+
+} boot_infos_t;
+
+#ifdef __KERNEL__
+/* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index
+ * is represented by 3 short words containing a 16 bits (unsigned) color
+ * component. Later versions may contain the gamma table for direct-color
+ * devices here.
+ */
+#define BOOTX_COLORTABLE_SIZE    (256UL*3UL*2UL)
+
+/* BootX passes the device-tree using a format that comes from earlier
+ * ppc32 kernels. This used to match what is in prom.h, but not anymore
+ * so we now define it here
+ */
+struct bootx_dt_prop {
+	u32	name;
+	int	length;
+	u32	value;
+	u32	next;
+};
+
+struct bootx_dt_node {
+	u32	unused0;
+	u32	unused1;
+	u32	phandle;	/* not really available */
+	u32	unused2;
+	u32	unused3;
+	u32	unused4;
+	u32	unused5;
+	u32	full_name;
+	u32	properties;
+	u32	parent;
+	u32	child;
+	u32	sibling;
+	u32	next;
+	u32	allnext;
+};
+
+extern void bootx_init(unsigned long r4, unsigned long phys);
+
+#endif /* __KERNEL__ */
+
+#ifdef macintosh
+#pragma options align=reset
+#endif
+
+#endif
diff --git a/include/asm-powerpc/btext.h b/include/asm-powerpc/btext.h
index 71cce36..906f46e 100644
--- a/include/asm-powerpc/btext.h
+++ b/include/asm-powerpc/btext.h
@@ -7,21 +7,22 @@
 #define __PPC_BTEXT_H
 #ifdef __KERNEL__
 
-extern void btext_clearscreen(void);
-extern void btext_flushscreen(void);
-
-extern int boot_text_mapped;
-
-extern int btext_initialize(struct device_node *np);
-
-extern void map_boot_text(void);
-extern void init_boot_display(void);
+extern int btext_find_display(int allow_nonstdout);
 extern void btext_update_display(unsigned long phys, int width, int height,
 				 int depth, int pitch);
+extern void btext_setup_display(int width, int height, int depth, int pitch,
+				unsigned long address);
+extern void btext_prepare_BAT(void);
+extern void btext_unmap(void);
 
 extern void btext_drawchar(char c);
 extern void btext_drawstring(const char *str);
 extern void btext_drawhex(unsigned long v);
+extern void btext_drawtext(const char *c, unsigned int len);
+
+extern void btext_clearscreen(void);
+extern void btext_flushscreen(void);
+extern void btext_flushline(void);
 
 #endif /* __KERNEL__ */
 #endif /* __PPC_BTEXT_H */
diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h
index b001ecb..99817a8 100644
--- a/include/asm-powerpc/bug.h
+++ b/include/asm-powerpc/bug.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_BUG_H
 #define _ASM_POWERPC_BUG_H
+#ifdef __KERNEL__
 
 #include <asm/asm-compat.h>
 /*
@@ -67,4 +68,5 @@
 
 #include <asm-generic/bug.h>
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_BUG_H */
diff --git a/include/asm-powerpc/checksum.h b/include/asm-powerpc/checksum.h
index d8354d8..609ecbb 100644
--- a/include/asm-powerpc/checksum.h
+++ b/include/asm-powerpc/checksum.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_CHECKSUM_H
 #define _ASM_POWERPC_CHECKSUM_H
+#ifdef __KERNEL__
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -129,4 +130,5 @@
 }
 
 #endif
+#endif /* __KERNEL__ */
 #endif
diff --git a/include/asm-powerpc/compat.h b/include/asm-powerpc/compat.h
index 4db4360..accb80c 100644
--- a/include/asm-powerpc/compat.h
+++ b/include/asm-powerpc/compat.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_COMPAT_H
 #define _ASM_POWERPC_COMPAT_H
+#ifdef __KERNEL__
 /*
  * Architecture specific compatibility types
  */
@@ -202,4 +203,5 @@
 	compat_ulong_t __unused6;
 };
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_COMPAT_H */
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index d1cfa3f..ef6ead3 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -1,7 +1,6 @@
 #ifndef __ASM_POWERPC_CPUTABLE_H
 #define __ASM_POWERPC_CPUTABLE_H
 
-#include <linux/config.h>
 #include <asm/asm-compat.h>
 
 #define PPC_FEATURE_32			0x80000000
@@ -28,10 +27,17 @@
  * via the mkdefs mechanism.
  */
 struct cpu_spec;
-struct op_powerpc_model;
 
 typedef	void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
 
+enum powerpc_oprofile_type {
+	INVALID = 0,
+	RS64 = 1,
+	POWER4 = 2,
+	G4 = 3,
+	BOOKE = 4,
+};
+
 struct cpu_spec {
 	/* CPU is matched via (PVR & pvr_mask) == pvr_value */
 	unsigned int	pvr_mask;
@@ -57,7 +63,7 @@
 	char		*oprofile_cpu_type;
 
 	/* Processor specific oprofile operations */
-	struct op_powerpc_model *oprofile_model;
+	enum powerpc_oprofile_type oprofile_type;
 };
 
 extern struct cpu_spec		*cur_cpu_spec;
@@ -106,6 +112,7 @@
 #define CPU_FTR_LOCKLESS_TLBIE		ASM_CONST(0x0000040000000000)
 #define CPU_FTR_MMCRA_SIHV		ASM_CONST(0x0000080000000000)
 #define CPU_FTR_CI_LARGE_PAGE		ASM_CONST(0x0000100000000000)
+#define CPU_FTR_PAUSE_ZERO		ASM_CONST(0x0000200000000000)
 #else
 /* ensure on 32b processors the flags are available for compiling but
  * don't do anything */
@@ -305,12 +312,18 @@
 	    CPU_FTR_MMCRA_SIHV,
 	CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
 	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
-	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT,
+	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT |
+	    CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO,
 	CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
 	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2,
 #endif
 
 	CPU_FTRS_POSSIBLE =
+#ifdef __powerpc64__
+	    CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |
+	    CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL |
+            CPU_FTR_CI_LARGE_PAGE |
+#else
 #if CLASSIC_PPC
 	    CPU_FTRS_PPC601 | CPU_FTRS_603 | CPU_FTRS_604 | CPU_FTRS_740_NOTAU |
 	    CPU_FTRS_740 | CPU_FTRS_750 | CPU_FTRS_750FX1 |
@@ -344,14 +357,14 @@
 #ifdef CONFIG_E500
 	    CPU_FTRS_E500 | CPU_FTRS_E500_2 |
 #endif
-#ifdef __powerpc64__
-	    CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |
-	    CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL |
-            CPU_FTR_CI_LARGE_PAGE |
-#endif
+#endif /* __powerpc64__ */
 	    0,
 
 	CPU_FTRS_ALWAYS =
+#ifdef __powerpc64__
+	    CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &
+	    CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &
+#else
 #if CLASSIC_PPC
 	    CPU_FTRS_PPC601 & CPU_FTRS_603 & CPU_FTRS_604 & CPU_FTRS_740_NOTAU &
 	    CPU_FTRS_740 & CPU_FTRS_750 & CPU_FTRS_750FX1 &
@@ -385,10 +398,7 @@
 #ifdef CONFIG_E500
 	    CPU_FTRS_E500 & CPU_FTRS_E500_2 &
 #endif
-#ifdef __powerpc64__
-	    CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &
-	    CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &
-#endif
+#endif /* __powerpc64__ */
 	    CPU_FTRS_POSSIBLE,
 };
 
diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h
index 82cd4a9..1938d6a 100644
--- a/include/asm-powerpc/current.h
+++ b/include/asm-powerpc/current.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_CURRENT_H
 #define _ASM_POWERPC_CURRENT_H
+#ifdef __KERNEL__
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -24,4 +25,5 @@
 
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_CURRENT_H */
diff --git a/include/asm-powerpc/delay.h b/include/asm-powerpc/delay.h
index 54fe1f4..057a609 100644
--- a/include/asm-powerpc/delay.h
+++ b/include/asm-powerpc/delay.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_DELAY_H
 #define _ASM_POWERPC_DELAY_H
+#ifdef __KERNEL__
 
 /*
  * Copyright 1996, Paul Mackerras.
@@ -16,4 +17,5 @@
 extern void __delay(unsigned long loops);
 extern void udelay(unsigned long usecs);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DELAY_H */
diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h
index a96e574..837756a 100644
--- a/include/asm-powerpc/dma-mapping.h
+++ b/include/asm-powerpc/dma-mapping.h
@@ -6,6 +6,7 @@
  */
 #ifndef _ASM_DMA_MAPPING_H
 #define _ASM_DMA_MAPPING_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -282,4 +283,5 @@
 	int		(*dac_dma_supported)(struct device *dev, u64 mask);
 };
 
+#endif /* __KERNEL__ */
 #endif	/* _ASM_DMA_MAPPING_H */
diff --git a/include/asm-powerpc/dma.h b/include/asm-powerpc/dma.h
index 926378d..4bb57fe 100644
--- a/include/asm-powerpc/dma.h
+++ b/include/asm-powerpc/dma.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_DMA_H
 #define _ASM_POWERPC_DMA_H
+#ifdef __KERNEL__
 
 /*
  * Defines for using and allocating dma channels.
@@ -387,4 +388,5 @@
 
 #endif	/* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */
 
+#endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_DMA_H */
diff --git a/include/asm-powerpc/eeh.h b/include/asm-powerpc/eeh.h
index f8633aa..4395b7b 100644
--- a/include/asm-powerpc/eeh.h
+++ b/include/asm-powerpc/eeh.h
@@ -19,6 +19,7 @@
 
 #ifndef _PPC64_EEH_H
 #define _PPC64_EEH_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <linux/init.h>
@@ -57,6 +58,7 @@
  * to finish the eeh setup for this device.
  */
 void eeh_add_device_early(struct device_node *);
+void eeh_add_device_tree_early(struct device_node *);
 void eeh_add_device_late(struct pci_dev *);
 
 /**
@@ -72,6 +74,15 @@
 void eeh_remove_device(struct pci_dev *);
 
 /**
+ * eeh_remove_device_recursive - undo EEH for device & children.
+ * @dev: pci device to be removed
+ *
+ * As above, this removes the device; it also removes child
+ * pci devices as well.
+ */
+void eeh_remove_bus_device(struct pci_dev *);
+
+/**
  * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
  *
  * If this macro yields TRUE, the caller relays to eeh_check_failure()
@@ -107,6 +118,9 @@
 
 static inline void eeh_remove_device(struct pci_dev *dev) { }
 
+static inline void eeh_add_device_tree_early(struct device_node *dn) { }
+
+static inline void eeh_remove_bus_device(struct pci_dev *dev) { }
 #define EEH_POSSIBLE_ERROR(val, type) (0)
 #define EEH_IO_ERROR_VALUE(size) (-1UL)
 #endif /* CONFIG_EEH */
@@ -363,4 +377,5 @@
 		eeh_check_failure((void __iomem *)(port), *(u32*)buf);
 }
 
+#endif /* __KERNEL__ */
 #endif /* _PPC64_EEH_H */
diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h
index d168a30..5e11a00 100644
--- a/include/asm-powerpc/eeh_event.h
+++ b/include/asm-powerpc/eeh_event.h
@@ -20,6 +20,7 @@
 
 #ifndef ASM_PPC64_EEH_EVENT_H
 #define ASM_PPC64_EEH_EVENT_H
+#ifdef __KERNEL__
 
 /** EEH event -- structure holding pci controller data that describes
  *  a change in the isolation status of a PCI slot.  A pointer
@@ -49,4 +50,5 @@
                             int reset_state,
                             int time_unavail);
 
+#endif /* __KERNEL__ */
 #endif /* ASM_PPC64_EEH_EVENT_H */
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index 3dcd65e..c5a635d 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -1,7 +1,10 @@
 #ifndef _ASM_POWERPC_ELF_H
 #define _ASM_POWERPC_ELF_H
 
+#ifdef __KERNEL__
 #include <linux/sched.h>	/* for task_struct */
+#endif
+
 #include <asm/types.h>
 #include <asm/ptrace.h>
 #include <asm/cputable.h>
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
index 12fabbc..f804b34 100644
--- a/include/asm-powerpc/firmware.h
+++ b/include/asm-powerpc/firmware.h
@@ -98,6 +98,12 @@
 extern firmware_feature_t firmware_features_table[];
 #endif
 
+extern void system_reset_fwnmi(void);
+extern void machine_check_fwnmi(void);
+
+/* This is true if we are using the firmware NMI handler (typically LPAR) */
+extern int fwnmi_active;
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_FIRMWARE_H */
diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h
index 64276a3..e258778 100644
--- a/include/asm-powerpc/floppy.h
+++ b/include/asm-powerpc/floppy.h
@@ -9,6 +9,7 @@
  */
 #ifndef __ASM_POWERPC_FLOPPY_H
 #define __ASM_POWERPC_FLOPPY_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <asm/machdep.h>
@@ -102,4 +103,5 @@
 
 #define EXTRA_FLOPPY_PARAMS
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_FLOPPY_H */
diff --git a/include/asm-powerpc/grackle.h b/include/asm-powerpc/grackle.h
index 563c7a5..bd7812a 100644
--- a/include/asm-powerpc/grackle.h
+++ b/include/asm-powerpc/grackle.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_GRACKLE_H
+#define _ASM_POWERPC_GRACKLE_H
+#ifdef __KERNEL__
 /*
  * Functions for setting up and using a MPC106 northbridge
  */
@@ -5,3 +8,5 @@
 #include <asm/pci-bridge.h>
 
 extern void setup_grackle(struct pci_controller *hose);
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_GRACKLE_H */
diff --git a/include/asm-powerpc/hardirq.h b/include/asm-powerpc/hardirq.h
index 3b3e3b4..288e14d 100644
--- a/include/asm-powerpc/hardirq.h
+++ b/include/asm-powerpc/hardirq.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_HARDIRQ_H
 #define _ASM_POWERPC_HARDIRQ_H
+#ifdef __KERNEL__
 
 #include <asm/irq.h>
 #include <asm/bug.h>
@@ -24,4 +25,5 @@
 	BUG();
 }
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HARDIRQ_H */
diff --git a/include/asm-powerpc/heathrow.h b/include/asm-powerpc/heathrow.h
index 22ac179..93f5495 100644
--- a/include/asm-powerpc/heathrow.h
+++ b/include/asm-powerpc/heathrow.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_HEATHROW_H
+#define _ASM_POWERPC_HEATHROW_H
+#ifdef __KERNEL__
 /*
  * heathrow.h: definitions for using the "Heathrow" I/O controller chip.
  *
@@ -60,3 +63,5 @@
 /* Looks like Heathrow has some sort of GPIOs as well... */
 #define HRW_GPIO_MODEM_RESET	0x6d
 
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_HEATHROW_H */
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index d36da61..da7af5a 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_HVCALL_H
 #define _ASM_POWERPC_HVCALL_H
+#ifdef __KERNEL__
 
 #define HVSC			.long 0x44000022
 
@@ -170,4 +171,5 @@
 		      unsigned long *out4);
 
 #endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HVCALL_H */
diff --git a/include/asm-powerpc/hvconsole.h b/include/asm-powerpc/hvconsole.h
index 6da93ce..34daf7b 100644
--- a/include/asm-powerpc/hvconsole.h
+++ b/include/asm-powerpc/hvconsole.h
@@ -21,6 +21,7 @@
 
 #ifndef _PPC64_HVCONSOLE_H
 #define _PPC64_HVCONSOLE_H
+#ifdef __KERNEL__
 
 /*
  * This is the max number of console adapters that can/will be found as
@@ -46,4 +47,5 @@
 						 struct hv_ops *ops);
 /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
 extern int __devexit hvc_remove(struct hvc_struct *hp);
+#endif /* __KERNEL__ */
 #endif /* _PPC64_HVCONSOLE_H */
diff --git a/include/asm-powerpc/hvcserver.h b/include/asm-powerpc/hvcserver.h
index aecba96..67d7da3 100644
--- a/include/asm-powerpc/hvcserver.h
+++ b/include/asm-powerpc/hvcserver.h
@@ -21,6 +21,7 @@
 
 #ifndef _PPC64_HVCSERVER_H
 #define _PPC64_HVCSERVER_H
+#ifdef __KERNEL__
 
 #include <linux/list.h>
 
@@ -54,4 +55,5 @@
 		uint32_t p_partition_ID, uint32_t p_unit_address);
 extern int hvcs_free_connection(uint32_t unit_address);
 
+#endif /* __KERNEL__ */
 #endif /* _PPC64_HVCSERVER_H */
diff --git a/include/asm-powerpc/i8259.h b/include/asm-powerpc/i8259.h
index fc4bfee..0392159 100644
--- a/include/asm-powerpc/i8259.h
+++ b/include/asm-powerpc/i8259.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_I8259_H
 #define _ASM_POWERPC_I8259_H
+#ifdef __KERNEL__
 
 #include <linux/irq.h>
 
@@ -9,4 +10,5 @@
 extern int i8259_irq(struct pt_regs *regs);
 extern int i8259_irq_cascade(struct pt_regs *regs, void *unused);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_I8259_H */
diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
new file mode 100644
index 0000000..7a42723
--- /dev/null
+++ b/include/asm-powerpc/ibmebus.h
@@ -0,0 +1,85 @@
+/*
+ * IBM PowerPC eBus Infrastructure Support.
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *  Heiko J Schick <schickhj@de.ibm.com>
+ *    
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB 
+ * BSD. 
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met: 
+ *
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer. 
+ *
+ * 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. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#ifndef _ASM_EBUS_H
+#define _ASM_EBUS_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <asm/of_device.h>
+
+extern struct dma_mapping_ops ibmebus_dma_ops;
+extern struct bus_type ibmebus_bus_type;
+
+struct ibmebus_dev {	
+	char *name;
+	struct of_device ofdev;
+};
+
+struct ibmebus_driver {	
+	char *name;
+	struct of_device_id *id_table;
+	int (*probe) (struct ibmebus_dev *dev, const struct of_device_id *id);
+	int (*remove) (struct ibmebus_dev *dev);
+	struct device_driver driver;
+};
+
+int ibmebus_register_driver(struct ibmebus_driver *drv);
+void ibmebus_unregister_driver(struct ibmebus_driver *drv);
+
+int ibmebus_request_irq(struct ibmebus_dev *dev,
+			u32 ist, 
+			irqreturn_t (*handler)(int, void*, struct pt_regs *),
+			unsigned long irq_flags, const char * devname,
+			void *dev_id);
+void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id);
+
+static inline struct ibmebus_driver *to_ibmebus_driver(struct device_driver *drv)
+{
+	return container_of(drv, struct ibmebus_driver, driver);
+}
+
+static inline struct ibmebus_dev *to_ibmebus_dev(struct device *dev)
+{
+	return container_of(dev, struct ibmebus_dev, ofdev.dev);
+}
+
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_IBMEBUS_H */
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 48938d8..68efbea 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_IO_H
 #define _ASM_POWERPC_IO_H
+#ifdef __KERNEL__
 
 /* 
  * This program is free software; you can redistribute it and/or
@@ -186,7 +187,6 @@
 #define IO_SPACE_LIMIT ~(0UL)
 
 
-#ifdef __KERNEL__
 extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr,
 		     	      unsigned long size, unsigned long flags);
 extern void __iomem *__ioremap(unsigned long address, unsigned long size,
@@ -256,8 +256,6 @@
  */
 #define BIO_VMERGE_BOUNDARY	0
 
-#endif /* __KERNEL__ */
-
 static inline void iosync(void)
 {
         __asm__ __volatile__ ("sync" : : : "memory");
@@ -405,8 +403,6 @@
 #include <asm/eeh.h>
 #endif
 
-#ifdef __KERNEL__
-
 /**
  *	check_signature		-	find BIOS signatures
  *	@io_addr: mmio address to check
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
index f89f060..8a8393e 100644
--- a/include/asm-powerpc/iommu.h
+++ b/include/asm-powerpc/iommu.h
@@ -20,6 +20,7 @@
 
 #ifndef _ASM_IOMMU_H
 #define _ASM_IOMMU_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <asm/types.h>
@@ -56,7 +57,7 @@
 
 /* Walks all buses and creates iommu tables */
 extern void iommu_setup_pSeries(void);
-extern void iommu_setup_u3(void);
+extern void iommu_setup_dart(void);
 
 /* Frees table for an individual device node */
 extern void iommu_free_table(struct device_node *dn);
@@ -104,7 +105,7 @@
 
 extern void iommu_init_early_pSeries(void);
 extern void iommu_init_early_iSeries(void);
-extern void iommu_init_early_u3(void);
+extern void iommu_init_early_dart(void);
 
 #ifdef CONFIG_PCI
 extern void pci_iommu_init(void);
@@ -113,6 +114,7 @@
 static inline void pci_iommu_init(void) { }
 #endif
 
-extern void alloc_u3_dart_table(void);
+extern void alloc_dart_table(void);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_IOMMU_H */
diff --git a/include/asm-ppc/ipic.h b/include/asm-powerpc/ipic.h
similarity index 100%
rename from include/asm-ppc/ipic.h
rename to include/asm-powerpc/ipic.h
diff --git a/include/asm-powerpc/iseries/it_lp_reg_save.h b/include/asm-powerpc/iseries/it_lp_reg_save.h
index 288044b..81824e1 100644
--- a/include/asm-powerpc/iseries/it_lp_reg_save.h
+++ b/include/asm-powerpc/iseries/it_lp_reg_save.h
@@ -81,4 +81,6 @@
 	u8	xRsvd3[176];	// Reserved			350-3FF
 };
 
+extern struct ItLpRegSave iseries_reg_save[];
+
 #endif /* _ITLPREGSAVE_H */
diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h
index 9dcbac6..7c16265 100644
--- a/include/asm-powerpc/kdebug.h
+++ b/include/asm-powerpc/kdebug.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_KDEBUG_H
 #define _ASM_POWERPC_KDEBUG_H
+#ifdef __KERNEL__
 
 /* nearly identical to x86_64/i386 code */
 
@@ -39,4 +40,5 @@
 	return notifier_call_chain(&powerpc_die_chain, val, &args);
 }
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_KDEBUG_H */
diff --git a/include/asm-powerpc/kdump.h b/include/asm-powerpc/kdump.h
new file mode 100644
index 0000000..a87aed0
--- /dev/null
+++ b/include/asm-powerpc/kdump.h
@@ -0,0 +1,13 @@
+#ifndef _PPC64_KDUMP_H
+#define _PPC64_KDUMP_H
+
+/* How many bytes to reserve at zero for kdump. The reserve limit should
+ * be greater or equal to the trampoline's end address. */
+#define KDUMP_RESERVE_LIMIT	0x8000
+
+#define KDUMP_TRAMPOLINE_START	0x0100
+#define KDUMP_TRAMPOLINE_END	0x3000
+
+extern void kdump_setup(void);
+
+#endif /* __PPC64_KDUMP_H */
diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h
index c72ffc7..4263af3 100644
--- a/include/asm-powerpc/kexec.h
+++ b/include/asm-powerpc/kexec.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_KEXEC_H
 #define _ASM_POWERPC_KEXEC_H
+#ifdef __KERNEL__
 
 /*
  * Maximum page that is mapped directly into kernel memory.
@@ -30,8 +31,12 @@
 #define KEXEC_ARCH KEXEC_ARCH_PPC
 #endif
 
+#define HAVE_ARCH_COPY_OLDMEM_PAGE
+
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_KEXEC
+
 #define MAX_NOTE_BYTES 1024
 typedef u32 note_buf_t[MAX_NOTE_BYTES / sizeof(u32)];
 
@@ -41,10 +46,18 @@
 extern void kexec_smp_wait(void);	/* get and clear naca physid, wait for
 					  master to copy new code to 0 */
 extern void __init kexec_setup(void);
-#else
+extern int crashing_cpu;
+extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
+#endif /* __powerpc64 __ */
+
 struct kimage;
-extern void machine_kexec_simple(struct kimage *image);
-#endif
+struct pt_regs;
+extern void default_machine_kexec(struct kimage *image);
+extern int default_machine_kexec_prepare(struct kimage *image);
+extern void default_machine_crash_shutdown(struct pt_regs *regs);
+
+#endif /* !CONFIG_KEXEC */
 
 #endif /* ! __ASSEMBLY__ */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_KEXEC_H */
diff --git a/include/asm-powerpc/keylargo.h b/include/asm-powerpc/keylargo.h
index a669a3f..d8520ef 100644
--- a/include/asm-powerpc/keylargo.h
+++ b/include/asm-powerpc/keylargo.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_KEYLARGO_H
+#define _ASM_POWERPC_KEYLARGO_H
+#ifdef __KERNEL__
 /*
  * keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
  *
@@ -232,10 +235,12 @@
 #define K2_FCR1_I2S0_RESET		0x00000800
 #define K2_FCR1_I2S0_CLK_ENABLE_BIT	0x00001000
 #define K2_FCR1_I2S0_ENABLE    		0x00002000
-
 #define K2_FCR1_PCI1_CLK_ENABLE		0x00004000
 #define K2_FCR1_FW_CLK_ENABLE		0x00008000
 #define K2_FCR1_FW_RESET_N		0x00010000
+#define K2_FCR1_I2S1_CELL_ENABLE	0x00020000
+#define K2_FCR1_I2S1_CLK_ENABLE_BIT	0x00080000
+#define K2_FCR1_I2S1_ENABLE		0x00100000
 #define K2_FCR1_GMAC_CLK_ENABLE		0x00400000
 #define K2_FCR1_GMAC_POWER_DOWN		0x00800000
 #define K2_FCR1_GMAC_RESET_N		0x01000000
@@ -246,3 +251,11 @@
 #define K2_FCR1_UATA_RESET_N		0x40000000
 #define K2_FCR1_UATA_CHOOSE_CLK66	0x80000000
 
+/* Shasta definitions */
+#define SH_FCR1_I2S2_CELL_ENABLE	0x00000010
+#define SH_FCR1_I2S2_CLK_ENABLE_BIT	0x00000040
+#define SH_FCR1_I2S2_ENABLE		0x00000080
+#define SH_FCR3_I2S2_CLK18_ENABLE	0x00008000
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_KEYLARGO_H */
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 6cd0a3b..0654f79 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_KPROBES_H
 #define _ASM_POWERPC_KPROBES_H
+#ifdef __KERNEL__
 /*
  *  Kernel Probes (KProbes)
  *
@@ -78,4 +79,5 @@
 	return 0;
 }
 #endif
+#endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_KPROBES_H */
diff --git a/include/asm-powerpc/lmb.h b/include/asm-powerpc/lmb.h
index ea0afe3..d3546c4 100644
--- a/include/asm-powerpc/lmb.h
+++ b/include/asm-powerpc/lmb.h
@@ -1,5 +1,6 @@
 #ifndef _PPC64_LMB_H
 #define _PPC64_LMB_H
+#ifdef __KERNEL__
 
 /*
  * Definitions for talking to the Open Firmware PROM on
@@ -78,4 +79,5 @@
 	       lmb_size_pages(type, region_nr);
 }
 
+#endif /* __KERNEL__ */
 #endif /* _PPC64_LMB_H */
diff --git a/include/asm-powerpc/lppaca.h b/include/asm-powerpc/lppaca.h
index c1bedab..ff82ea7 100644
--- a/include/asm-powerpc/lppaca.h
+++ b/include/asm-powerpc/lppaca.h
@@ -18,6 +18,7 @@
  */
 #ifndef _ASM_POWERPC_LPPACA_H
 #define _ASM_POWERPC_LPPACA_H
+#ifdef __KERNEL__
 
 //=============================================================================
 //
@@ -128,4 +129,5 @@
 	u8	pmc_save_area[256];	// PMC interrupt Area           x00-xFF
 };
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_LPPACA_H */
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index c011abb..5348b82 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -27,6 +27,9 @@
 struct iommu_table;
 struct rtc_time;
 struct file;
+#ifdef CONFIG_KEXEC
+struct kimage;
+#endif
 
 #ifdef CONFIG_SMP
 struct smp_ops_t {
@@ -131,7 +134,7 @@
 	void		(*nvram_sync)(void);
 
 	/* Exception handlers */
-	void		(*system_reset_exception)(struct pt_regs *regs);
+	int		(*system_reset_exception)(struct pt_regs *regs);
 	int 		(*machine_check_exception)(struct pt_regs *regs);
 
 	/* Motherboard/chipset features. This is a kind of general purpose
@@ -207,19 +210,19 @@
 
 	/* this is for modules, since _machine can be a define -- Cort */
 	int ppc_machine;
+#endif /* CONFIG_PPC32 */
 
-#ifdef CONFIG_KEXEC
 	/* Called to shutdown machine specific hardware not already controlled
 	 * by other drivers.
-	 * XXX Should we move this one out of kexec scope?
 	 */
 	void (*machine_shutdown)(void);
 
+#ifdef CONFIG_KEXEC
 	/* Called to do the minimal shutdown needed to run a kexec'd kernel
 	 * to run successfully.
 	 * XXX Should we move this one out of kexec scope?
 	 */
-	void (*machine_crash_shutdown)(void);
+	void (*machine_crash_shutdown)(struct pt_regs *regs);
 
 	/* Called to do what every setup is needed on image and the
 	 * reboot code buffer. Returns 0 on success.
@@ -237,7 +240,6 @@
 	 */
 	void (*machine_kexec)(struct kimage *image);
 #endif /* CONFIG_KEXEC */
-#endif /* CONFIG_PPC32 */
 };
 
 extern void default_idle(void);
diff --git a/include/asm-powerpc/macio.h b/include/asm-powerpc/macio.h
index b553dd4..3a6cb1a 100644
--- a/include/asm-powerpc/macio.h
+++ b/include/asm-powerpc/macio.h
@@ -1,5 +1,6 @@
 #ifndef __MACIO_ASIC_H__
 #define __MACIO_ASIC_H__
+#ifdef __KERNEL__
 
 #include <asm/of_device.h>
 
@@ -137,4 +138,5 @@
 extern int macio_register_driver(struct macio_driver *);
 extern void macio_unregister_driver(struct macio_driver *);
 
+#endif /* __KERNEL__ */
 #endif /* __MACIO_ASIC_H__ */
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 29b0bb0..d096d9e 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_MMU_H_
 #define _ASM_POWERPC_MMU_H_
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/mmu.h>
@@ -33,7 +34,8 @@
 
 /* Location of cpu0's segment table */
 #define STAB0_PAGE	0x6
-#define STAB0_PHYS_ADDR	(STAB0_PAGE<<12)
+#define STAB0_OFFSET	(STAB0_PAGE << 12)
+#define STAB0_PHYS_ADDR	(STAB0_OFFSET + PHYSICAL_START)
 
 #ifndef __ASSEMBLY__
 extern char initial_stab[];
@@ -394,7 +396,12 @@
 #define VSID_SCRAMBLE(pvsid)	(((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
 #define KERNEL_VSID(ea)		VSID_SCRAMBLE(GET_ESID(ea))
 
+/* Physical address used by some IO functions */
+typedef unsigned long phys_addr_t;
+
+
 #endif /* __ASSEMBLY */
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MMU_H_ */
diff --git a/include/asm-powerpc/mmu_context.h b/include/asm-powerpc/mmu_context.h
index ea6798c..1b8a25f 100644
--- a/include/asm-powerpc/mmu_context.h
+++ b/include/asm-powerpc/mmu_context.h
@@ -1,5 +1,6 @@
 #ifndef __ASM_POWERPC_MMU_CONTEXT_H
 #define __ASM_POWERPC_MMU_CONTEXT_H
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/mmu_context.h>
@@ -86,4 +87,5 @@
 }
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_MMU_CONTEXT_H */
diff --git a/include/asm-powerpc/mmzone.h b/include/asm-powerpc/mmzone.h
index 54958d6..88d70ba 100644
--- a/include/asm-powerpc/mmzone.h
+++ b/include/asm-powerpc/mmzone.h
@@ -6,6 +6,7 @@
  */
 #ifndef _ASM_MMZONE_H_
 #define _ASM_MMZONE_H_
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 
@@ -47,4 +48,5 @@
 extern int __init early_pfn_to_nid(unsigned long pfn);
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-powerpc/module.h b/include/asm-powerpc/module.h
index 7ecd05e..584fabf 100644
--- a/include/asm-powerpc/module.h
+++ b/include/asm-powerpc/module.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_MODULE_H
 #define _ASM_POWERPC_MODULE_H
+#ifdef __KERNEL__
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -74,4 +75,5 @@
 void sort_ex_table(struct exception_table_entry *start,
 		   struct exception_table_entry *finish);
 
+#endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_MODULE_H */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index 7083d1f..6b9e781 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_MPIC_H
 #define _ASM_POWERPC_MPIC_H
+#ifdef __KERNEL__
 
 #include <linux/irq.h>
 
@@ -117,7 +118,9 @@
 struct mpic_irq_fixup
 {
 	u8 __iomem	*base;
-	unsigned int   irq;
+	u8 __iomem	*applebase;
+	u32		data;
+	unsigned int	index;
 };
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
@@ -284,4 +287,5 @@
 /* global mpic for pSeries */
 extern struct mpic *pSeries_mpic;
 
+#endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_MPIC_H */
diff --git a/include/asm-powerpc/numnodes.h b/include/asm-powerpc/numnodes.h
index 795533a..e138eda 100644
--- a/include/asm-powerpc/numnodes.h
+++ b/include/asm-powerpc/numnodes.h
@@ -1,7 +1,9 @@
 #ifndef _ASM_POWERPC_MAX_NUMNODES_H
 #define _ASM_POWERPC_MAX_NUMNODES_H
+#ifdef __KERNEL__
 
 /* Max 16 Nodes */
 #define NODES_SHIFT	4
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MAX_NUMNODES_H */
diff --git a/include/asm-powerpc/nvram.h b/include/asm-powerpc/nvram.h
index 24bd8c2..f3563e1 100644
--- a/include/asm-powerpc/nvram.h
+++ b/include/asm-powerpc/nvram.h
@@ -55,6 +55,7 @@
 	char name[12];
 };
 
+#ifdef __KERNEL__
 struct nvram_partition {
 	struct list_head partition;
 	struct nvram_header header;
@@ -69,6 +70,7 @@
 
 extern int pSeries_nvram_init(void);
 extern int mmio_nvram_init(void);
+#endif /* __KERNEL__ */
 
 /* PowerMac specific nvram stuffs */
 
@@ -78,6 +80,7 @@
 	pmac_nvram_NR		/* MacOS Name Registry partition */
 };
 
+#ifdef __KERNEL__
 /* Return partition offset in nvram */
 extern int	pmac_get_partition(int partition);
 
@@ -91,6 +94,7 @@
 /* Normal access to NVRAM */
 extern unsigned char nvram_read_byte(int i);
 extern void nvram_write_byte(unsigned char c, int i);
+#endif
 
 /* Some offsets in XPRAM */
 #define PMAC_XPRAM_MACHINE_LOC	0xe4
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index ddb16aa..6249a7c 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_OF_DEVICE_H
 #define _ASM_POWERPC_OF_DEVICE_H
+#ifdef __KERNEL__
 
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
@@ -61,4 +62,5 @@
 						   struct device *parent);
 extern void of_release_dev(struct device *dev);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OF_DEVICE_H */
diff --git a/include/asm-powerpc/ohare.h b/include/asm-powerpc/ohare.h
index 023b597..0d030f9 100644
--- a/include/asm-powerpc/ohare.h
+++ b/include/asm-powerpc/ohare.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_OHARE_H
+#define _ASM_POWERPC_OHARE_H
+#ifdef __KERNEL__
 /*
  * ohare.h: definitions for using the "O'Hare" I/O controller chip.
  *
@@ -46,3 +49,6 @@
  * Contributed by Harry Eaton.
  */
 #define STARMAX_FEATURES	0xbeff7a
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_OHARE_H */
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 8013cd2..338e6a7 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -11,6 +11,7 @@
 
 #ifndef _ASM_POWERPC_OPROFILE_IMPL_H
 #define _ASM_POWERPC_OPROFILE_IMPL_H
+#ifdef __KERNEL__
 
 #define OP_MAX_COUNTER 8
 
@@ -22,24 +23,22 @@
 	unsigned long enabled;
 	unsigned long event;
 	unsigned long count;
+	/* Classic doesn't support per-counter user/kernel selection */
 	unsigned long kernel;
-#ifdef __powerpc64__
-	/* We dont support per counter user/kernel selection */
-#endif
 	unsigned long user;
 	unsigned long unit_mask;
 };
 
 /* System-wide configuration as set via oprofilefs.  */
 struct op_system_config {
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
 	unsigned long mmcr0;
 	unsigned long mmcr1;
 	unsigned long mmcra;
 #endif
 	unsigned long enable_kernel;
 	unsigned long enable_user;
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
 	unsigned long backtrace_spinlocks;
 #endif
 };
@@ -49,9 +48,7 @@
 	void (*reg_setup) (struct op_counter_config *,
 			   struct op_system_config *,
 			   int num_counters);
-#ifdef __powerpc64__
 	void (*cpu_setup) (void *);
-#endif
 	void (*start) (struct op_counter_config *);
 	void (*stop) (void);
 	void (*handle_interrupt) (struct pt_regs *,
@@ -59,10 +56,19 @@
 	int num_counters;
 };
 
-#ifdef __powerpc64__
+#ifdef CONFIG_FSL_BOOKE
+extern struct op_powerpc_model op_model_fsl_booke;
+#else /* Otherwise, it's classic */
+
+#ifdef CONFIG_PPC64
 extern struct op_powerpc_model op_model_rs64;
 extern struct op_powerpc_model op_model_power4;
 
+#else /* Otherwise, CONFIG_PPC32 */
+extern struct op_powerpc_model op_model_7450;
+#endif
+
+/* All the classic PPC parts use these */
 static inline unsigned int ctr_read(unsigned int i)
 {
 	switch(i) {
@@ -78,10 +84,14 @@
 		return mfspr(SPRN_PMC5);
 	case 5:
 		return mfspr(SPRN_PMC6);
+
+/* No PPC32 chip has more than 6 so far */
+#ifdef CONFIG_PPC64
 	case 6:
 		return mfspr(SPRN_PMC7);
 	case 7:
 		return mfspr(SPRN_PMC8);
+#endif
 	default:
 		return 0;
 	}
@@ -108,16 +118,21 @@
 	case 5:
 		mtspr(SPRN_PMC6, val);
 		break;
+
+/* No PPC32 chip has more than 6, yet */
+#ifdef CONFIG_PPC64
 	case 6:
 		mtspr(SPRN_PMC7, val);
 		break;
 	case 7:
 		mtspr(SPRN_PMC8, val);
 		break;
+#endif
 	default:
 		break;
 	}
 }
-#endif /* __powerpc64__ */
+#endif /* !CONFIG_FSL_BOOKE */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OPROFILE_IMPL_H */
diff --git a/include/asm-powerpc/pSeries_reconfig.h b/include/asm-powerpc/pSeries_reconfig.h
index c0db1ea..ea6cfb8 100644
--- a/include/asm-powerpc/pSeries_reconfig.h
+++ b/include/asm-powerpc/pSeries_reconfig.h
@@ -1,5 +1,6 @@
 #ifndef _PPC64_PSERIES_RECONFIG_H
 #define _PPC64_PSERIES_RECONFIG_H
+#ifdef __KERNEL__
 
 #include <linux/notifier.h>
 
@@ -22,4 +23,5 @@
 static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
 #endif /* CONFIG_PPC_PSERIES */
 
+#endif /* __KERNEL__ */
 #endif /* _PPC64_PSERIES_RECONFIG_H */
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 92c765c..3ae52d9 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -14,11 +14,11 @@
  */
 #ifndef _ASM_POWERPC_PACA_H
 #define _ASM_POWERPC_PACA_H
+#ifdef __KERNEL__
 
 #include	<linux/config.h>
 #include	<asm/types.h>
 #include	<asm/lppaca.h>
-#include	<asm/iseries/it_lp_reg_save.h>
 #include	<asm/mmu.h>
 
 register struct paca_struct *local_paca asm("r13");
@@ -31,9 +31,9 @@
  *
  * This structure is not directly accessed by firmware or the service
  * processor except for the first two pointers that point to the
- * lppaca area and the ItLpRegSave area for this CPU.  Both the
- * lppaca and ItLpRegSave objects are currently contained within the
- * PACA but they do not need to be.
+ * lppaca area and the ItLpRegSave area for this CPU.  The lppaca
+ * object is currently contained within the PACA but it doesn't need
+ * to be.
  */
 struct paca_struct {
 	/*
@@ -48,7 +48,9 @@
 	 * accessed by the firmware
 	 */
 	struct lppaca *lppaca_ptr;	/* Pointer to LpPaca for PLIC */
-	struct ItLpRegSave *reg_save_ptr; /* Pointer to LpRegSave for PLIC */
+#ifdef CONFIG_PPC_ISERIES
+	void *reg_save_ptr; /* Pointer to LpRegSave for PLIC */
+#endif /* CONFIG_PPC_ISERIES */
 
 	/*
 	 * MAGIC: the spinlock functions in arch/ppc64/lib/locks.c
@@ -59,7 +61,6 @@
 	u16 lock_token;			/* Constant 0x8000, used in locks */
 	u16 paca_index;			/* Logical processor number */
 
-	u32 default_decr;		/* Default decrementer value */
 	u64 kernel_toc;			/* Kernel TOC address */
 	u64 stab_real;			/* Absolute address of segment table */
 	u64 stab_addr;			/* Virtual address of segment table */
@@ -90,14 +91,10 @@
 	struct task_struct *__current;	/* Pointer to current */
 	u64 kstack;			/* Saved Kernel stack addr */
 	u64 stab_rr;			/* stab/slb round-robin counter */
-	u64 next_jiffy_update_tb;	/* TB value for next jiffy update */
 	u64 saved_r1;			/* r1 save for RTAS calls */
 	u64 saved_msr;			/* MSR saved here by enter_rtas */
 	u8 proc_enabled;		/* irq soft-enable flag */
 
-	/* not yet used */
-	u64 exdsi[8];		/* used for linear mapping hash table misses */
-
 	/*
 	 * iSeries structure which the hypervisor knows about -
 	 * this structure should not cross a page boundary.
@@ -110,11 +107,9 @@
 	 * cross a page boundary.
 	 */
 	struct lppaca lppaca __attribute__((__aligned__(0x400)));
-#ifdef CONFIG_PPC_ISERIES
-	struct ItLpRegSave reg_save;
-#endif
 };
 
 extern struct paca_struct paca[];
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PACA_H */
diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h
index 18c1e5e..76d7cb4 100644
--- a/include/asm-powerpc/page.h
+++ b/include/asm-powerpc/page.h
@@ -37,8 +37,30 @@
  */
 #define PAGE_MASK      (~((1 << PAGE_SHIFT) - 1))
 
+/*
+ * KERNELBASE is the virtual address of the start of the kernel, it's often
+ * the same as PAGE_OFFSET, but _might not be_.
+ *
+ * The kdump dump kernel is one example where KERNELBASE != PAGE_OFFSET.
+ *
+ * To get a physical address from a virtual one you subtract PAGE_OFFSET,
+ * _not_ KERNELBASE.
+ *
+ * If you want to know something's offset from the start of the kernel you
+ * should subtract KERNELBASE.
+ *
+ * If you want to test if something's a kernel address, use is_kernel_addr().
+ */
+
+#ifdef CONFIG_CRASH_DUMP
+/* Kdump kernel runs at 32 MB, change at your peril. */
+#define PHYSICAL_START	0x2000000
+#else
+#define PHYSICAL_START	0x0
+#endif
+
 #define PAGE_OFFSET     ASM_CONST(CONFIG_KERNEL_START)
-#define KERNELBASE      PAGE_OFFSET
+#define KERNELBASE      (PAGE_OFFSET + PHYSICAL_START)
 
 #ifdef CONFIG_DISCONTIGMEM
 #define page_to_pfn(page)	discontigmem_page_to_pfn(page)
@@ -56,7 +78,7 @@
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
-#define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
 #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
 
 /*
@@ -86,6 +108,12 @@
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	_ALIGN(addr, PAGE_SIZE)
 
+/*
+ * Don't compare things with KERNELBASE or PAGE_OFFSET to test for
+ * "kernelness", use is_kernel_addr() - it should do what you want.
+ */
+#define is_kernel_addr(x)	((x) >= PAGE_OFFSET)
+
 #ifndef __ASSEMBLY__
 
 #undef STRICT_MM_TYPECHECKS
diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h
index 7259cfd..2677bad 100644
--- a/include/asm-powerpc/page_32.h
+++ b/include/asm-powerpc/page_32.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PAGE_32_H
 #define _ASM_POWERPC_PAGE_32_H
+#ifdef __KERNEL__
 
 #define VM_DATA_DEFAULT_FLAGS	VM_DATA_DEFAULT_FLAGS32
 
@@ -37,4 +38,5 @@
 
 #endif /* __ASSEMBLY__ */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PAGE_32_H */
diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h
index 6642c01..3fb061b 100644
--- a/include/asm-powerpc/page_64.h
+++ b/include/asm-powerpc/page_64.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PAGE_64_H
 #define _ASM_POWERPC_PAGE_64_H
+#ifdef __KERNEL__
 
 /*
  * Copyright (C) 2001 PPC64 Team, IBM Corp
@@ -25,16 +26,6 @@
  */
 #define PAGE_FACTOR		(PAGE_SHIFT - HW_PAGE_SHIFT)
 
-#define REGION_SIZE   4UL
-#define REGION_SHIFT  60UL
-#define REGION_MASK   (((1UL<<REGION_SIZE)-1UL)<<REGION_SHIFT)
-
-#define VMALLOCBASE		ASM_CONST(0xD000000000000000)
-#define VMALLOC_REGION_ID	(VMALLOCBASE >> REGION_SHIFT)
-#define KERNEL_REGION_ID	(KERNELBASE >> REGION_SHIFT)
-#define USER_REGION_ID		(0UL)
-#define REGION_ID(ea)		(((unsigned long)(ea)) >> REGION_SHIFT)
-
 /* Segment size */
 #define SID_SHIFT		28
 #define SID_MASK		0xfffffffffUL
@@ -180,4 +171,5 @@
 
 #include <asm-generic/page.h>
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PAGE_64_H */
diff --git a/include/asm-powerpc/param.h b/include/asm-powerpc/param.h
index bdc724f..094f63d 100644
--- a/include/asm-powerpc/param.h
+++ b/include/asm-powerpc/param.h
@@ -1,8 +1,6 @@
 #ifndef _ASM_POWERPC_PARAM_H
 #define _ASM_POWERPC_PARAM_H
 
-#include <linux/config.h>
-
 #ifdef __KERNEL__
 #define HZ		CONFIG_HZ	/* internal kernel timer frequency */
 #define USER_HZ		100		/* for user interfaces in "ticks" */
diff --git a/include/asm-powerpc/parport.h b/include/asm-powerpc/parport.h
index d86b410..897e49a 100644
--- a/include/asm-powerpc/parport.h
+++ b/include/asm-powerpc/parport.h
@@ -8,6 +8,7 @@
 
 #ifndef _ASM_POWERPC_PARPORT_H
 #define _ASM_POWERPC_PARPORT_H
+#ifdef __KERNEL__
 
 static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
 static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
@@ -15,4 +16,5 @@
 	return parport_pc_find_isa_ports (autoirq, autodma);
 }
 
+#endif /* __KERNEL__ */
 #endif /* !(_ASM_POWERPC_PARPORT_H) */
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 223ec7b..1a08860 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PCI_BRIDGE_H
 #define _ASM_POWERPC_PCI_BRIDGE_H
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/pci-bridge.h>
@@ -125,9 +126,19 @@
 		return bus->sysdata; /* Must be root bus (PHB) */
 }
 
+/** Find the bus corresponding to the indicated device node */
+struct pci_bus * pcibios_find_pci_bus(struct device_node *dn);
+
 extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 					 struct device_node *dev, int primary);
 
+/** Remove all of the PCI devices under this bus */
+void pcibios_remove_pci_devices(struct pci_bus *bus);
+
+/** Discover new pci devices under this bus, and add them */
+void pcibios_add_pci_devices(struct pci_bus * bus);
+void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus);
+
 extern int pcibios_remove_root_bus(struct pci_controller *phb);
 
 extern void phbs_remap_io(void);
@@ -140,14 +151,27 @@
 	return PCI_DN(busdn)->phb;
 }
 
+extern struct pci_controller*
+pci_find_hose_for_OF_device(struct device_node* node);
+
 extern struct pci_controller *
 pcibios_alloc_controller(struct device_node *dev);
 extern void pcibios_free_controller(struct pci_controller *phb);
 
+#ifdef CONFIG_PCI
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#else
+static inline unsigned long pci_address_to_pio(phys_addr_t address)
+{
+	return (unsigned long)-1;
+}
+#endif
+
 /* Return values for ppc_md.pci_probe_mode function */
 #define PCI_PROBE_NONE		-1	/* Don't look at this bus at all */
 #define PCI_PROBE_NORMAL	0	/* Do normal PCI probing */
 #define PCI_PROBE_DEVTREE	1	/* Instantiate from device tree */
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h
index d5934a0..5d2c9e6 100644
--- a/include/asm-powerpc/pci.h
+++ b/include/asm-powerpc/pci.h
@@ -216,6 +216,8 @@
 extern void pcibios_fixup_device_resources(struct pci_dev *dev,
 			struct pci_bus *bus);
 
+extern void pcibios_claim_one_bus(struct pci_bus *b);
+
 extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
 
 extern struct pci_dev *of_create_pci_dev(struct device_node *node,
diff --git a/include/asm-powerpc/pgalloc.h b/include/asm-powerpc/pgalloc.h
index bfc2113..9f5b052 100644
--- a/include/asm-powerpc/pgalloc.h
+++ b/include/asm-powerpc/pgalloc.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PGALLOC_H
 #define _ASM_POWERPC_PGALLOC_H
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/pgalloc.h>
@@ -153,4 +154,5 @@
 #define check_pgt_cache()	do { } while (0)
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGALLOC_H */
diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h
index 154f184..6539150 100644
--- a/include/asm-powerpc/pgtable-64k.h
+++ b/include/asm-powerpc/pgtable-64k.h
@@ -1,3 +1,7 @@
+#ifndef _ASM_POWERPC_PGTABLE_64K_H
+#define _ASM_POWERPC_PGTABLE_64K_H
+#ifdef __KERNEL__
+
 #include <asm-generic/pgtable-nopud.h>
 
 
@@ -88,3 +92,5 @@
 
 
 #endif /*  __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_PGTABLE_64K_H */
diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
index 0303f57..e389313 100644
--- a/include/asm-powerpc/pgtable.h
+++ b/include/asm-powerpc/pgtable.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PGTABLE_H
 #define _ASM_POWERPC_PGTABLE_H
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/pgtable.h>
@@ -58,6 +59,17 @@
 #define IMALLOC_END	(VMALLOC_START + PGTABLE_RANGE)
 
 /*
+ * Region IDs
+ */
+#define REGION_SHIFT		60UL
+#define REGION_MASK		(0xfUL << REGION_SHIFT)
+#define REGION_ID(ea)		(((unsigned long)(ea)) >> REGION_SHIFT)
+
+#define VMALLOC_REGION_ID	(REGION_ID(VMALLOC_START))
+#define KERNEL_REGION_ID	(REGION_ID(PAGE_OFFSET))
+#define USER_REGION_ID		(0UL)
+
+/*
  * Common bits in a linux-style PTE.  These match the bits in the
  * (hardware-defined) PowerPC PTE as closely as possible. Additional
  * bits may be defined in pgtable-*.h
@@ -521,4 +533,5 @@
 #endif /* __ASSEMBLY__ */
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGTABLE_H */
diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h
index e9683bc..3221628 100644
--- a/include/asm-powerpc/pmac_feature.h
+++ b/include/asm-powerpc/pmac_feature.h
@@ -121,6 +121,7 @@
 #define PMAC_TYPE_IMAC_G5		0x152	/* iMac G5 */
 #define PMAC_TYPE_XSERVE_G5		0x153	/* Xserve G5 */
 #define PMAC_TYPE_UNKNOWN_K2		0x19f	/* Any other K2 based */
+#define PMAC_TYPE_UNKNOWN_SHASTA       	0x19e	/* Any other Shasta based */
 
 /*
  * Motherboard flags
@@ -317,10 +318,6 @@
 extern void pmac_suspend_agp_for_card(struct pci_dev *dev);
 extern void pmac_resume_agp_for_card(struct pci_dev *dev);
 
-/* Used by the via-pmu driver for suspend/resume
- */
-extern void pmac_tweak_clock_spreading(int enable);
-
 /*
  * The part below is for use by macio_asic.c only, do not rely
  * on the data structures or constants below in a normal driver
@@ -341,6 +338,7 @@
 	macio_pangea,
 	macio_intrepid,
 	macio_keylargo2,
+	macio_shasta,
 };
 
 struct macio_chip
@@ -376,5 +374,24 @@
 #define MACIO_IN8(r)		(in_8(MACIO_FCR8(macio,r)))
 #define MACIO_OUT8(r,v)		(out_8(MACIO_FCR8(macio,r), (v)))
 
+/*
+ * Those are exported by pmac feature for internal use by arch code
+ * only like the platform function callbacks, do not use directly in drivers
+ */
+extern spinlock_t feature_lock;
+extern struct device_node *uninorth_node;
+extern u32 __iomem *uninorth_base;
+
+/*
+ * Uninorth reg. access. Note that Uni-N regs are big endian
+ */
+
+#define UN_REG(r)	(uninorth_base + ((r) >> 2))
+#define UN_IN(r)	(in_be32(UN_REG(r)))
+#define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
+
+
 #endif /* __PPC_ASM_PMAC_FEATURE_H */
 #endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/pmac_low_i2c.h b/include/asm-powerpc/pmac_low_i2c.h
index 809a596..131011b 100644
--- a/include/asm-powerpc/pmac_low_i2c.h
+++ b/include/asm-powerpc/pmac_low_i2c.h
@@ -11,33 +11,97 @@
  */
 #ifndef __PMAC_LOW_I2C_H__
 #define __PMAC_LOW_I2C_H__
+#ifdef __KERNEL__
 
 /* i2c mode (based on the platform functions format) */
 enum {
-	pmac_low_i2c_mode_dumb		= 1,
-	pmac_low_i2c_mode_std		= 2,
-	pmac_low_i2c_mode_stdsub	= 3,
-	pmac_low_i2c_mode_combined	= 4,
+	pmac_i2c_mode_dumb	= 1,
+	pmac_i2c_mode_std	= 2,
+	pmac_i2c_mode_stdsub	= 3,
+	pmac_i2c_mode_combined	= 4,
 };
 
 /* RW bit in address */
 enum {
-	pmac_low_i2c_read		= 0x01,
-	pmac_low_i2c_write		= 0x00
+	pmac_i2c_read		= 0x01,
+	pmac_i2c_write		= 0x00
 };
 
-/* Init, called early during boot */
-extern void pmac_init_low_i2c(void);
+/* i2c bus type */
+enum {
+	pmac_i2c_bus_keywest	= 0,
+	pmac_i2c_bus_pmu	= 1,
+	pmac_i2c_bus_smu	= 2,
+};
 
-/* Locking functions exposed to i2c-keywest */
-int pmac_low_i2c_lock(struct device_node *np);
-int pmac_low_i2c_unlock(struct device_node *np);
+/* i2c bus features */
+enum {
+	/* can_largesub : supports >1 byte subaddresses (SMU only) */
+	pmac_i2c_can_largesub	= 0x00000001u,
+
+	/* multibus : device node holds multiple busses, bus number is
+	 * encoded in bits 0xff00 of "reg" of a given device
+	 */
+	pmac_i2c_multibus	= 0x00000002u,
+};
+
+/* i2c busses in the system */
+struct pmac_i2c_bus;
+struct i2c_adapter;
+
+/* Init, called early during boot */
+extern int pmac_i2c_init(void);
+
+/* Lookup an i2c bus for a device-node. The node can be either the bus
+ * node itself or a device below it. In the case of a multibus, the bus
+ * node itself is the controller node, else, it's a child of the controller
+ * node
+ */
+extern struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node);
+
+/* Get the address for an i2c device. This strips the bus number if
+ * necessary. The 7 bits address is returned 1 bit right shifted so that the
+ * direction can be directly ored in
+ */
+extern u8 pmac_i2c_get_dev_addr(struct device_node *device);
+
+/* Get infos about a bus */
+extern struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus);
+extern struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_type(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_flags(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_channel(struct pmac_i2c_bus *bus);
+
+/* i2c layer adapter attach/detach */
+extern void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
+				    struct i2c_adapter *adapter);
+extern void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
+				    struct i2c_adapter *adapter);
+extern struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus);
+extern struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter);
+
+/* March a device or bus with an i2c adapter structure, to be used by drivers
+ * to match device-tree nodes with i2c adapters during adapter discovery
+ * callbacks
+ */
+extern int pmac_i2c_match_adapter(struct device_node *dev,
+				  struct i2c_adapter *adapter);
+
+
+/* (legacy) Locking functions exposed to i2c-keywest */
+extern int pmac_low_i2c_lock(struct device_node *np);
+extern int pmac_low_i2c_unlock(struct device_node *np);
 
 /* Access functions for platform code */
-int pmac_low_i2c_open(struct device_node *np, int channel);
-int pmac_low_i2c_close(struct device_node *np);
-int pmac_low_i2c_setmode(struct device_node *np, int mode);
-int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len);
+extern int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled);
+extern void pmac_i2c_close(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode);
+extern int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+			 u32 subaddr, u8 *data,  int len);
 
+/* Suspend/resume code called by via-pmu directly for now */
+extern void pmac_pfunc_i2c_suspend(void);
+extern void pmac_pfunc_i2c_resume(void);
 
+#endif /* __KERNEL__ */
 #endif /* __PMAC_LOW_I2C_H__ */
diff --git a/include/asm-powerpc/pmac_pfunc.h b/include/asm-powerpc/pmac_pfunc.h
new file mode 100644
index 0000000..d9728c8
--- /dev/null
+++ b/include/asm-powerpc/pmac_pfunc.h
@@ -0,0 +1,253 @@
+#ifndef __PMAC_PFUNC_H__
+#define __PMAC_PFUNC_H__
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+/* Flags in command lists */
+#define PMF_FLAGS_ON_INIT		0x80000000u
+#define PMF_FLGAS_ON_TERM		0x40000000u
+#define PMF_FLAGS_ON_SLEEP		0x20000000u
+#define PMF_FLAGS_ON_WAKE		0x10000000u
+#define PMF_FLAGS_ON_DEMAND		0x08000000u
+#define PMF_FLAGS_INT_GEN		0x04000000u
+#define PMF_FLAGS_HIGH_SPEED		0x02000000u
+#define PMF_FLAGS_LOW_SPEED		0x01000000u
+#define PMF_FLAGS_SIDE_EFFECTS		0x00800000u
+
+/*
+ * Arguments to a platform function call.
+ *
+ * NOTE: By convention, pointer arguments point to an u32
+ */
+struct pmf_args {
+	union {
+		u32 v;
+		u32 *p;
+	} u[4];
+	unsigned int count;
+};
+
+/*
+ * A driver capable of interpreting commands provides a handlers
+ * structure filled with whatever handlers are implemented by this
+ * driver. Non implemented handlers are left NULL.
+ *
+ * PMF_STD_ARGS are the same arguments that are passed to the parser
+ * and that gets passed back to the various handlers.
+ *
+ * Interpreting a given function always start with a begin() call which
+ * returns an instance data to be passed around subsequent calls, and
+ * ends with an end() call. This allows the low level driver to implement
+ * locking policy or per-function instance data.
+ *
+ * For interrupt capable functions, irq_enable() is called when a client
+ * registers, and irq_disable() is called when the last client unregisters
+ * Note that irq_enable & irq_disable are called within a semaphore held
+ * by the core, thus you should not try to register yourself to some other
+ * pmf interrupt during those calls.
+ */
+
+#define PMF_STD_ARGS	struct pmf_function *func, void *instdata, \
+		        struct pmf_args *args
+
+struct pmf_function;
+
+struct pmf_handlers {
+	void * (*begin)(struct pmf_function *func, struct pmf_args *args);
+	void (*end)(struct pmf_function *func, void *instdata);
+
+	int (*irq_enable)(struct pmf_function *func);
+	int (*irq_disable)(struct pmf_function *func);
+
+	int (*write_gpio)(PMF_STD_ARGS, u8 value, u8 mask);
+	int (*read_gpio)(PMF_STD_ARGS, u8 mask, int rshift, u8 xor);
+
+	int (*write_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask);
+	int (*read_reg32)(PMF_STD_ARGS, u32 offset);
+	int (*write_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask);
+	int (*read_reg16)(PMF_STD_ARGS, u32 offset);
+	int (*write_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask);
+	int (*read_reg8)(PMF_STD_ARGS, u32 offset);
+
+	int (*delay)(PMF_STD_ARGS, u32 duration);
+
+	int (*wait_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask);
+	int (*wait_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask);
+	int (*wait_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask);
+
+	int (*read_i2c)(PMF_STD_ARGS, u32 len);
+	int (*write_i2c)(PMF_STD_ARGS, u32 len, const u8 *data);
+	int (*rmw_i2c)(PMF_STD_ARGS, u32 masklen, u32 valuelen, u32 totallen,
+		       const u8 *maskdata, const u8 *valuedata);
+
+	int (*read_cfg)(PMF_STD_ARGS, u32 offset, u32 len);
+	int (*write_cfg)(PMF_STD_ARGS, u32 offset, u32 len, const u8 *data);
+	int (*rmw_cfg)(PMF_STD_ARGS, u32 offset, u32 masklen, u32 valuelen,
+		       u32 totallen, const u8 *maskdata, const u8 *valuedata);
+
+	int (*read_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len);
+	int (*write_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len, const u8 *data);
+	int (*set_i2c_mode)(PMF_STD_ARGS, int mode);
+	int (*rmw_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 masklen, u32 valuelen,
+			   u32 totallen, const u8 *maskdata,
+			   const u8 *valuedata);
+
+	int (*read_reg32_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+			       u32 xor);
+	int (*read_reg16_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+			       u32 xor);
+	int (*read_reg8_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+			      u32 xor);
+
+	int (*write_reg32_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+	int (*write_reg16_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+	int (*write_reg8_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+
+	int (*mask_and_compare)(PMF_STD_ARGS, u32 len, const u8 *maskdata,
+				const u8 *valuedata);
+
+	struct module *owner;
+};
+
+
+/*
+ * Drivers who expose platform functions register at init time, this
+ * causes the platform functions for that device node to be parsed in
+ * advance and associated with the device. The data structures are
+ * partially public so a driver can walk the list of platform functions
+ * and eventually inspect the flags
+ */
+struct pmf_device;
+
+struct pmf_function {
+	/* All functions for a given driver are linked */
+	struct list_head	link;
+
+	/* Function node & driver data */
+	struct device_node	*node;
+	void			*driver_data;
+
+	/* For internal use by core */
+	struct pmf_device	*dev;
+
+	/* The name is the "xxx" in "platform-do-xxx", this is how
+	 * platform functions are identified by this code. Some functions
+	 * only operate for a given target, in which case the phandle is
+	 * here (or 0 if the filter doesn't apply)
+	 */
+	const char		*name;
+	u32			phandle;
+
+	/* The flags for that function. You can have several functions
+	 * with the same name and different flag
+	 */
+	u32			flags;
+
+	/* The actual tokenized function blob */
+	const void		*data;
+	unsigned int		length;
+
+	/* Interrupt clients */
+	struct list_head	irq_clients;
+
+	/* Refcounting */
+	struct kref		ref;
+};
+
+/*
+ * For platform functions that are interrupts, one can register
+ * irq_client structures. You canNOT use the same structure twice
+ * as it contains a link member. Also, the callback is called with
+ * a spinlock held, you must not call back into any of the pmf_* functions
+ * from within that callback
+ */
+struct pmf_irq_client {
+	void			(*handler)(void *data);
+	void			*data;
+	struct module		*owner;
+	struct list_head	link;
+};
+
+
+/*
+ * Register/Unregister a function-capable driver and its handlers
+ */
+extern int pmf_register_driver(struct device_node *np,
+			      struct pmf_handlers *handlers,
+			      void *driverdata);
+
+extern void pmf_unregister_driver(struct device_node *np);
+
+
+/*
+ * Register/Unregister interrupt clients
+ */
+extern int pmf_register_irq_client(struct device_node *np,
+				   const char *name,
+				   struct pmf_irq_client *client);
+
+extern void pmf_unregister_irq_client(struct device_node *np,
+				      const char *name,
+				      struct pmf_irq_client *client);
+
+/*
+ * Called by the handlers when an irq happens
+ */
+extern void pmf_do_irq(struct pmf_function *func);
+
+
+/*
+ * Low level call to platform functions.
+ *
+ * The phandle can filter on the target object for functions that have
+ * multiple targets, the flags allow you to restrict the call to a given
+ * combination of flags.
+ *
+ * The args array contains as many arguments as is required by the function,
+ * this is dependent on the function you are calling, unfortunately Apple
+ * mecanism provides no way to encode that so you have to get it right at
+ * the call site. Some functions require no args, in which case, you can
+ * pass NULL.
+ *
+ * You can also pass NULL to the name. This will match any function that has
+ * the appropriate combination of flags & phandle or you can pass 0 to the
+ * phandle to match any
+ */
+extern int pmf_do_functions(struct device_node *np, const char *name,
+			    u32 phandle, u32 flags, struct pmf_args *args);
+
+
+
+/*
+ * High level call to a platform function.
+ *
+ * This one looks for the platform-xxx first so you should call it to the
+ * actual target if any. It will fallback to platform-do-xxx if it can't
+ * find one. It will also exclusively target functions that have
+ * the "OnDemand" flag.
+ */
+
+extern int pmf_call_function(struct device_node *target, const char *name,
+			     struct pmf_args *args);
+
+
+/*
+ * For low latency interrupt usage, you can lookup for on-demand functions
+ * using the functions below
+ */
+
+extern struct pmf_function *pmf_find_function(struct device_node *target,
+					      const char *name);
+
+extern struct pmf_function * pmf_get_function(struct pmf_function *func);
+extern void pmf_put_function(struct pmf_function *func);
+
+extern int pmf_call_one(struct pmf_function *func, struct pmf_args *args);
+
+
+/* Suspend/resume code called by via-pmu directly for now */
+extern void pmac_pfunc_base_suspend(void);
+extern void pmac_pfunc_base_resume(void);
+
+#endif /* __PMAC_PFUNC_H__ */
diff --git a/include/asm-powerpc/pmc.h b/include/asm-powerpc/pmc.h
index 5f41f3a..07d6a42 100644
--- a/include/asm-powerpc/pmc.h
+++ b/include/asm-powerpc/pmc.h
@@ -18,6 +18,7 @@
  */
 #ifndef _POWERPC_PMC_H
 #define _POWERPC_PMC_H
+#ifdef __KERNEL__
 
 #include <asm/ptrace.h>
 
@@ -44,4 +45,5 @@
 extern struct op_powerpc_model op_model_fsl_booke;
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _POWERPC_PMC_H */
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index 36cdc86..bdef312 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -8,6 +8,7 @@
  */
 #ifndef _ASM_POWERPC_PPC_PCI_H
 #define _ASM_POWERPC_PPC_PCI_H
+#ifdef __KERNEL__
 
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
@@ -93,4 +94,5 @@
 
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PPC_PCI_H */
diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h
index c27baa0..0dc798d 100644
--- a/include/asm-powerpc/ppc_asm.h
+++ b/include/asm-powerpc/ppc_asm.h
@@ -94,6 +94,7 @@
 #define RFDI		.long 0x4c00004e	/* rfdi instruction */
 #define RFMCI		.long 0x4c00004c	/* rfmci instruction */
 
+#ifdef __KERNEL__
 #ifdef CONFIG_PPC64
 
 #define XGLUE(a,b) a##b
@@ -325,6 +326,8 @@
 #define CLR_TOP32(r)
 #endif
 
+#endif /* __KERNEL__ */
+
 /* The boring bits... */
 
 /* Condition Register Bit Fields */
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index d12382d..415fa39 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -10,7 +10,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <asm/reg.h>
 
 #ifndef __ASSEMBLY__
@@ -50,6 +49,7 @@
 #define _CHRP_IBM	0x05	/* IBM chrp, the longtrail and longtrail 2 */
 #define _CHRP_Pegasos	0x06	/* Genesi/bplan's Pegasos and Pegasos2 */
 
+#ifdef __KERNEL__
 #define platform_is_pseries()	(_machine == PLATFORM_PSERIES || \
 				 _machine == PLATFORM_PSERIES_LPAR)
 #define platform_is_lpar()	(!!(_machine & PLATFORM_LPAR))
@@ -68,7 +68,6 @@
  * vendor. Board revision is also made available. This will be moved
  * elsewhere soon
  */
-extern unsigned char ucSystemType;
 extern unsigned char ucBoardRev;
 extern unsigned char ucBoardRevMaj, ucBoardRevMin;
 
@@ -82,7 +81,7 @@
 #else
 #define _machine 0
 #endif /* CONFIG_PPC_MULTIPLATFORM */
-
+#endif /* __KERNEL__ */
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index f999df1..329e9bf 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -65,49 +65,11 @@
 typedef u32 phandle;
 typedef u32 ihandle;
 
-struct address_range {
-	unsigned long space;
-	unsigned long address;
-	unsigned long size;
-};
-
 struct interrupt_info {
 	int	line;
 	int	sense;		/* +ve/-ve logic, edge or level, etc. */
 };
 
-struct pci_address {
-	u32 a_hi;
-	u32 a_mid;
-	u32 a_lo;
-};
-
-struct isa_address {
-	u32 a_hi;
-	u32 a_lo;
-};
-
-struct isa_range {
-	struct isa_address isa_addr;
-	struct pci_address pci_addr;
-	unsigned int size;
-};
-
-struct reg_property {
-	unsigned long address;
-	unsigned long size;
-};
-
-struct reg_property32 {
-	unsigned int address;
-	unsigned int size;
-};
-
-struct reg_property64 {
-	u64 address;
-	u64 size;
-};
-
 struct property {
 	char	*name;
 	int	length;
@@ -120,8 +82,6 @@
 	char	*type;
 	phandle	node;
 	phandle linux_phandle;
-	int	n_addrs;
-	struct	address_range *addrs;
 	int	n_intrs;
 	struct	interrupt_info *intrs;
 	char	*full_name;
@@ -223,5 +183,36 @@
 				int index, const char* name_postfix);
 extern int release_OF_resource(struct device_node* node, int index);
 
+
+/*
+ * OF address retreival & translation
+ */
+
+
+/* Translate an OF address block into a CPU physical address
+ */
+#define OF_BAD_ADDR	((u64)-1)
+extern u64 of_translate_address(struct device_node *np, u32 *addr);
+
+/* Extract an address from a device, returns the region size and
+ * the address space flags too. The PCI version uses a BAR number
+ * instead of an absolute index
+ */
+extern u32 *of_get_address(struct device_node *dev, int index,
+			   u64 *size, unsigned int *flags);
+extern u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+			       u64 *size, unsigned int *flags);
+
+/* Get an address as a resource. Note that if your address is
+ * a PIO address, the conversion will fail if the physical address
+ * can't be internally converted to an IO token with
+ * pci_address_to_pio(), that is because it's either called to early
+ * or it can't be matched to any host bridge IO space
+ */
+extern int of_address_to_resource(struct device_node *dev, int index,
+				  struct resource *r);
+extern int of_pci_address_to_resource(struct device_node *dev, int bar,
+				      struct resource *r);
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 1f7ecdb..9c550b3 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -87,7 +87,7 @@
 
 #define force_successful_syscall_return()   \
 	do { \
-		current_thread_info()->syscall_noerror = 1; \
+		set_thread_flag(TIF_NOERROR); \
 	} while(0)
 
 /*
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index eb392d0..12ecc9b 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -145,6 +145,10 @@
 #define SPRN_CTR	0x009	/* Count Register */
 #define SPRN_CTRLF	0x088
 #define SPRN_CTRLT	0x098
+#define   CTRL_CT	0xc0000000	/* current thread */
+#define   CTRL_CT0	0x80000000	/* thread 0 */
+#define   CTRL_CT1	0x40000000	/* thread 1 */
+#define   CTRL_TE	0x00c00000	/* thread enable */
 #define   CTRL_RUNLATCH	0x1
 #define SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
 #define   DABR_TRANSLATION	(1UL << 2)
@@ -257,11 +261,11 @@
 #define	SPRN_HID6	0x3F9	/* BE HID 6 */
 #define	  HID6_LB	(0x0F<<12) /* Concurrent Large Page Modes */
 #define	  HID6_DLP	(1<<20)	/* Disable all large page modes (4K only) */
-#define	SPRN_TSCR	0x399   /* Thread switch control on BE */
-#define	SPRN_TTR	0x39A   /* Thread switch timeout on BE */
-#define	  TSCR_DEC_ENABLE	0x200000 /* Decrementer Interrupt */
-#define	  TSCR_EE_ENABLE	0x100000 /* External Interrupt */
-#define	  TSCR_EE_BOOST		0x080000 /* External Interrupt Boost */
+#define	SPRN_TSC_CELL	0x399	/* Thread switch control on Cell */
+#define	  TSC_CELL_DEC_ENABLE_0	0x400000 /* Decrementer Interrupt */
+#define	  TSC_CELL_DEC_ENABLE_1	0x200000 /* Decrementer Interrupt */
+#define	  TSC_CELL_EE_ENABLE	0x100000 /* External Interrupt */
+#define	  TSC_CELL_EE_BOOST	0x080000 /* External Interrupt Boost */
 #define	SPRN_TSC 	0x3FD	/* Thread switch control on others */
 #define	SPRN_TST 	0x3FC	/* Thread switch timeout on others */
 #if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
@@ -375,6 +379,14 @@
 #define SPRN_SPRG7	0x117	/* Special Purpose Register General 7 */
 #define SPRN_SRR0	0x01A	/* Save/Restore Register 0 */
 #define SPRN_SRR1	0x01B	/* Save/Restore Register 1 */
+#define   SRR1_WAKEMASK		0x00380000 /* reason for wakeup */
+#define   SRR1_WAKERESET	0x00380000 /* System reset */
+#define   SRR1_WAKESYSERR	0x00300000 /* System error */
+#define   SRR1_WAKEEE		0x00200000 /* External interrupt */
+#define   SRR1_WAKEMT		0x00280000 /* mtctrl */
+#define   SRR1_WAKEDEC		0x00180000 /* Decrementer interrupt */
+#define   SRR1_WAKETHERM	0x00100000 /* Thermal management interrupt */
+
 #ifndef SPRN_SVR
 #define SPRN_SVR	0x11E	/* System Version Register */
 #endif
@@ -443,12 +455,35 @@
 #define SPRN_SDAR	781
 
 #else /* 32-bit */
-#define SPRN_MMCR0	0x3B8	/* Monitor Mode Control Register 0 */
-#define SPRN_MMCR1	0x3BC	/* Monitor Mode Control Register 1 */
-#define SPRN_PMC1	0x3B9	/* Performance Counter Register 1 */
-#define SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
-#define SPRN_PMC3	0x3BD	/* Performance Counter Register 3 */
-#define SPRN_PMC4	0x3BE	/* Performance Counter Register 4 */
+#define SPRN_MMCR0	952	/* Monitor Mode Control Register 0 */
+#define   MMCR0_FC	0x80000000UL /* freeze counters */
+#define   MMCR0_FCS	0x40000000UL /* freeze in supervisor state */
+#define   MMCR0_FCP	0x20000000UL /* freeze in problem state */
+#define   MMCR0_FCM1	0x10000000UL /* freeze counters while MSR mark = 1 */
+#define   MMCR0_FCM0	0x08000000UL /* freeze counters while MSR mark = 0 */
+#define   MMCR0_PMXE	0x04000000UL /* performance monitor exception enable */
+#define   MMCR0_FCECE	0x02000000UL /* freeze ctrs on enabled cond or event */
+#define   MMCR0_TBEE	0x00400000UL /* time base exception enable */
+#define   MMCR0_PMC1CE	0x00008000UL /* PMC1 count enable*/
+#define   MMCR0_PMCnCE	0x00004000UL /* count enable for all but PMC 1*/
+#define   MMCR0_TRIGGER	0x00002000UL /* TRIGGER enable */
+#define   MMCR0_PMC1SEL	0x00001fc0UL /* PMC 1 Event */
+#define   MMCR0_PMC2SEL	0x0000003fUL /* PMC 2 Event */
+
+#define SPRN_MMCR1	956
+#define   MMCR1_PMC3SEL	0xf8000000UL /* PMC 3 Event */
+#define   MMCR1_PMC4SEL	0x07c00000UL /* PMC 4 Event */
+#define   MMCR1_PMC5SEL	0x003e0000UL /* PMC 5 Event */
+#define   MMCR1_PMC6SEL 0x0001f800UL /* PMC 6 Event */
+#define SPRN_MMCR2	944
+#define SPRN_PMC1	953	/* Performance Counter Register 1 */
+#define SPRN_PMC2	954	/* Performance Counter Register 2 */
+#define SPRN_PMC3	957	/* Performance Counter Register 3 */
+#define SPRN_PMC4	958	/* Performance Counter Register 4 */
+#define SPRN_PMC5	945	/* Performance Counter Register 5 */
+#define SPRN_PMC6	946	/* Performance Counter Register 6 */
+
+#define SPRN_SIAR	955	/* Sampled Instruction Address Register */
 
 /* Bit definitions for MMCR0 and PMC1 / PMC2. */
 #define MMCR0_PMC1_CYCLES	(1 << 7)
@@ -458,7 +493,6 @@
 #define MMCR0_PMC2_CYCLES	0x1
 #define MMCR0_PMC2_ITLB		0x7
 #define MMCR0_PMC2_LOADMISSTIME	0x5
-#define MMCR0_PMXE	(1 << 26)
 #endif
 
 /* Processor Version Register (PVR) field extraction */
diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h
index d1bb611..3428889 100644
--- a/include/asm-powerpc/rtas.h
+++ b/include/asm-powerpc/rtas.h
@@ -1,5 +1,6 @@
 #ifndef _POWERPC_RTAS_H
 #define _POWERPC_RTAS_H
+#ifdef __KERNEL__
 
 #include <linux/spinlock.h>
 #include <asm/page.h>
@@ -229,4 +230,5 @@
 
 #define GLOBAL_INTERRUPT_QUEUE 9005
 
+#endif /* __KERNEL__ */
 #endif /* _POWERPC_RTAS_H */
diff --git a/include/asm-powerpc/seccomp.h b/include/asm-powerpc/seccomp.h
index 1e1cfe1..853765e 100644
--- a/include/asm-powerpc/seccomp.h
+++ b/include/asm-powerpc/seccomp.h
@@ -1,6 +1,10 @@
 #ifndef _ASM_POWERPC_SECCOMP_H
+#define _ASM_POWERPC_SECCOMP_H
 
+#ifdef __KERNEL__
 #include <linux/thread_info.h>
+#endif
+
 #include <linux/unistd.h>
 
 #define __NR_seccomp_read __NR_read
diff --git a/include/asm-powerpc/sections.h b/include/asm-powerpc/sections.h
index 47be2ac..916018e 100644
--- a/include/asm-powerpc/sections.h
+++ b/include/asm-powerpc/sections.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_SECTIONS_H
 #define _ASM_POWERPC_SECTIONS_H
+#ifdef __KERNEL__
 
 #include <asm-generic/sections.h>
 
@@ -17,4 +18,5 @@
 
 #endif
 
+#endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_SECTIONS_H */
diff --git a/include/asm-powerpc/serial.h b/include/asm-powerpc/serial.h
index b273d63..6dc9546 100644
--- a/include/asm-powerpc/serial.h
+++ b/include/asm-powerpc/serial.h
@@ -15,4 +15,6 @@
 /* Default baud base if not found in device-tree */
 #define BASE_BAUD ( 1843200 / 16 )
 
+extern void find_legacy_serial_ports(void);
+
 #endif /* _PPC64_SERIAL_H */
diff --git a/include/asm-powerpc/signal.h b/include/asm-powerpc/signal.h
index 694c8d2..a4d8f86 100644
--- a/include/asm-powerpc/signal.h
+++ b/include/asm-powerpc/signal.h
@@ -2,10 +2,13 @@
 #define _ASM_POWERPC_SIGNAL_H
 
 #include <linux/types.h>
-#include <linux/config.h>
 
 #define _NSIG		64
-#define _NSIG_BPW	BITS_PER_LONG
+#ifdef __powerpc64__
+#define _NSIG_BPW	64
+#else
+#define _NSIG_BPW	32
+#endif
 #define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
 
 typedef unsigned long old_sigset_t;		/* at least 32 bits */
diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h
index 76c29a9..134c2b5 100644
--- a/include/asm-powerpc/smu.h
+++ b/include/asm-powerpc/smu.h
@@ -4,9 +4,11 @@
 /*
  * Definitions for talking to the SMU chip in newer G5 PowerMacs
  */
-
+#ifdef __KERNEL__
 #include <linux/config.h>
 #include <linux/list.h>
+#endif
+#include <linux/types.h>
 
 /*
  * Known SMU commands
@@ -356,6 +358,9 @@
  * Kenrel asynchronous i2c interface
  */
 
+#define SMU_I2C_READ_MAX	0x1d
+#define SMU_I2C_WRITE_MAX	0x15
+
 /* SMU i2c header, exactly matches i2c header on wire */
 struct smu_i2c_param
 {
@@ -366,12 +371,9 @@
 	u8	subaddr[3];	/* subaddress */
 	u8	caddr;		/* combined address, filled by SMU driver */
 	u8	datalen;	/* length of transfer */
-	u8	data[7];	/* data */
+	u8	data[SMU_I2C_READ_MAX];	/* data */
 };
 
-#define SMU_I2C_READ_MAX	0x0d
-#define SMU_I2C_WRITE_MAX	0x05
-
 struct smu_i2c_cmd
 {
 	/* public */
@@ -385,7 +387,7 @@
 	int			read;
 	int			stage;
 	int			retries;
-	u8			pdata[0x10];
+	u8			pdata[32];
 	struct list_head	link;
 };
 
@@ -487,8 +489,8 @@
 #define SMU_SDB_SENSORTREE_ID		0x25
 
 struct smu_sdbp_sensortree {
-	u8	model_id;
-	u8	unknown[3];
+	__u8	model_id;
+	__u8	unknown[3];
 };
 
 /* This partition contains CPU thermal control PID informations. So far
@@ -498,13 +500,13 @@
 #define SMU_SDB_CPUPIDDATA_ID		0x17
 
 struct smu_sdbp_cpupiddata {
-	u8	unknown1;
-	u8	target_temp_delta;
-	u8	unknown2;
-	u8	history_len;
-	s16	power_adj;
-	u16	max_power;
-	s32	gp,gr,gd;
+	__u8	unknown1;
+	__u8	target_temp_delta;
+	__u8	unknown2;
+	__u8	history_len;
+	__s16	power_adj;
+	__u16	max_power;
+	__s32	gp,gr,gd;
 };
 
 
@@ -517,7 +519,7 @@
  * if not found. The data format is described below
  */
 extern struct smu_sdbp_header *smu_get_sdb_partition(int id,
-						     unsigned int *size);
+					unsigned int *size);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h
index ba1b34f..38b1ea3 100644
--- a/include/asm-powerpc/sparsemem.h
+++ b/include/asm-powerpc/sparsemem.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_SPARSEMEM_H
 #define _ASM_POWERPC_SPARSEMEM_H 1
+#ifdef __KERNEL__
 
 #ifdef CONFIG_SPARSEMEM
 /*
@@ -13,8 +14,17 @@
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 extern void create_section_mapping(unsigned long start, unsigned long end);
+#ifdef CONFIG_NUMA
+extern int hot_add_scn_to_nid(unsigned long scn_addr);
+#else
+static inline int hot_add_scn_to_nid(unsigned long scn_addr)
+{
+	return 0;
+}
+#endif /* CONFIG_NUMA */
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
 #endif /* CONFIG_SPARSEMEM */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SPARSEMEM_H */
diff --git a/include/asm-powerpc/spinlock.h b/include/asm-powerpc/spinlock.h
index caa4b14..7549009 100644
--- a/include/asm-powerpc/spinlock.h
+++ b/include/asm-powerpc/spinlock.h
@@ -1,5 +1,6 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
+#ifdef __KERNEL__
 
 /*
  * Simple spin lock operations.  
@@ -266,4 +267,5 @@
 	rw->lock = 0;
 }
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
new file mode 100644
index 0000000..38bacf2
--- /dev/null
+++ b/include/asm-powerpc/spu.h
@@ -0,0 +1,600 @@
+/*
+ * SPU core / file system interface and HW structures
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SPU_H
+#define _SPU_H
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/kref.h>
+#include <linux/workqueue.h>
+
+#define LS_SIZE (256 * 1024)
+#define LS_ADDR_MASK (LS_SIZE - 1)
+
+#define MFC_PUT_CMD             0x20
+#define MFC_PUTS_CMD            0x28
+#define MFC_PUTR_CMD            0x30
+#define MFC_PUTF_CMD            0x22
+#define MFC_PUTB_CMD            0x21
+#define MFC_PUTFS_CMD           0x2A
+#define MFC_PUTBS_CMD           0x29
+#define MFC_PUTRF_CMD           0x32
+#define MFC_PUTRB_CMD           0x31
+#define MFC_PUTL_CMD            0x24
+#define MFC_PUTRL_CMD           0x34
+#define MFC_PUTLF_CMD           0x26
+#define MFC_PUTLB_CMD           0x25
+#define MFC_PUTRLF_CMD          0x36
+#define MFC_PUTRLB_CMD          0x35
+
+#define MFC_GET_CMD             0x40
+#define MFC_GETS_CMD            0x48
+#define MFC_GETF_CMD            0x42
+#define MFC_GETB_CMD            0x41
+#define MFC_GETFS_CMD           0x4A
+#define MFC_GETBS_CMD           0x49
+#define MFC_GETL_CMD            0x44
+#define MFC_GETLF_CMD           0x46
+#define MFC_GETLB_CMD           0x45
+
+#define MFC_SDCRT_CMD           0x80
+#define MFC_SDCRTST_CMD         0x81
+#define MFC_SDCRZ_CMD           0x89
+#define MFC_SDCRS_CMD           0x8D
+#define MFC_SDCRF_CMD           0x8F
+
+#define MFC_GETLLAR_CMD         0xD0
+#define MFC_PUTLLC_CMD          0xB4
+#define MFC_PUTLLUC_CMD         0xB0
+#define MFC_PUTQLLUC_CMD        0xB8
+#define MFC_SNDSIG_CMD          0xA0
+#define MFC_SNDSIGB_CMD         0xA1
+#define MFC_SNDSIGF_CMD         0xA2
+#define MFC_BARRIER_CMD         0xC0
+#define MFC_EIEIO_CMD           0xC8
+#define MFC_SYNC_CMD            0xCC
+
+#define MFC_MIN_DMA_SIZE_SHIFT  4       /* 16 bytes */
+#define MFC_MAX_DMA_SIZE_SHIFT  14      /* 16384 bytes */
+#define MFC_MIN_DMA_SIZE        (1 << MFC_MIN_DMA_SIZE_SHIFT)
+#define MFC_MAX_DMA_SIZE        (1 << MFC_MAX_DMA_SIZE_SHIFT)
+#define MFC_MIN_DMA_SIZE_MASK   (MFC_MIN_DMA_SIZE - 1)
+#define MFC_MAX_DMA_SIZE_MASK   (MFC_MAX_DMA_SIZE - 1)
+#define MFC_MIN_DMA_LIST_SIZE   0x0008  /*   8 bytes */
+#define MFC_MAX_DMA_LIST_SIZE   0x4000  /* 16K bytes */
+
+#define MFC_TAGID_TO_TAGMASK(tag_id)  (1 << (tag_id & 0x1F))
+
+/* Events for Channels 0-2 */
+#define MFC_DMA_TAG_STATUS_UPDATE_EVENT     0x00000001
+#define MFC_DMA_TAG_CMD_STALL_NOTIFY_EVENT  0x00000002
+#define MFC_DMA_QUEUE_AVAILABLE_EVENT       0x00000008
+#define MFC_SPU_MAILBOX_WRITTEN_EVENT       0x00000010
+#define MFC_DECREMENTER_EVENT               0x00000020
+#define MFC_PU_INT_MAILBOX_AVAILABLE_EVENT  0x00000040
+#define MFC_PU_MAILBOX_AVAILABLE_EVENT      0x00000080
+#define MFC_SIGNAL_2_EVENT                  0x00000100
+#define MFC_SIGNAL_1_EVENT                  0x00000200
+#define MFC_LLR_LOST_EVENT                  0x00000400
+#define MFC_PRIV_ATTN_EVENT                 0x00000800
+#define MFC_MULTI_SRC_EVENT                 0x00001000
+
+/* Flags indicating progress during context switch. */
+#define SPU_CONTEXT_SWITCH_PENDING	0UL
+#define SPU_CONTEXT_SWITCH_ACTIVE	1UL
+
+struct spu_context;
+struct spu_runqueue;
+
+struct spu {
+	char *name;
+	unsigned long local_store_phys;
+	u8 *local_store;
+	struct spu_problem __iomem *problem;
+	struct spu_priv1 __iomem *priv1;
+	struct spu_priv2 __iomem *priv2;
+	struct list_head list;
+	struct list_head sched_list;
+	int number;
+	u32 isrc;
+	u32 node;
+	u64 flags;
+	u64 dar;
+	u64 dsisr;
+	struct kref kref;
+	size_t ls_size;
+	unsigned int slb_replace;
+	struct mm_struct *mm;
+	struct spu_context *ctx;
+	struct spu_runqueue *rq;
+	unsigned long long timestamp;
+	pid_t pid;
+	int prio;
+	int class_0_pending;
+	spinlock_t register_lock;
+
+	u32 stop_code;
+	void (* wbox_callback)(struct spu *spu);
+	void (* ibox_callback)(struct spu *spu);
+	void (* stop_callback)(struct spu *spu);
+
+	char irq_c0[8];
+	char irq_c1[8];
+	char irq_c2[8];
+};
+
+struct spu *spu_alloc(void);
+void spu_free(struct spu *spu);
+int spu_irq_class_0_bottom(struct spu *spu);
+int spu_irq_class_1_bottom(struct spu *spu);
+void spu_irq_setaffinity(struct spu *spu, int cpu);
+
+extern struct spufs_calls {
+	asmlinkage long (*create_thread)(const char __user *name,
+					unsigned int flags, mode_t mode);
+	asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
+						__u32 __user *ustatus);
+	struct module *owner;
+} spufs_calls;
+
+#ifdef CONFIG_SPU_FS_MODULE
+int register_spu_syscalls(struct spufs_calls *calls);
+void unregister_spu_syscalls(struct spufs_calls *calls);
+#else
+static inline int register_spu_syscalls(struct spufs_calls *calls)
+{
+	return 0;
+}
+static inline void unregister_spu_syscalls(struct spufs_calls *calls)
+{
+}
+#endif /* MODULE */
+
+
+/* access to priv1 registers */
+void spu_int_mask_and(struct spu *spu, int class, u64 mask);
+void spu_int_mask_or(struct spu *spu, int class, u64 mask);
+void spu_int_mask_set(struct spu *spu, int class, u64 mask);
+u64 spu_int_mask_get(struct spu *spu, int class);
+void spu_int_stat_clear(struct spu *spu, int class, u64 stat);
+u64 spu_int_stat_get(struct spu *spu, int class);
+void spu_int_route_set(struct spu *spu, u64 route);
+u64 spu_mfc_dar_get(struct spu *spu);
+u64 spu_mfc_dsisr_get(struct spu *spu);
+void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr);
+void spu_mfc_sdr_set(struct spu *spu, u64 sdr);
+void spu_mfc_sr1_set(struct spu *spu, u64 sr1);
+u64 spu_mfc_sr1_get(struct spu *spu);
+void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id);
+u64 spu_mfc_tclass_id_get(struct spu *spu);
+void spu_tlb_invalidate(struct spu *spu);
+void spu_resource_allocation_groupID_set(struct spu *spu, u64 id);
+u64 spu_resource_allocation_groupID_get(struct spu *spu);
+void spu_resource_allocation_enable_set(struct spu *spu, u64 enable);
+u64 spu_resource_allocation_enable_get(struct spu *spu);
+
+
+/*
+ * This defines the Local Store, Problem Area and Privlege Area of an SPU.
+ */
+
+union mfc_tag_size_class_cmd {
+	struct {
+		u16 mfc_size;
+		u16 mfc_tag;
+		u8  pad;
+		u8  mfc_rclassid;
+		u16 mfc_cmd;
+	} u;
+	struct {
+		u32 mfc_size_tag32;
+		u32 mfc_class_cmd32;
+	} by32;
+	u64 all64;
+};
+
+struct mfc_cq_sr {
+	u64 mfc_cq_data0_RW;
+	u64 mfc_cq_data1_RW;
+	u64 mfc_cq_data2_RW;
+	u64 mfc_cq_data3_RW;
+};
+
+struct spu_problem {
+#define MS_SYNC_PENDING         1L
+	u64 spc_mssync_RW;					/* 0x0000 */
+	u8  pad_0x0008_0x3000[0x3000 - 0x0008];
+
+	/* DMA Area */
+	u8  pad_0x3000_0x3004[0x4];				/* 0x3000 */
+	u32 mfc_lsa_W;						/* 0x3004 */
+	u64 mfc_ea_W;						/* 0x3008 */
+	union mfc_tag_size_class_cmd mfc_union_W;			/* 0x3010 */
+	u8  pad_0x3018_0x3104[0xec];				/* 0x3018 */
+	u32 dma_qstatus_R;					/* 0x3104 */
+	u8  pad_0x3108_0x3204[0xfc];				/* 0x3108 */
+	u32 dma_querytype_RW;					/* 0x3204 */
+	u8  pad_0x3208_0x321c[0x14];				/* 0x3208 */
+	u32 dma_querymask_RW;					/* 0x321c */
+	u8  pad_0x3220_0x322c[0xc];				/* 0x3220 */
+	u32 dma_tagstatus_R;					/* 0x322c */
+#define DMA_TAGSTATUS_INTR_ANY	1u
+#define DMA_TAGSTATUS_INTR_ALL	2u
+	u8  pad_0x3230_0x4000[0x4000 - 0x3230]; 		/* 0x3230 */
+
+	/* SPU Control Area */
+	u8  pad_0x4000_0x4004[0x4];				/* 0x4000 */
+	u32 pu_mb_R;						/* 0x4004 */
+	u8  pad_0x4008_0x400c[0x4];				/* 0x4008 */
+	u32 spu_mb_W;						/* 0x400c */
+	u8  pad_0x4010_0x4014[0x4];				/* 0x4010 */
+	u32 mb_stat_R;						/* 0x4014 */
+	u8  pad_0x4018_0x401c[0x4];				/* 0x4018 */
+	u32 spu_runcntl_RW;					/* 0x401c */
+#define SPU_RUNCNTL_STOP	0L
+#define SPU_RUNCNTL_RUNNABLE	1L
+	u8  pad_0x4020_0x4024[0x4];				/* 0x4020 */
+	u32 spu_status_R;					/* 0x4024 */
+#define SPU_STOP_STATUS_SHIFT           16
+#define SPU_STATUS_STOPPED		0x0
+#define SPU_STATUS_RUNNING		0x1
+#define SPU_STATUS_STOPPED_BY_STOP	0x2
+#define SPU_STATUS_STOPPED_BY_HALT	0x4
+#define SPU_STATUS_WAITING_FOR_CHANNEL	0x8
+#define SPU_STATUS_SINGLE_STEP		0x10
+#define SPU_STATUS_INVALID_INSTR        0x20
+#define SPU_STATUS_INVALID_CH           0x40
+#define SPU_STATUS_ISOLATED_STATE       0x80
+#define SPU_STATUS_ISOLATED_LOAD_STAUTUS 0x200
+#define SPU_STATUS_ISOLATED_EXIT_STAUTUS 0x400
+	u8  pad_0x4028_0x402c[0x4];				/* 0x4028 */
+	u32 spu_spe_R;						/* 0x402c */
+	u8  pad_0x4030_0x4034[0x4];				/* 0x4030 */
+	u32 spu_npc_RW;						/* 0x4034 */
+	u8  pad_0x4038_0x14000[0x14000 - 0x4038];		/* 0x4038 */
+
+	/* Signal Notification Area */
+	u8  pad_0x14000_0x1400c[0xc];				/* 0x14000 */
+	u32 signal_notify1;					/* 0x1400c */
+	u8  pad_0x14010_0x1c00c[0x7ffc];			/* 0x14010 */
+	u32 signal_notify2;					/* 0x1c00c */
+} __attribute__ ((aligned(0x20000)));
+
+/* SPU Privilege 2 State Area */
+struct spu_priv2 {
+	/* MFC Registers */
+	u8  pad_0x0000_0x1100[0x1100 - 0x0000]; 		/* 0x0000 */
+
+	/* SLB Management Registers */
+	u8  pad_0x1100_0x1108[0x8];				/* 0x1100 */
+	u64 slb_index_W;					/* 0x1108 */
+#define SLB_INDEX_MASK				0x7L
+	u64 slb_esid_RW;					/* 0x1110 */
+	u64 slb_vsid_RW;					/* 0x1118 */
+#define SLB_VSID_SUPERVISOR_STATE	(0x1ull << 11)
+#define SLB_VSID_SUPERVISOR_STATE_MASK	(0x1ull << 11)
+#define SLB_VSID_PROBLEM_STATE		(0x1ull << 10)
+#define SLB_VSID_PROBLEM_STATE_MASK	(0x1ull << 10)
+#define SLB_VSID_EXECUTE_SEGMENT	(0x1ull << 9)
+#define SLB_VSID_NO_EXECUTE_SEGMENT	(0x1ull << 9)
+#define SLB_VSID_EXECUTE_SEGMENT_MASK	(0x1ull << 9)
+#define SLB_VSID_4K_PAGE		(0x0 << 8)
+#define SLB_VSID_LARGE_PAGE		(0x1ull << 8)
+#define SLB_VSID_PAGE_SIZE_MASK		(0x1ull << 8)
+#define SLB_VSID_CLASS_MASK		(0x1ull << 7)
+#define SLB_VSID_VIRTUAL_PAGE_SIZE_MASK	(0x1ull << 6)
+	u64 slb_invalidate_entry_W;				/* 0x1120 */
+	u64 slb_invalidate_all_W;				/* 0x1128 */
+	u8  pad_0x1130_0x2000[0x2000 - 0x1130]; 		/* 0x1130 */
+
+	/* Context Save / Restore Area */
+	struct mfc_cq_sr spuq[16];				/* 0x2000 */
+	struct mfc_cq_sr puq[8];				/* 0x2200 */
+	u8  pad_0x2300_0x3000[0x3000 - 0x2300]; 		/* 0x2300 */
+
+	/* MFC Control */
+	u64 mfc_control_RW;					/* 0x3000 */
+#define MFC_CNTL_RESUME_DMA_QUEUE		(0ull << 0)
+#define MFC_CNTL_SUSPEND_DMA_QUEUE		(1ull << 0)
+#define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK		(1ull << 0)
+#define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION	(0ull << 8)
+#define MFC_CNTL_SUSPEND_IN_PROGRESS		(1ull << 8)
+#define MFC_CNTL_SUSPEND_COMPLETE		(3ull << 8)
+#define MFC_CNTL_SUSPEND_DMA_STATUS_MASK	(3ull << 8)
+#define MFC_CNTL_DMA_QUEUES_EMPTY		(1ull << 14)
+#define MFC_CNTL_DMA_QUEUES_EMPTY_MASK		(1ull << 14)
+#define MFC_CNTL_PURGE_DMA_REQUEST		(1ull << 15)
+#define MFC_CNTL_PURGE_DMA_IN_PROGRESS		(1ull << 24)
+#define MFC_CNTL_PURGE_DMA_COMPLETE		(3ull << 24)
+#define MFC_CNTL_PURGE_DMA_STATUS_MASK		(3ull << 24)
+#define MFC_CNTL_RESTART_DMA_COMMAND		(1ull << 32)
+#define MFC_CNTL_DMA_COMMAND_REISSUE_PENDING	(1ull << 32)
+#define MFC_CNTL_DMA_COMMAND_REISSUE_STATUS_MASK (1ull << 32)
+#define MFC_CNTL_MFC_PRIVILEGE_STATE		(2ull << 33)
+#define MFC_CNTL_MFC_PROBLEM_STATE		(3ull << 33)
+#define MFC_CNTL_MFC_KEY_PROTECTION_STATE_MASK	(3ull << 33)
+#define MFC_CNTL_DECREMENTER_HALTED		(1ull << 35)
+#define MFC_CNTL_DECREMENTER_RUNNING		(1ull << 40)
+#define MFC_CNTL_DECREMENTER_STATUS_MASK	(1ull << 40)
+	u8  pad_0x3008_0x4000[0x4000 - 0x3008]; 		/* 0x3008 */
+
+	/* Interrupt Mailbox */
+	u64 puint_mb_R;						/* 0x4000 */
+	u8  pad_0x4008_0x4040[0x4040 - 0x4008]; 		/* 0x4008 */
+
+	/* SPU Control */
+	u64 spu_privcntl_RW;					/* 0x4040 */
+#define SPU_PRIVCNTL_MODE_NORMAL		(0x0ull << 0)
+#define SPU_PRIVCNTL_MODE_SINGLE_STEP		(0x1ull << 0)
+#define SPU_PRIVCNTL_MODE_MASK			(0x1ull << 0)
+#define SPU_PRIVCNTL_NO_ATTENTION_EVENT		(0x0ull << 1)
+#define SPU_PRIVCNTL_ATTENTION_EVENT		(0x1ull << 1)
+#define SPU_PRIVCNTL_ATTENTION_EVENT_MASK	(0x1ull << 1)
+#define SPU_PRIVCNT_LOAD_REQUEST_NORMAL		(0x0ull << 2)
+#define SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK	(0x1ull << 2)
+	u8  pad_0x4048_0x4058[0x10];				/* 0x4048 */
+	u64 spu_lslr_RW;					/* 0x4058 */
+	u64 spu_chnlcntptr_RW;					/* 0x4060 */
+	u64 spu_chnlcnt_RW;					/* 0x4068 */
+	u64 spu_chnldata_RW;					/* 0x4070 */
+	u64 spu_cfg_RW;						/* 0x4078 */
+	u8  pad_0x4080_0x5000[0x5000 - 0x4080]; 		/* 0x4080 */
+
+	/* PV2_ImplRegs: Implementation-specific privileged-state 2 regs */
+	u64 spu_pm_trace_tag_status_RW;				/* 0x5000 */
+	u64 spu_tag_status_query_RW;				/* 0x5008 */
+#define TAG_STATUS_QUERY_CONDITION_BITS (0x3ull << 32)
+#define TAG_STATUS_QUERY_MASK_BITS (0xffffffffull)
+	u64 spu_cmd_buf1_RW;					/* 0x5010 */
+#define SPU_COMMAND_BUFFER_1_LSA_BITS (0x7ffffull << 32)
+#define SPU_COMMAND_BUFFER_1_EAH_BITS (0xffffffffull)
+	u64 spu_cmd_buf2_RW;					/* 0x5018 */
+#define SPU_COMMAND_BUFFER_2_EAL_BITS ((0xffffffffull) << 32)
+#define SPU_COMMAND_BUFFER_2_TS_BITS (0xffffull << 16)
+#define SPU_COMMAND_BUFFER_2_TAG_BITS (0x3full)
+	u64 spu_atomic_status_RW;				/* 0x5020 */
+} __attribute__ ((aligned(0x20000)));
+
+/* SPU Privilege 1 State Area */
+struct spu_priv1 {
+	/* Control and Configuration Area */
+	u64 mfc_sr1_RW;						/* 0x000 */
+#define MFC_STATE1_LOCAL_STORAGE_DECODE_MASK	0x01ull
+#define MFC_STATE1_BUS_TLBIE_MASK		0x02ull
+#define MFC_STATE1_REAL_MODE_OFFSET_ENABLE_MASK	0x04ull
+#define MFC_STATE1_PROBLEM_STATE_MASK		0x08ull
+#define MFC_STATE1_RELOCATE_MASK		0x10ull
+#define MFC_STATE1_MASTER_RUN_CONTROL_MASK	0x20ull
+	u64 mfc_lpid_RW;					/* 0x008 */
+	u64 spu_idr_RW;						/* 0x010 */
+	u64 mfc_vr_RO;						/* 0x018 */
+#define MFC_VERSION_BITS		(0xffff << 16)
+#define MFC_REVISION_BITS		(0xffff)
+#define MFC_GET_VERSION_BITS(vr)	(((vr) & MFC_VERSION_BITS) >> 16)
+#define MFC_GET_REVISION_BITS(vr)	((vr) & MFC_REVISION_BITS)
+	u64 spu_vr_RO;						/* 0x020 */
+#define SPU_VERSION_BITS		(0xffff << 16)
+#define SPU_REVISION_BITS		(0xffff)
+#define SPU_GET_VERSION_BITS(vr)	(vr & SPU_VERSION_BITS) >> 16
+#define SPU_GET_REVISION_BITS(vr)	(vr & SPU_REVISION_BITS)
+	u8  pad_0x28_0x100[0x100 - 0x28];			/* 0x28 */
+
+
+	/* Interrupt Area */
+	u64 int_mask_RW[3];					/* 0x100 */
+#define CLASS0_ENABLE_DMA_ALIGNMENT_INTR		0x1L
+#define CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR		0x2L
+#define CLASS0_ENABLE_SPU_ERROR_INTR			0x4L
+#define CLASS0_ENABLE_MFC_FIR_INTR			0x8L
+#define CLASS1_ENABLE_SEGMENT_FAULT_INTR		0x1L
+#define CLASS1_ENABLE_STORAGE_FAULT_INTR		0x2L
+#define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_GET_INTR	0x4L
+#define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_PUT_INTR	0x8L
+#define CLASS2_ENABLE_MAILBOX_INTR			0x1L
+#define CLASS2_ENABLE_SPU_STOP_INTR			0x2L
+#define CLASS2_ENABLE_SPU_HALT_INTR			0x4L
+#define CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR	0x8L
+	u8  pad_0x118_0x140[0x28];				/* 0x118 */
+	u64 int_stat_RW[3];					/* 0x140 */
+	u8  pad_0x158_0x180[0x28];				/* 0x158 */
+	u64 int_route_RW;					/* 0x180 */
+
+	/* Interrupt Routing */
+	u8  pad_0x188_0x200[0x200 - 0x188];			/* 0x188 */
+
+	/* Atomic Unit Control Area */
+	u64 mfc_atomic_flush_RW;				/* 0x200 */
+#define mfc_atomic_flush_enable			0x1L
+	u8  pad_0x208_0x280[0x78];				/* 0x208 */
+	u64 resource_allocation_groupID_RW;			/* 0x280 */
+	u64 resource_allocation_enable_RW; 			/* 0x288 */
+	u8  pad_0x290_0x3c8[0x3c8 - 0x290];			/* 0x290 */
+
+	/* SPU_Cache_ImplRegs: Implementation-dependent cache registers */
+
+	u64 smf_sbi_signal_sel;					/* 0x3c8 */
+#define smf_sbi_mask_lsb	56
+#define smf_sbi_shift		(63 - smf_sbi_mask_lsb)
+#define smf_sbi_mask		(0x301LL << smf_sbi_shift)
+#define smf_sbi_bus0_bits	(0x001LL << smf_sbi_shift)
+#define smf_sbi_bus2_bits	(0x100LL << smf_sbi_shift)
+#define smf_sbi2_bus0_bits	(0x201LL << smf_sbi_shift)
+#define smf_sbi2_bus2_bits	(0x300LL << smf_sbi_shift)
+	u64 smf_ato_signal_sel;					/* 0x3d0 */
+#define smf_ato_mask_lsb	35
+#define smf_ato_shift		(63 - smf_ato_mask_lsb)
+#define smf_ato_mask		(0x3LL << smf_ato_shift)
+#define smf_ato_bus0_bits	(0x2LL << smf_ato_shift)
+#define smf_ato_bus2_bits	(0x1LL << smf_ato_shift)
+	u8  pad_0x3d8_0x400[0x400 - 0x3d8];			/* 0x3d8 */
+
+	/* TLB Management Registers */
+	u64 mfc_sdr_RW;						/* 0x400 */
+	u8  pad_0x408_0x500[0xf8];				/* 0x408 */
+	u64 tlb_index_hint_RO;					/* 0x500 */
+	u64 tlb_index_W;					/* 0x508 */
+	u64 tlb_vpn_RW;						/* 0x510 */
+	u64 tlb_rpn_RW;						/* 0x518 */
+	u8  pad_0x520_0x540[0x20];				/* 0x520 */
+	u64 tlb_invalidate_entry_W;				/* 0x540 */
+	u64 tlb_invalidate_all_W;				/* 0x548 */
+	u8  pad_0x550_0x580[0x580 - 0x550];			/* 0x550 */
+
+	/* SPU_MMU_ImplRegs: Implementation-dependent MMU registers */
+	u64 smm_hid;						/* 0x580 */
+#define PAGE_SIZE_MASK		0xf000000000000000ull
+#define PAGE_SIZE_16MB_64KB	0x2000000000000000ull
+	u8  pad_0x588_0x600[0x600 - 0x588];			/* 0x588 */
+
+	/* MFC Status/Control Area */
+	u64 mfc_accr_RW;					/* 0x600 */
+#define MFC_ACCR_EA_ACCESS_GET		(1 << 0)
+#define MFC_ACCR_EA_ACCESS_PUT		(1 << 1)
+#define MFC_ACCR_LS_ACCESS_GET		(1 << 3)
+#define MFC_ACCR_LS_ACCESS_PUT		(1 << 4)
+	u8  pad_0x608_0x610[0x8];				/* 0x608 */
+	u64 mfc_dsisr_RW;					/* 0x610 */
+#define MFC_DSISR_PTE_NOT_FOUND		(1 << 30)
+#define MFC_DSISR_ACCESS_DENIED		(1 << 27)
+#define MFC_DSISR_ATOMIC		(1 << 26)
+#define MFC_DSISR_ACCESS_PUT		(1 << 25)
+#define MFC_DSISR_ADDR_MATCH		(1 << 22)
+#define MFC_DSISR_LS			(1 << 17)
+#define MFC_DSISR_L			(1 << 16)
+#define MFC_DSISR_ADDRESS_OVERFLOW	(1 << 0)
+	u8  pad_0x618_0x620[0x8];				/* 0x618 */
+	u64 mfc_dar_RW;						/* 0x620 */
+	u8  pad_0x628_0x700[0x700 - 0x628];			/* 0x628 */
+
+	/* Replacement Management Table (RMT) Area */
+	u64 rmt_index_RW;					/* 0x700 */
+	u8  pad_0x708_0x710[0x8];				/* 0x708 */
+	u64 rmt_data1_RW;					/* 0x710 */
+	u8  pad_0x718_0x800[0x800 - 0x718];			/* 0x718 */
+
+	/* Control/Configuration Registers */
+	u64 mfc_dsir_R;						/* 0x800 */
+#define MFC_DSIR_Q			(1 << 31)
+#define MFC_DSIR_SPU_QUEUE		MFC_DSIR_Q
+	u64 mfc_lsacr_RW;					/* 0x808 */
+#define MFC_LSACR_COMPARE_MASK		((~0ull) << 32)
+#define MFC_LSACR_COMPARE_ADDR		((~0ull) >> 32)
+	u64 mfc_lscrr_R;					/* 0x810 */
+#define MFC_LSCRR_Q			(1 << 31)
+#define MFC_LSCRR_SPU_QUEUE		MFC_LSCRR_Q
+#define MFC_LSCRR_QI_SHIFT		32
+#define MFC_LSCRR_QI_MASK		((~0ull) << MFC_LSCRR_QI_SHIFT)
+	u8  pad_0x818_0x820[0x8];				/* 0x818 */
+	u64 mfc_tclass_id_RW;					/* 0x820 */
+#define MFC_TCLASS_ID_ENABLE		(1L << 0L)
+#define MFC_TCLASS_SLOT2_ENABLE		(1L << 5L)
+#define MFC_TCLASS_SLOT1_ENABLE		(1L << 6L)
+#define MFC_TCLASS_SLOT0_ENABLE		(1L << 7L)
+#define MFC_TCLASS_QUOTA_2_SHIFT	8L
+#define MFC_TCLASS_QUOTA_1_SHIFT	16L
+#define MFC_TCLASS_QUOTA_0_SHIFT	24L
+#define MFC_TCLASS_QUOTA_2_MASK		(0x1FL << MFC_TCLASS_QUOTA_2_SHIFT)
+#define MFC_TCLASS_QUOTA_1_MASK		(0x1FL << MFC_TCLASS_QUOTA_1_SHIFT)
+#define MFC_TCLASS_QUOTA_0_MASK		(0x1FL << MFC_TCLASS_QUOTA_0_SHIFT)
+	u8  pad_0x828_0x900[0x900 - 0x828];			/* 0x828 */
+
+	/* Real Mode Support Registers */
+	u64 mfc_rm_boundary;					/* 0x900 */
+	u8  pad_0x908_0x938[0x30];				/* 0x908 */
+	u64 smf_dma_signal_sel;					/* 0x938 */
+#define mfc_dma1_mask_lsb	41
+#define mfc_dma1_shift		(63 - mfc_dma1_mask_lsb)
+#define mfc_dma1_mask		(0x3LL << mfc_dma1_shift)
+#define mfc_dma1_bits		(0x1LL << mfc_dma1_shift)
+#define mfc_dma2_mask_lsb	43
+#define mfc_dma2_shift		(63 - mfc_dma2_mask_lsb)
+#define mfc_dma2_mask		(0x3LL << mfc_dma2_shift)
+#define mfc_dma2_bits		(0x1LL << mfc_dma2_shift)
+	u8  pad_0x940_0xa38[0xf8];				/* 0x940 */
+	u64 smm_signal_sel;					/* 0xa38 */
+#define smm_sig_mask_lsb	12
+#define smm_sig_shift		(63 - smm_sig_mask_lsb)
+#define smm_sig_mask		(0x3LL << smm_sig_shift)
+#define smm_sig_bus0_bits	(0x2LL << smm_sig_shift)
+#define smm_sig_bus2_bits	(0x1LL << smm_sig_shift)
+	u8  pad_0xa40_0xc00[0xc00 - 0xa40];			/* 0xa40 */
+
+	/* DMA Command Error Area */
+	u64 mfc_cer_R;						/* 0xc00 */
+#define MFC_CER_Q		(1 << 31)
+#define MFC_CER_SPU_QUEUE	MFC_CER_Q
+	u8  pad_0xc08_0x1000[0x1000 - 0xc08];			/* 0xc08 */
+
+	/* PV1_ImplRegs: Implementation-dependent privileged-state 1 regs */
+	/* DMA Command Error Area */
+	u64 spu_ecc_cntl_RW;					/* 0x1000 */
+#define SPU_ECC_CNTL_E			(1ull << 0ull)
+#define SPU_ECC_CNTL_ENABLE		SPU_ECC_CNTL_E
+#define SPU_ECC_CNTL_DISABLE		(~SPU_ECC_CNTL_E & 1L)
+#define SPU_ECC_CNTL_S			(1ull << 1ull)
+#define SPU_ECC_STOP_AFTER_ERROR	SPU_ECC_CNTL_S
+#define SPU_ECC_CONTINUE_AFTER_ERROR	(~SPU_ECC_CNTL_S & 2L)
+#define SPU_ECC_CNTL_B			(1ull << 2ull)
+#define SPU_ECC_BACKGROUND_ENABLE	SPU_ECC_CNTL_B
+#define SPU_ECC_BACKGROUND_DISABLE	(~SPU_ECC_CNTL_B & 4L)
+#define SPU_ECC_CNTL_I_SHIFT		3ull
+#define SPU_ECC_CNTL_I_MASK		(3ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_WRITE_ALWAYS		(~SPU_ECC_CNTL_I & 12L)
+#define SPU_ECC_WRITE_CORRECTABLE	(1ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_WRITE_UNCORRECTABLE	(3ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_CNTL_D			(1ull << 5ull)
+#define SPU_ECC_DETECTION_ENABLE	SPU_ECC_CNTL_D
+#define SPU_ECC_DETECTION_DISABLE	(~SPU_ECC_CNTL_D & 32L)
+	u64 spu_ecc_stat_RW;					/* 0x1008 */
+#define SPU_ECC_CORRECTED_ERROR		(1ull << 0ul)
+#define SPU_ECC_UNCORRECTED_ERROR	(1ull << 1ul)
+#define SPU_ECC_SCRUB_COMPLETE		(1ull << 2ul)
+#define SPU_ECC_SCRUB_IN_PROGRESS	(1ull << 3ul)
+#define SPU_ECC_INSTRUCTION_ERROR	(1ull << 4ul)
+#define SPU_ECC_DATA_ERROR		(1ull << 5ul)
+#define SPU_ECC_DMA_ERROR		(1ull << 6ul)
+#define SPU_ECC_STATUS_CNT_MASK		(256ull << 8)
+	u64 spu_ecc_addr_RW;					/* 0x1010 */
+	u64 spu_err_mask_RW;					/* 0x1018 */
+#define SPU_ERR_ILLEGAL_INSTR		(1ull << 0ul)
+#define SPU_ERR_ILLEGAL_CHANNEL		(1ull << 1ul)
+	u8  pad_0x1020_0x1028[0x1028 - 0x1020];			/* 0x1020 */
+
+	/* SPU Debug-Trace Bus (DTB) Selection Registers */
+	u64 spu_trig0_sel;					/* 0x1028 */
+	u64 spu_trig1_sel;					/* 0x1030 */
+	u64 spu_trig2_sel;					/* 0x1038 */
+	u64 spu_trig3_sel;					/* 0x1040 */
+	u64 spu_trace_sel;					/* 0x1048 */
+#define spu_trace_sel_mask		0x1f1fLL
+#define spu_trace_sel_bus0_bits		0x1000LL
+#define spu_trace_sel_bus2_bits		0x0010LL
+	u64 spu_event0_sel;					/* 0x1050 */
+	u64 spu_event1_sel;					/* 0x1058 */
+	u64 spu_event2_sel;					/* 0x1060 */
+	u64 spu_event3_sel;					/* 0x1068 */
+	u64 spu_trace_cntl;					/* 0x1070 */
+} __attribute__ ((aligned(0x2000)));
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
new file mode 100644
index 0000000..ba18d7d
--- /dev/null
+++ b/include/asm-powerpc/spu_csa.h
@@ -0,0 +1,255 @@
+/*
+ * spu_csa.h: Definitions for SPU context save area (CSA).
+ *
+ * (C) Copyright IBM 2005
+ *
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SPU_CSA_H_
+#define _SPU_CSA_H_
+#ifdef __KERNEL__
+
+/*
+ * Total number of 128-bit registers.
+ */
+#define NR_SPU_GPRS         	128
+#define NR_SPU_SPRS         	9
+#define NR_SPU_REGS_PAD	    	7
+#define NR_SPU_SPILL_REGS   	144	/* GPRS + SPRS + PAD */
+#define SIZEOF_SPU_SPILL_REGS	NR_SPU_SPILL_REGS * 16
+
+#define SPU_SAVE_COMPLETE      	0x3FFB
+#define SPU_RESTORE_COMPLETE   	0x3FFC
+
+/*
+ * Definitions for various 'stopped' status conditions,
+ * to be recreated during context restore.
+ */
+#define SPU_STOPPED_STATUS_P    1
+#define SPU_STOPPED_STATUS_I    2
+#define SPU_STOPPED_STATUS_H    3
+#define SPU_STOPPED_STATUS_S    4
+#define SPU_STOPPED_STATUS_S_I  5
+#define SPU_STOPPED_STATUS_S_P  6
+#define SPU_STOPPED_STATUS_P_H  7
+#define SPU_STOPPED_STATUS_P_I  8
+#define SPU_STOPPED_STATUS_R    9
+
+#ifndef  __ASSEMBLY__
+/**
+ * spu_reg128 - generic 128-bit register definition.
+ */
+struct spu_reg128 {
+	u32 slot[4];
+};
+
+/**
+ * struct spu_lscsa - Local Store Context Save Area.
+ * @gprs: Array of saved registers.
+ * @fpcr: Saved floating point status control register.
+ * @decr: Saved decrementer value.
+ * @decr_status: Indicates decrementer run status.
+ * @ppu_mb: Saved PPU mailbox data.
+ * @ppuint_mb: Saved PPU interrupting mailbox data.
+ * @tag_mask: Saved tag group mask.
+ * @event_mask: Saved event mask.
+ * @srr0: Saved SRR0.
+ * @stopped_status: Conditions to be recreated by restore.
+ * @ls: Saved contents of Local Storage Area.
+ *
+ * The LSCSA represents state that is primarily saved and
+ * restored by SPU-side code.
+ */
+struct spu_lscsa {
+	struct spu_reg128 gprs[128];
+	struct spu_reg128 fpcr;
+	struct spu_reg128 decr;
+	struct spu_reg128 decr_status;
+	struct spu_reg128 ppu_mb;
+	struct spu_reg128 ppuint_mb;
+	struct spu_reg128 tag_mask;
+	struct spu_reg128 event_mask;
+	struct spu_reg128 srr0;
+	struct spu_reg128 stopped_status;
+	struct spu_reg128 pad[119];	/* 'ls' must be page-aligned. */
+	unsigned char ls[LS_SIZE];
+};
+
+/*
+ * struct spu_problem_collapsed - condensed problem state area, w/o pads.
+ */
+struct spu_problem_collapsed {
+	u64 spc_mssync_RW;
+	u32 mfc_lsa_W;
+	u32 unused_pad0;
+	u64 mfc_ea_W;
+	union mfc_tag_size_class_cmd mfc_union_W;
+	u32 dma_qstatus_R;
+	u32 dma_querytype_RW;
+	u32 dma_querymask_RW;
+	u32 dma_tagstatus_R;
+	u32 pu_mb_R;
+	u32 spu_mb_W;
+	u32 mb_stat_R;
+	u32 spu_runcntl_RW;
+	u32 spu_status_R;
+	u32 spu_spc_R;
+	u32 spu_npc_RW;
+	u32 signal_notify1;
+	u32 signal_notify2;
+	u32 unused_pad1;
+};
+
+/*
+ * struct spu_priv1_collapsed - condensed privileged 1 area, w/o pads.
+ */
+struct spu_priv1_collapsed {
+	u64 mfc_sr1_RW;
+	u64 mfc_lpid_RW;
+	u64 spu_idr_RW;
+	u64 mfc_vr_RO;
+	u64 spu_vr_RO;
+	u64 int_mask_class0_RW;
+	u64 int_mask_class1_RW;
+	u64 int_mask_class2_RW;
+	u64 int_stat_class0_RW;
+	u64 int_stat_class1_RW;
+	u64 int_stat_class2_RW;
+	u64 int_route_RW;
+	u64 mfc_atomic_flush_RW;
+	u64 resource_allocation_groupID_RW;
+	u64 resource_allocation_enable_RW;
+	u64 mfc_fir_R;
+	u64 mfc_fir_status_or_W;
+	u64 mfc_fir_status_and_W;
+	u64 mfc_fir_mask_R;
+	u64 mfc_fir_mask_or_W;
+	u64 mfc_fir_mask_and_W;
+	u64 mfc_fir_chkstp_enable_RW;
+	u64 smf_sbi_signal_sel;
+	u64 smf_ato_signal_sel;
+	u64 mfc_sdr_RW;
+	u64 tlb_index_hint_RO;
+	u64 tlb_index_W;
+	u64 tlb_vpn_RW;
+	u64 tlb_rpn_RW;
+	u64 tlb_invalidate_entry_W;
+	u64 tlb_invalidate_all_W;
+	u64 smm_hid;
+	u64 mfc_accr_RW;
+	u64 mfc_dsisr_RW;
+	u64 mfc_dar_RW;
+	u64 rmt_index_RW;
+	u64 rmt_data1_RW;
+	u64 mfc_dsir_R;
+	u64 mfc_lsacr_RW;
+	u64 mfc_lscrr_R;
+	u64 mfc_tclass_id_RW;
+	u64 mfc_rm_boundary;
+	u64 smf_dma_signal_sel;
+	u64 smm_signal_sel;
+	u64 mfc_cer_R;
+	u64 pu_ecc_cntl_RW;
+	u64 pu_ecc_stat_RW;
+	u64 spu_ecc_addr_RW;
+	u64 spu_err_mask_RW;
+	u64 spu_trig0_sel;
+	u64 spu_trig1_sel;
+	u64 spu_trig2_sel;
+	u64 spu_trig3_sel;
+	u64 spu_trace_sel;
+	u64 spu_event0_sel;
+	u64 spu_event1_sel;
+	u64 spu_event2_sel;
+	u64 spu_event3_sel;
+	u64 spu_trace_cntl;
+};
+
+/*
+ * struct spu_priv2_collapsed - condensed priviliged 2 area, w/o pads.
+ */
+struct spu_priv2_collapsed {
+	u64 slb_index_W;
+	u64 slb_esid_RW;
+	u64 slb_vsid_RW;
+	u64 slb_invalidate_entry_W;
+	u64 slb_invalidate_all_W;
+	struct mfc_cq_sr spuq[16];
+	struct mfc_cq_sr puq[8];
+	u64 mfc_control_RW;
+	u64 puint_mb_R;
+	u64 spu_privcntl_RW;
+	u64 spu_lslr_RW;
+	u64 spu_chnlcntptr_RW;
+	u64 spu_chnlcnt_RW;
+	u64 spu_chnldata_RW;
+	u64 spu_cfg_RW;
+	u64 spu_tag_status_query_RW;
+	u64 spu_cmd_buf1_RW;
+	u64 spu_cmd_buf2_RW;
+	u64 spu_atomic_status_RW;
+};
+
+/**
+ * struct spu_state
+ * @lscsa: Local Store Context Save Area.
+ * @prob: Collapsed Problem State Area, w/o pads.
+ * @priv1: Collapsed Privileged 1 Area, w/o pads.
+ * @priv2: Collapsed Privileged 2 Area, w/o pads.
+ * @spu_chnlcnt_RW: Array of saved channel counts.
+ * @spu_chnldata_RW: Array of saved channel data.
+ * @suspend_time: Time stamp when decrementer disabled.
+ * @slb_esid_RW: Array of saved SLB esid entries.
+ * @slb_vsid_RW: Array of saved SLB vsid entries.
+ *
+ * Structure representing the whole of the SPU
+ * context save area (CSA).  This struct contains
+ * all of the state necessary to suspend and then
+ * later optionally resume execution of an SPU
+ * context.
+ *
+ * The @lscsa region is by far the largest, and is
+ * allocated separately so that it may either be
+ * pinned or mapped to/from application memory, as
+ * appropriate for the OS environment.
+ */
+struct spu_state {
+	struct spu_lscsa *lscsa;
+	struct spu_problem_collapsed prob;
+	struct spu_priv1_collapsed priv1;
+	struct spu_priv2_collapsed priv2;
+	u64 spu_chnlcnt_RW[32];
+	u64 spu_chnldata_RW[32];
+	u32 spu_mailbox_data[4];
+	u32 pu_mailbox_data[1];
+	unsigned long suspend_time;
+	u64 slb_esid_RW[8];
+	u64 slb_vsid_RW[8];
+	spinlock_t register_lock;
+};
+
+extern void spu_init_csa(struct spu_state *csa);
+extern void spu_fini_csa(struct spu_state *csa);
+extern int spu_save(struct spu_state *prev, struct spu *spu);
+extern int spu_restore(struct spu_state *new, struct spu *spu);
+extern int spu_switch(struct spu_state *prev, struct spu_state *new,
+		      struct spu *spu);
+
+#endif /* __KERNEL__ */
+#endif /* !__ASSEMBLY__ */
+#endif /* _SPU_CSA_H_ */
diff --git a/include/asm-powerpc/synch.h b/include/asm-powerpc/synch.h
index 4660c03..794870a 100644
--- a/include/asm-powerpc/synch.h
+++ b/include/asm-powerpc/synch.h
@@ -1,7 +1,6 @@
 #ifndef _ASM_POWERPC_SYNCH_H 
 #define _ASM_POWERPC_SYNCH_H 
-
-#include <linux/config.h>
+#ifdef __KERNEL__
 
 #ifdef __powerpc64__
 #define __SUBARCH_HAS_LWSYNC
@@ -47,5 +46,6 @@
 #define isync_on_smp()	__asm__ __volatile__("": : :"memory")
 #endif
 
+#endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_SYNCH_H */
 
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 5341b75..0c58e32 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -4,7 +4,6 @@
 #ifndef _ASM_POWERPC_SYSTEM_H
 #define _ASM_POWERPC_SYSTEM_H
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 
 #include <asm/hw_irq.h>
@@ -42,6 +41,7 @@
 #define set_mb(var, value)	do { var = value; mb(); } while (0)
 #define set_wmb(var, value)	do { var = value; wmb(); } while (0)
 
+#ifdef __KERNEL__
 #ifdef CONFIG_SMP
 #define smp_mb()	mb()
 #define smp_rmb()	rmb()
@@ -54,7 +54,6 @@
 #define smp_read_barrier_depends()	do { } while(0)
 #endif /* CONFIG_SMP */
 
-#ifdef __KERNEL__
 struct task_struct;
 struct pt_regs;
 
diff --git a/include/asm-powerpc/tce.h b/include/asm-powerpc/tce.h
index 980a094..6fa200a 100644
--- a/include/asm-powerpc/tce.h
+++ b/include/asm-powerpc/tce.h
@@ -20,6 +20,7 @@
 
 #ifndef _ASM_POWERPC_TCE_H
 #define _ASM_POWERPC_TCE_H
+#ifdef __KERNEL__
 
 /*
  * Tces come in two formats, one for the virtual bus and a different
@@ -61,4 +62,5 @@
 };
 
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_TCE_H */
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index e525f49..ac1e80e 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -37,8 +37,7 @@
 	int		preempt_count;		/* 0 => preemptable,
 						   <0 => BUG */
 	struct restart_block restart_block;
-	/* set by force_successful_syscall_return */
-	unsigned char	syscall_noerror;
+	void *nvgprs_frame;
 	/* low level flags - has atomic operations done on it */
 	unsigned long	flags ____cacheline_aligned_in_smp;
 };
@@ -123,6 +122,9 @@
 #define TIF_SINGLESTEP		9	/* singlestepping active */
 #define TIF_MEMDIE		10
 #define TIF_SECCOMP		11	/* secure computing */
+#define TIF_RESTOREALL		12	/* Restore all regs (implies NOERROR) */
+#define TIF_SAVE_NVGPRS		13	/* Save r14-r31 in signal frame */
+#define TIF_NOERROR		14	/* Force successful syscall return */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -136,10 +138,14 @@
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+#define _TIF_RESTOREALL		(1<<TIF_RESTOREALL)
+#define _TIF_SAVE_NVGPRS	(1<<TIF_SAVE_NVGPRS)
+#define _TIF_NOERROR		(1<<TIF_NOERROR)
 #define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
 
 #define _TIF_USER_WORK_MASK	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
-				 _TIF_NEED_RESCHED)
+				 _TIF_NEED_RESCHED | _TIF_RESTOREALL)
+#define _TIF_PERSYSCALL_MASK	(_TIF_RESTOREALL|_TIF_NOERROR|_TIF_SAVE_NVGPRS)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-powerpc/tlb.h b/include/asm-powerpc/tlb.h
index 56659f1..601a53c 100644
--- a/include/asm-powerpc/tlb.h
+++ b/include/asm-powerpc/tlb.h
@@ -11,6 +11,7 @@
  */
 #ifndef _ASM_POWERPC_TLB_H
 #define _ASM_POWERPC_TLB_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #ifndef __powerpc64__
@@ -67,4 +68,5 @@
 }
 
 #endif
+#endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_TLB_H */
diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h
index db8095c..9f3d4da 100644
--- a/include/asm-powerpc/topology.h
+++ b/include/asm-powerpc/topology.h
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_TOPOLOGY_H
 #define _ASM_POWERPC_TOPOLOGY_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 
@@ -55,10 +56,15 @@
 	.nr_balance_failed	= 0,			\
 }
 
+extern void __init dump_numa_cpu_topology(void);
+
 #else
 
+static inline void dump_numa_cpu_topology(void) {}
+
 #include <asm-generic/topology.h>
 
 #endif /* CONFIG_NUMA */
 
+#endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_TOPOLOGY_H */
diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h
index a383383..479f2d8 100644
--- a/include/asm-powerpc/udbg.h
+++ b/include/asm-powerpc/udbg.h
@@ -9,12 +9,13 @@
 
 #ifndef _ASM_POWERPC_UDBG_H
 #define _ASM_POWERPC_UDBG_H
+#ifdef __KERNEL__
 
 #include <linux/compiler.h>
 #include <linux/init.h>
 
-extern void (*udbg_putc)(unsigned char c);
-extern unsigned char (*udbg_getc)(void);
+extern void (*udbg_putc)(char c);
+extern int (*udbg_getc)(void);
 extern int (*udbg_getc_poll)(void);
 
 extern void udbg_puts(const char *s);
@@ -23,9 +24,17 @@
 
 extern void register_early_udbg_console(void);
 extern void udbg_printf(const char *fmt, ...);
+extern void udbg_progress(char *s, unsigned short hex);
 
-extern void udbg_init_uart(void __iomem *comport, unsigned int speed);
+extern void udbg_init_uart(void __iomem *comport, unsigned int speed,
+			   unsigned int clock);
+extern unsigned int udbg_probe_uart_speed(void __iomem *comport,
+					  unsigned int clock);
 
 struct device_node;
-extern void udbg_init_scc(struct device_node *np);
+extern void udbg_scc_init(int force_scc);
+extern int udbg_adb_init(int force_btext);
+extern void udbg_adb_init_early(void);
+
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_UDBG_H */
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 0991dfc..19eaac3 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -296,8 +296,10 @@
 #define __NR_inotify_init	275
 #define __NR_inotify_add_watch	276
 #define __NR_inotify_rm_watch	277
+#define __NR_spu_run		278
+#define __NR_spu_create		279
 
-#define __NR_syscalls		278
+#define __NR_syscalls		280
 
 #ifdef __KERNEL__
 #define __NR__exit __NR_exit
diff --git a/include/asm-powerpc/vdso_datapage.h b/include/asm-powerpc/vdso_datapage.h
index 411832d..7aa9208 100644
--- a/include/asm-powerpc/vdso_datapage.h
+++ b/include/asm-powerpc/vdso_datapage.h
@@ -1,5 +1,6 @@
 #ifndef _VDSO_DATAPAGE_H
 #define _VDSO_DATAPAGE_H
+#ifdef __KERNEL__
 
 /*
  * Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM
@@ -105,4 +106,5 @@
 
 #endif /* __ASSEMBLY__ */
 
+#endif /* __KERNEL__ */
 #endif /* _SYSTEMCFG_H */
diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h
index e0ccf10..0544ece 100644
--- a/include/asm-powerpc/vio.h
+++ b/include/asm-powerpc/vio.h
@@ -13,6 +13,7 @@
 
 #ifndef _ASM_POWERPC_VIO_H
 #define _ASM_POWERPC_VIO_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <linux/init.h>
@@ -103,4 +104,5 @@
 	return container_of(dev, struct vio_dev, dev);
 }
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_VIO_H */
diff --git a/include/asm-ppc/bseip.h b/include/asm-ppc/bseip.h
deleted file mode 100644
index 691f4a5..0000000
--- a/include/asm-ppc/bseip.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * A collection of structures, addresses, and values associated with
- * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_BSEIP_DEFS
-#define __MACH_BSEIP_DEFS
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * All we need to get started is the IMMR.
- */
-#define IMAP_ADDR		((uint)0xff000000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0x04000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-#endif	/* !__ASSEMBLY__ */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif
diff --git a/include/asm-ppc/btext.h b/include/asm-ppc/btext.h
index ccaefab..ed36302 100644
--- a/include/asm-ppc/btext.h
+++ b/include/asm-ppc/btext.h
@@ -17,7 +17,7 @@
 extern boot_infos_t disp_bi;
 extern int boot_text_mapped;
 
-extern void init_boot_display(void);
+extern void btext_init(boot_infos_t *bi);
 extern void btext_welcome(void);
 extern void btext_prepare_BAT(void);
 extern void btext_setup_display(int width, int height, int depth, int pitch,
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index f01255b..39200de 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -35,8 +35,10 @@
 	int		(*get_irq)(struct pt_regs *);
 	
 	/* A general init function, called by ppc_init in init/main.c.
-	   May be NULL. */
+	   May be NULL. DEPRECATED ! */
 	void		(*init)(void);
+	/* For compatibility with merged platforms */
+	void		(*init_early)(void);
 
 	void		(*restart)(char *cmd);
 	void		(*power_off)(void);
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h
index 9d14bae..c8a96aa 100644
--- a/include/asm-ppc/mpc85xx.h
+++ b/include/asm-ppc/mpc85xx.h
@@ -37,6 +37,10 @@
 #ifdef CONFIG_STX_GP3
 #include <platforms/85xx/stx_gp3.h>
 #endif
+#if defined(CONFIG_TQM8540) || defined(CONFIG_TQM8541) || \
+	defined(CONFIG_TQM8555) || defined(CONFIG_TQM8560)
+#include <platforms/85xx/tqm85xx.h>
+#endif
 
 #define _IO_BASE        isa_io_base
 #define _ISA_MEM_BASE   isa_mem_base
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
index e58c78f..9d52306 100644
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -137,5 +137,14 @@
  */
 extern int pciauto_bus_scan(struct pci_controller *, int);
 
+#ifdef CONFIG_PCI
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#else
+static inline unsigned long pci_address_to_pio(phys_addr_t address)
+{
+	return (unsigned long)-1;
+}
+#endif
+
 #endif
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index 3e39827..eb317a0 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -136,5 +136,37 @@
 #define PTRRELOC(x)	((typeof(x))add_reloc_offset((unsigned long)(x)))
 #define PTRUNRELOC(x)	((typeof(x))sub_reloc_offset((unsigned long)(x)))
 
+
+/*
+ * OF address retreival & translation
+ */
+
+
+/* Translate an OF address block into a CPU physical address
+ */
+#define OF_BAD_ADDR	((u64)-1)
+extern u64 of_translate_address(struct device_node *np, u32 *addr);
+
+/* Extract an address from a device, returns the region size and
+ * the address space flags too. The PCI version uses a BAR number
+ * instead of an absolute index
+ */
+extern u32 *of_get_address(struct device_node *dev, int index,
+			   u64 *size, unsigned int *flags);
+extern u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+			       u64 *size, unsigned int *flags);
+
+/* Get an address as a resource. Note that if your address is
+ * a PIO address, the conversion will fail if the physical address
+ * can't be internally converted to an IO token with
+ * pci_address_to_pio(), that is because it's either called to early
+ * or it can't be matched to any host bridge IO space
+ */
+extern int of_address_to_resource(struct device_node *dev, int index,
+				  struct resource *r);
+extern int of_pci_address_to_resource(struct device_node *dev, int bar,
+				      struct resource *r);
+
+
 #endif /* _PPC_PROM_H */
 #endif /* __KERNEL__ */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index fb09853..02a585f 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -118,9 +118,9 @@
  * try to put the fields that are referenced together in the same cacheline
  */
 struct request {
-	struct list_head queuelist; /* looking for ->queue? you must _not_
-				     * access it directly, use
-				     * blkdev_dequeue_request! */
+	struct list_head queuelist;
+	struct list_head donelist;
+
 	unsigned long flags;		/* see REQ_ bits below */
 
 	/* Maintain bio traversal state for part by part I/O submission.
@@ -141,6 +141,7 @@
 	struct bio *biotail;
 
 	void *elevator_private;
+	void *completion_data;
 
 	unsigned short ioprio;
 
@@ -291,6 +292,7 @@
 typedef void (activity_fn) (void *data, int rw);
 typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *);
 typedef void (prepare_flush_fn) (request_queue_t *, struct request *);
+typedef void (softirq_done_fn)(struct request *);
 
 enum blk_queue_state {
 	Queue_down,
@@ -332,6 +334,7 @@
 	activity_fn		*activity_fn;
 	issue_flush_fn		*issue_flush_fn;
 	prepare_flush_fn	*prepare_flush_fn;
+	softirq_done_fn		*softirq_done_fn;
 
 	/*
 	 * Dispatch queue sorting
@@ -592,7 +595,6 @@
 extern void blk_put_request(struct request *);
 extern void __blk_put_request(request_queue_t *, struct request *);
 extern void blk_end_sync_rq(struct request *rq, int error);
-extern void blk_attempt_remerge(request_queue_t *, struct request *);
 extern struct request *blk_get_request(request_queue_t *, int, gfp_t);
 extern void blk_insert_request(request_queue_t *, struct request *, int, void *);
 extern void blk_requeue_request(request_queue_t *, struct request *);
@@ -646,6 +648,17 @@
 extern int end_that_request_chunk(struct request *, int, int);
 extern void end_that_request_last(struct request *, int);
 extern void end_request(struct request *req, int uptodate);
+extern void blk_complete_request(struct request *);
+
+static inline int rq_all_done(struct request *rq, unsigned int nr_bytes)
+{
+	if (blk_fs_request(rq))
+		return (nr_bytes >= (rq->hard_nr_sectors << 9));
+	else if (blk_pc_request(rq))
+		return nr_bytes >= rq->data_len;
+
+	return 0;
+}
 
 /*
  * end_that_request_first/chunk() takes an uptodate argument. we account
@@ -694,6 +707,7 @@
 extern void blk_queue_prep_rq(request_queue_t *, prep_rq_fn *pfn);
 extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(request_queue_t *, int);
+extern void blk_queue_softirq_done(request_queue_t *, softirq_done_fn *);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(request_queue_t *, unsigned, prepare_flush_fn *);
 extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *);
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index fb80fa4..4a6f50e 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -114,8 +114,6 @@
 extern int elevator_init(request_queue_t *, char *);
 extern void elevator_exit(elevator_t *);
 extern int elv_rq_merge_ok(struct request *, struct bio *);
-extern int elv_try_merge(struct request *, struct bio *);
-extern int elv_try_last_merge(request_queue_t *, struct bio *);
 
 /*
  * Return values from elevator merger
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 4dd6694..ef8d0cb 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -1001,6 +1001,7 @@
 
 extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
 extern int __ide_end_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs);
+extern void ide_softirq_done(struct request *rq);
 
 /*
  * This is used on exit from the driver to designate the next irq handler
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index e50a95f..2c08fdc 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -112,7 +112,7 @@
 	TIMER_SOFTIRQ,
 	NET_TX_SOFTIRQ,
 	NET_RX_SOFTIRQ,
-	SCSI_SOFTIRQ,
+	BLOCK_SOFTIRQ,
 	TASKLET_SOFTIRQ
 };
 
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index e2a089b..d27a78b 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -196,6 +196,7 @@
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_HT_IRQCONF	0x08	/* HyperTransport IRQ Configuration */
 #define  PCI_CAP_ID_SHPC 	0x0C	/* PCI Standard Hot-Plug Controller */
 #define  PCI_CAP_ID_EXP 	0x10	/* PCI Express */
 #define  PCI_CAP_ID_MSIX	0x11	/* MSI-X */
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 373bd3b..217d3da 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -140,7 +140,7 @@
 
 extern int pmu_request(struct adb_request *req,
 		void (*done)(struct adb_request *), int nbytes, ...);
-
+extern int pmu_queue_request(struct adb_request *req);
 extern void pmu_poll(void);
 extern void pmu_poll_adb(void); /* For use by xmon */
 extern void pmu_wait_complete(struct adb_request *req);
@@ -160,12 +160,6 @@
 extern int pmu_present(void);
 extern int pmu_get_model(void);
 
-extern int pmu_i2c_combined_read(int bus, int addr, int subaddr,  u8* data, int len);
-extern int pmu_i2c_stdsub_write(int bus, int addr, int subaddr,  u8* data, int len);
-extern int pmu_i2c_simple_read(int bus, int addr,  u8* data, int len);
-extern int pmu_i2c_simple_write(int bus, int addr,  u8* data, int len);
-
-
 #ifdef CONFIG_PM
 /*
  * Stuff for putting the powerbook to sleep and waking it again.
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 51747cd..a1d26cb 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -125,36 +125,7 @@
 	rdp->passed_quiesc = 1;
 }
 
-static inline int __rcu_pending(struct rcu_ctrlblk *rcp,
-						struct rcu_data *rdp)
-{
-	/* This cpu has pending rcu entries and the grace period
-	 * for them has completed.
-	 */
-	if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
-		return 1;
-
-	/* This cpu has no pending entries, but there are new entries */
-	if (!rdp->curlist && rdp->nxtlist)
-		return 1;
-
-	/* This cpu has finished callbacks to invoke */
-	if (rdp->donelist)
-		return 1;
-
-	/* The rcu core waits for a quiescent state from the cpu */
-	if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
-		return 1;
-
-	/* nothing to do */
-	return 0;
-}
-
-static inline int rcu_pending(int cpu)
-{
-	return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
-		__rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
-}
+extern int rcu_pending(int cpu);
 
 /**
  * rcu_read_lock - mark the beginning of an RCU read-side critical section.
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index e910d1a..3eed473 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -514,4 +514,9 @@
 asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
 			const unsigned long __user *from, const unsigned long __user *to);
 
+asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
+				 __u32 __user *ustatus);
+asmlinkage long sys_spu_create(const char __user *name,
+		unsigned int flags, mode_t mode);
+
 #endif
diff --git a/include/video/cyblafb.h b/include/video/cyblafb.h
index a994823..7174405 100644
--- a/include/video/cyblafb.h
+++ b/include/video/cyblafb.h
@@ -153,6 +153,10 @@
 #define GE04	(GEBase+0x04)	// source 2, p 111
 #define GE08	(GEBase+0x08)	// destination 1, p 111
 #define GE0C	(GEBase+0x0C)	// destination 2, p 112
+#define GE10	(GEBase+0x10)	// right view base & enable, p 112
+#define GE13	(GEBase+0x13)	// left view base & enable, p 112
+#define GE18	(GEBase+0x18)	// block write start address, p 112
+#define GE1C	(GEBase+0x1C)	// block write end address, p 112
 #define GE20	(GEBase+0x20)	// engine status, p 113
 #define GE24	(GEBase+0x24)	// reset all GE pointers
 #define GE44	(GEBase+0x44)	// command register, p 126
diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
index 334c37f..fccb27d 100644
--- a/kernel/crash_dump.c
+++ b/kernel/crash_dump.c
@@ -14,10 +14,12 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/kexec.h>
 
 /* Stores the physical address of elf header of crash image. */
 unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
 
+#ifndef HAVE_ARCH_COPY_OLDMEM_PAGE
 /**
  * copy_oldmem_page - copy one page from "oldmem"
  * @pfn: page frame number to be copied
@@ -59,3 +61,4 @@
 	kfree(page);
 	return csize;
 }
+#endif
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 30b0bba..ccc45d4 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -429,6 +429,36 @@
 				&__get_cpu_var(rcu_bh_data));
 }
 
+static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
+{
+	/* This cpu has pending rcu entries and the grace period
+	 * for them has completed.
+	 */
+	if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
+		return 1;
+
+	/* This cpu has no pending entries, but there are new entries */
+	if (!rdp->curlist && rdp->nxtlist)
+		return 1;
+
+	/* This cpu has finished callbacks to invoke */
+	if (rdp->donelist)
+		return 1;
+
+	/* The rcu core waits for a quiescent state from the cpu */
+	if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
+		return 1;
+
+	/* nothing to do */
+	return 0;
+}
+
+int rcu_pending(int cpu)
+{
+	return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
+		__rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
+}
+
 void rcu_check_callbacks(int cpu, int user)
 {
 	if (user || 
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index bd3b9bf..17313b9 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -112,3 +112,5 @@
 cond_syscall(sys32_ipc);
 cond_syscall(sys32_sysctl);
 cond_syscall(ppc_rtas);
+cond_syscall(sys_spu_run);
+cond_syscall(sys_spu_create);
diff --git a/mm/memory.c b/mm/memory.c
index 7197f9b..3944fec 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2267,6 +2267,8 @@
 	return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
 }
 
+EXPORT_SYMBOL_GPL(__handle_mm_fault);
+
 #ifndef __PAGETABLE_PUD_FOLDED
 /*
  * Allocate page upper directory.
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
index 073aebd..f8dca31 100644
--- a/net/ieee80211/ieee80211_crypt_wep.c
+++ b/net/ieee80211/ieee80211_crypt_wep.c
@@ -75,22 +75,14 @@
 	kfree(priv);
 }
 
-/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
- * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
- * so the payload length increases with 8 bytes.
- *
- * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
- */
-static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
+static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv)
 {
 	struct prism2_wep_data *wep = priv;
-	u32 crc, klen, len;
-	u8 key[WEP_KEY_LEN + 3];
-	u8 *pos, *icv;
-	struct scatterlist sg;
-
-	if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
-	    skb->len < hdr_len)
+	u32 klen, len;
+	u8 *pos;
+	
+	if (skb_headroom(skb) < 4 || skb->len < hdr_len)
 		return -1;
 
 	len = skb->len - hdr_len;
@@ -112,15 +104,47 @@
 	}
 
 	/* Prepend 24-bit IV to RC4 key and TX frame */
-	*pos++ = key[0] = (wep->iv >> 16) & 0xff;
-	*pos++ = key[1] = (wep->iv >> 8) & 0xff;
-	*pos++ = key[2] = wep->iv & 0xff;
+	*pos++ = (wep->iv >> 16) & 0xff;
+	*pos++ = (wep->iv >> 8) & 0xff;
+	*pos++ = wep->iv & 0xff;
 	*pos++ = wep->key_idx << 6;
 
+	return 0;
+}
+
+/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
+ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
+ * so the payload length increases with 8 bytes.
+ *
+ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
+ */
+static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+	struct prism2_wep_data *wep = priv;
+	u32 crc, klen, len;
+	u8 *pos, *icv;
+	struct scatterlist sg;
+	u8 key[WEP_KEY_LEN + 3];
+
+	/* other checks are in prism2_wep_build_iv */
+	if (skb_tailroom(skb) < 4)
+		return -1;
+	
+	/* add the IV to the frame */
+	if (prism2_wep_build_iv(skb, hdr_len, priv))
+		return -1;
+	
+	/* Copy the IV into the first 3 bytes of the key */
+	memcpy(key, skb->data + hdr_len, 3);
+
 	/* Copy rest of the WEP key (the secret part) */
 	memcpy(key + 3, wep->key, wep->key_len);
+	
+	len = skb->len - hdr_len - 4;
+	pos = skb->data + hdr_len + 4;
+	klen = 3 + wep->key_len;
 
-	/* Append little-endian CRC32 and encrypt it to produce ICV */
+	/* Append little-endian CRC32 over only the data and encrypt it to produce ICV */
 	crc = ~crc32_le(~0, pos, len);
 	icv = skb_put(skb, 4);
 	icv[0] = crc;
@@ -231,6 +255,7 @@
 	.name = "WEP",
 	.init = prism2_wep_init,
 	.deinit = prism2_wep_deinit,
+	.build_iv = prism2_wep_build_iv,
 	.encrypt_mpdu = prism2_wep_encrypt,
 	.decrypt_mpdu = prism2_wep_decrypt,
 	.encrypt_msdu = NULL,
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 445f206..e5b33c8 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -288,7 +288,7 @@
 	/* Determine total amount of storage required for TXB packets */
 	bytes = skb->len + SNAP_SIZE + sizeof(u16);
 
-	if (host_encrypt)
+	if (host_encrypt || host_build_iv)
 		fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
 		    IEEE80211_FCTL_PROTECTED;
 	else
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 181755f..406d5b9 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -284,7 +284,7 @@
 	};
 	int i, key, key_provided, len;
 	struct ieee80211_crypt_data **crypt;
-	int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
+	int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
 
 	IEEE80211_DEBUG_WX("SET_ENCODE\n");
 
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 7849cac..a67f1b4 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -402,7 +402,7 @@
 	groups = nl_table[protocol].groups;
 	netlink_unlock_table();
 
-	if ((err = __netlink_create(sock, protocol) < 0))
+	if ((err = __netlink_create(sock, protocol)) < 0)
 		goto out_module;
 
 	nlk = nlk_sk(sock->sk);
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index cebd881..74f9756 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -125,6 +125,7 @@
 static int awacs_subframe;
 static struct device_node* awacs_node;
 static struct device_node* i2s_node;
+static struct resource awacs_rsrc[3];
 
 static char awacs_name[64];
 static int awacs_revision;
@@ -667,9 +668,12 @@
 	iounmap(awacs_txdma);
 	iounmap(awacs_rxdma);
 
-	release_OF_resource(awacs_node, 0);
-	release_OF_resource(awacs_node, 1);
-	release_OF_resource(awacs_node, 2);
+	release_mem_region(awacs_rsrc[0].start,
+			   awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+	release_mem_region(awacs_rsrc[1].start,
+			   awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+	release_mem_region(awacs_rsrc[2].start,
+			   awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
 
 	kfree(awacs_tx_cmd_space);
 	kfree(awacs_rx_cmd_space);
@@ -2863,46 +2867,58 @@
 	 * other info if necessary (early AWACS we want to read chip ids)
 	 */
 
-	if (io->n_addrs < 3 || io->n_intrs < 3) {
+	if (of_get_address(io, 2, NULL, NULL) == NULL || io->n_intrs < 3) {
 		/* OK - maybe we need to use the 'awacs' node (on earlier
 		 * machines).
-		*/
+		 */
 		if (awacs_node) {
 			io = awacs_node ;
-			if (io->n_addrs < 3 || io->n_intrs < 3) {
-				printk("dmasound_pmac: can't use %s"
-					" (%d addrs, %d intrs)\n",
-		      		 io->full_name, io->n_addrs, io->n_intrs);
+			if (of_get_address(io, 2, NULL, NULL) == NULL ||
+			    io->n_intrs < 3) {
+				printk("dmasound_pmac: can't use %s\n",
+				       io->full_name);
 				return -ENODEV;
 			}
-		} else {
-			printk("dmasound_pmac: can't use %s (%d addrs, %d intrs)\n",
-		 	      io->full_name, io->n_addrs, io->n_intrs);
-		}
+		} else
+			printk("dmasound_pmac: can't use %s\n", io->full_name);
 	}
 
-	if (!request_OF_resource(io, 0, NULL)) {
+	if (of_address_to_resource(io, 0, &awacs_rsrc[0]) ||
+	    request_mem_region(awacs_rsrc[0].start,
+			       awacs_rsrc[0].end - awacs_rsrc[0].start + 1,
+			       " (IO)") == NULL) {
 		printk(KERN_ERR "dmasound: can't request IO resource !\n");
 		return -ENODEV;
 	}
-	if (!request_OF_resource(io, 1, " (tx dma)")) {
-		release_OF_resource(io, 0);
-		printk(KERN_ERR "dmasound: can't request TX DMA resource !\n");
+	if (of_address_to_resource(io, 1, &awacs_rsrc[1]) ||
+	    request_mem_region(awacs_rsrc[1].start,
+			       awacs_rsrc[1].end - awacs_rsrc[1].start + 1,
+			       " (tx dma)") == NULL) {
+		release_mem_region(awacs_rsrc[0].start,
+				   awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+		printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n");
 		return -ENODEV;
 	}
-
-	if (!request_OF_resource(io, 2, " (rx dma)")) {
-		release_OF_resource(io, 0);
-		release_OF_resource(io, 1);
-		printk(KERN_ERR "dmasound: can't request RX DMA resource !\n");
+	if (of_address_to_resource(io, 2, &awacs_rsrc[2]) ||
+	    request_mem_region(awacs_rsrc[2].start,
+			       awacs_rsrc[2].end - awacs_rsrc[2].start + 1,
+			       " (rx dma)") == NULL) {
+		release_mem_region(awacs_rsrc[0].start,
+				   awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+		release_mem_region(awacs_rsrc[1].start,
+				   awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+		printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n");
 		return -ENODEV;
 	}
 
 	awacs_beep_dev = input_allocate_device();
 	if (!awacs_beep_dev) {
-		release_OF_resource(io, 0);
-		release_OF_resource(io, 1);
-		release_OF_resource(io, 2);
+		release_mem_region(awacs_rsrc[0].start,
+				   awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+		release_mem_region(awacs_rsrc[1].start,
+				   awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+		release_mem_region(awacs_rsrc[2].start,
+				   awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
 		printk(KERN_ERR "dmasound: can't allocate input device !\n");
 		return -ENOMEM;
 	}
@@ -2916,11 +2932,11 @@
 
 	/* all OF versions I've seen use this value */
 	if (i2s_node)
-		i2s = ioremap(io->addrs[0].address, 0x1000);
+		i2s = ioremap(awacs_rsrc[0].start, 0x1000);
 	else
-		awacs = ioremap(io->addrs[0].address, 0x1000);
-	awacs_txdma = ioremap(io->addrs[1].address, 0x100);
-	awacs_rxdma = ioremap(io->addrs[2].address, 0x100);
+		awacs = ioremap(awacs_rsrc[0].start, 0x1000);
+	awacs_txdma = ioremap(awacs_rsrc[1].start, 0x100);
+	awacs_rxdma = ioremap(awacs_rsrc[2].start, 0x100);
 
 	/* first of all make sure that the chip is powered up....*/
 	pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1);
@@ -3083,9 +3099,10 @@
 		struct device_node* mio;
 		macio_base = NULL;
 		for (mio = io->parent; mio; mio = mio->parent) {
-			if (strcmp(mio->name, "mac-io") == 0
-			    && mio->n_addrs > 0) {
-				macio_base = ioremap(mio->addrs[0].address, 0x40);
+			if (strcmp(mio->name, "mac-io") == 0) {
+				struct resource r;
+				if (of_address_to_resource(mio, 0, &r) == 0)
+					macio_base = ioremap(r.start, 0x40);
 				break;
 			}
 		}
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 9b2b00f..a642e4c 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -803,21 +803,17 @@
 		iounmap(chip->playback.dma);
 	if (chip->capture.dma)
 		iounmap(chip->capture.dma);
-#ifndef CONFIG_PPC64
+
 	if (chip->node) {
 		int i;
-
 		for (i = 0; i < 3; i++) {
-			if (chip->of_requested & (1 << i)) {
-				if (chip->is_k2)
-					release_OF_resource(chip->node->parent,
-							    i);
-				else
-					release_OF_resource(chip->node, i);
-			}
+			if (chip->requested & (1 << i))
+				release_mem_region(chip->rsrc[i].start,
+						   chip->rsrc[i].end -
+						   chip->rsrc[i].start + 1);
 		}
 	}
-#endif /* CONFIG_PPC64 */
+
 	if (chip->pdev)
 		pci_dev_put(chip->pdev);
 	kfree(chip);
@@ -991,6 +987,11 @@
 			chip->can_byte_swap = 0; /* FIXME: check this */
 			chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
 			break;
+		default:
+			printk(KERN_ERR "snd: Unknown layout ID 0x%x\n",
+			       layout_id);
+			return -ENODEV;
+
 		}
 	}
 	prop = (unsigned int *)get_property(sound, "device-id", NULL);
@@ -1175,46 +1176,69 @@
 	}
 
 	np = chip->node;
+	chip->requested = 0;
 	if (chip->is_k2) {
-		if (np->parent->n_addrs < 2 || np->n_intrs < 3) {
+		static char *rnames[] = {
+			"Sound Control", "Sound DMA" };
+		if (np->n_intrs < 3) {
 			err = -ENODEV;
 			goto __error;
 		}
-		for (i = 0; i < 2; i++) {
-#ifndef CONFIG_PPC64
-			static char *name[2] = { "- Control", "- DMA" };
-			if (! request_OF_resource(np->parent, i, name[i])) {
-				snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+		for (i = 0; i < 2; i ++) {
+			if (of_address_to_resource(np->parent, i,
+						   &chip->rsrc[i])) {
+				printk(KERN_ERR "snd: can't translate rsrc "
+				       " %d (%s)\n", i, rnames[i]);
 				err = -ENODEV;
 				goto __error;
 			}
-			chip->of_requested |= (1 << i);
-#endif /* CONFIG_PPC64 */
-			ctrl_addr = np->parent->addrs[0].address;
-			txdma_addr = np->parent->addrs[1].address;
-			rxdma_addr = txdma_addr + 0x100;
+			if (request_mem_region(chip->rsrc[i].start,
+					       chip->rsrc[i].end -
+					       chip->rsrc[i].start + 1,
+					       rnames[i]) == NULL) {
+				printk(KERN_ERR "snd: can't request rsrc "
+				       " %d (%s: 0x%08lx:%08lx)\n",
+				       i, rnames[i], chip->rsrc[i].start,
+				       chip->rsrc[i].end);
+				err = -ENODEV;
+				goto __error;
+			}
+			chip->requested |= (1 << i);
 		}
-
+		ctrl_addr = chip->rsrc[0].start;
+		txdma_addr = chip->rsrc[1].start;
+		rxdma_addr = txdma_addr + 0x100;
 	} else {
-		if (np->n_addrs < 3 || np->n_intrs < 3) {
+		static char *rnames[] = {
+			"Sound Control", "Sound Tx DMA", "Sound Rx DMA" };
+		if (np->n_intrs < 3) {
 			err = -ENODEV;
 			goto __error;
 		}
-
-		for (i = 0; i < 3; i++) {
-#ifndef CONFIG_PPC64
-			static char *name[3] = { "- Control", "- Tx DMA", "- Rx DMA" };
-			if (! request_OF_resource(np, i, name[i])) {
-				snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+		for (i = 0; i < 3; i ++) {
+			if (of_address_to_resource(np->parent, i,
+						   &chip->rsrc[i])) {
+				printk(KERN_ERR "snd: can't translate rsrc "
+				       " %d (%s)\n", i, rnames[i]);
 				err = -ENODEV;
 				goto __error;
 			}
-			chip->of_requested |= (1 << i);
-#endif /* CONFIG_PPC64 */
-			ctrl_addr = np->addrs[0].address;
-			txdma_addr = np->addrs[1].address;
-			rxdma_addr = np->addrs[2].address;
+			if (request_mem_region(chip->rsrc[i].start,
+					       chip->rsrc[i].end -
+					       chip->rsrc[i].start + 1,
+					       rnames[i]) == NULL) {
+				printk(KERN_ERR "snd: can't request rsrc "
+				       " %d (%s: 0x%08lx:%08lx)\n",
+				       i, rnames[i], chip->rsrc[i].start,
+				       chip->rsrc[i].end);
+				err = -ENODEV;
+				goto __error;
+			}
+			chip->requested |= (1 << i);
 		}
+		ctrl_addr = chip->rsrc[0].start;
+		txdma_addr = chip->rsrc[1].start;
+		rxdma_addr = chip->rsrc[2].start;
 	}
 
 	chip->awacs = ioremap(ctrl_addr, 0x1000);
@@ -1266,9 +1290,11 @@
 	} else if (chip->is_pbook_G3) {
 		struct device_node* mio;
 		for (mio = chip->node->parent; mio; mio = mio->parent) {
-			if (strcmp(mio->name, "mac-io") == 0
-			    && mio->n_addrs > 0) {
-				chip->macio_base = ioremap(mio->addrs[0].address, 0x40);
+			if (strcmp(mio->name, "mac-io") == 0) {
+				struct resource r;
+				if (of_address_to_resource(mio, 0, &r) == 0)
+					chip->macio_base =
+						ioremap(r.start, 0x40);
 				break;
 			}
 		}
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
index 086da7a..3a9bd4d 100644
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -113,7 +113,8 @@
 	unsigned int initialized : 1;
 	unsigned int feature_is_set : 1;
 
-	unsigned int of_requested;
+	unsigned int requested;
+	struct resource rsrc[3];
 
 	int num_freqs;
 	int *freq_table;