linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/32] My current serie of patches for 2.6.20 for review
@ 2006-11-10  7:44 Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 2/32] Call platform_notify_remove later Benjamin Herrenschmidt
                   ` (31 more replies)
  0 siblings, 32 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This should be ready for merge in powerpc tree

This is the whole of my current patch set that I intend to merge
as soon as 2.6.20 merge window opens. I'm posting them here for
review, some of them already had a few iterations on the list by
their own, some didn't show up publically at all yet.

Note that the first 5 ones require specific comments:

* ibmveth: Remove ibmveth "liobn" field

  is already queued with Jeff Garzik and will get in 2.6.20
  via his merge tree

* Call platform_notify_remove later

  is queued in -mm and Andrew sent it to Greg, I expect greg to
  merge it in 2.6.20

* Driver core: add notification of bus events

  is queued in Greg's tree and scheduled for merge in 2.6.20

* arch provides generic iomap missing accessors

  was written by Linus but is not merged yet. He asked me to
  resend it when needed, so I'll include it with the other patches
  when the merge window opens.

* Add arch specific dev_sysdata to struct device

  this is under discussion. I haven't had much comment yet, a few
  postitives though. I hope it will make 2.6.20 without problem,
  but we'll know in the upcoming couple of days.

* Change ACPI to use dev_sysdata instead of firmware_data

  this is a patch that goes along the previous one (though not actually
  necessary). It doesn't actually need to go in powerpc.git nor 2.6.20,
  I included it in this serie for completeness

This patch set started its life as the support for the new "Axon"
southbridge for cell (which includes such things as MMIO mapped DCR
and 4xx-type devices). However, as things evolved, I ended up doing
a lot more than just the basic support. Among other highlights of
this patch serie are:

 - Generic DCR support for both 4xx-type DCRs and MMIO mapped DCR and
MPIC & EMAC changes to work with that

 - Souped up of_platform_driver to make it easier to register entire
trees of devices at once, along with PCI host bridge detection support
for 64 bits architectures. Note that some name changes might break
compile of some platforms. I hope to have fixed everything before I
merge but don't forget to tell me if I missed something.

 - Completely reworked 64 bits DMA operations

 - Possibility to "hook" on PCI MMIO and PCI operations from the platform
code for use by iSeries, Cell and possibly others who have to deal with
weird hypervisor or PCI host bridge erratas. Currently supported only on
64 bits but would be easy to make it work on 32 bits if ever needed.

 - Merged 32 and 64 bits io.h. ARCH=powerpc now uses asm-powerpc/io.h
for both. ARCH=ppc still uses the old one in asm-ppc as I really don't
feel like dealing with some of the cruft in there.

 - As a consequence of the 2 above, new accessors are available that match
what is done by other architectures: {read,write}{w,l,q}_be for big endian
PCI MMIO accesses, {read,write}s{b,w,l} for MMIO "repeat" operations, and
a significant cleanup of the EEH stuff.

 - Cell IOMMU support (mostly written by Jeremy Kerr)

And more ...

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

* [PATCH 1/32] ibmveth: Remove ibmveth "liobn" field
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 2/32] Call platform_notify_remove later Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 4/32] arch provides generic iomap missing accessors Benjamin Herrenschmidt
                   ` (29 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

Remove the now unused "liobn" field in ibmveth which also avoids
having insider knowledge of the iommu table in that driver.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Santiago Leon <santil@us.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
---

Already in Jeff's queue.

 drivers/net/ibmveth.c |    4 ----
 drivers/net/ibmveth.h |    1 -
 2 files changed, 5 deletions(-)

Index: linux-cell/drivers/net/ibmveth.c
===================================================================
--- linux-cell.orig/drivers/net/ibmveth.c	2006-10-23 14:41:38.000000000 +1000
+++ linux-cell/drivers/net/ibmveth.c	2006-10-25 14:12:05.000000000 +1000
@@ -50,7 +50,6 @@
 #include <asm/semaphore.h>
 #include <asm/hvcall.h>
 #include <asm/atomic.h>
-#include <asm/iommu.h>
 #include <asm/vio.h>
 #include <asm/uaccess.h>
 #include <linux/seq_file.h>
@@ -1000,8 +999,6 @@ static int __devinit ibmveth_probe(struc
 	adapter->mac_addr = 0;
 	memcpy(&adapter->mac_addr, mac_addr_p, 6);
 
-	adapter->liobn = dev->iommu_table->it_index;
-
 	netdev->irq = dev->irq;
 	netdev->open               = ibmveth_open;
 	netdev->poll               = ibmveth_poll;
@@ -1115,7 +1112,6 @@ static int ibmveth_seq_show(struct seq_f
 	seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
 
 	seq_printf(seq, "Unit Address:    0x%x\n", adapter->vdev->unit_address);
-	seq_printf(seq, "LIOBN:           0x%lx\n", adapter->liobn);
 	seq_printf(seq, "Current MAC:     %02X:%02X:%02X:%02X:%02X:%02X\n",
 		   current_mac[0], current_mac[1], current_mac[2],
 		   current_mac[3], current_mac[4], current_mac[5]);
Index: linux-cell/drivers/net/ibmveth.h
===================================================================
--- linux-cell.orig/drivers/net/ibmveth.h	2006-10-06 13:48:09.000000000 +1000
+++ linux-cell/drivers/net/ibmveth.h	2006-10-25 14:10:39.000000000 +1000
@@ -118,7 +118,6 @@ struct ibmveth_adapter {
     struct net_device_stats stats;
     unsigned int mcastFilterSize;
     unsigned long mac_addr;
-    unsigned long liobn;
     void * buffer_list_addr;
     void * filter_list_addr;
     dma_addr_t buffer_list_dma;

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

* [PATCH 2/32] Call platform_notify_remove later
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 1/32] ibmveth: Remove ibmveth "liobn" field Benjamin Herrenschmidt
                   ` (30 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

Move the call to platform_notify_remove() to after the call to
bus_remove_device(), where it belongs.  It's bogus to notify the platform
of removal while drivers are still attached to the device and possibly
still operating since the platform might use this callback to tear down
some resources used by the driver (ACPI bits, iommu table, ...)

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: "Brown, Len" <len.brown@intel.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>

---
This patch is already in -mm under the name

call-platform_notify_remove-later.patch

 drivers/base/core.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Index: linux-cell/drivers/base/core.c
===================================================================
--- linux-cell.orig/drivers/base/core.c	2006-10-25 13:04:40.000000000 +1000
+++ linux-cell/drivers/base/core.c	2006-10-25 13:04:56.000000000 +1000
@@ -615,12 +615,13 @@ void device_del(struct device * dev)
 	device_remove_groups(dev);
 	device_remove_attrs(dev);
 
+	bus_remove_device(dev);
+
 	/* Notify the platform of the removal, in case they
 	 * need to do anything...
 	 */
 	if (platform_notify_remove)
 		platform_notify_remove(dev);
-	bus_remove_device(dev);
 	device_pm_remove(dev);
 	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);

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

* [PATCH 3/32] Driver core: add notification of bus events
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (2 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 4/32] arch provides generic iomap missing accessors Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 5/32] Add arch specific dev_sysdata to struct device Benjamin Herrenschmidt
                   ` (27 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

I finally did as you suggested and added the notifier to the struct
bus_type itself. There are still problems to be expected is something
attaches to a bus type where the code can hook in different struct
device sub-classes (which is imho a big bogosity but I won't even try to
argue that case now) but it will solve nicely a number of issues I've
had so far.

That also means that clients interested in registering for such
notifications have to do it before devices are added and after bus types
are registered. Fortunately, most bus types that matter for the various
usage scenarios I have in mind are registerd at postcore_initcall time,
which means I have a really nice spot at arch_initcall time to add my
notifiers.

There are 4 notifications provided. Device being added (before hooked to
the bus) and removed (failure of previous case or after being unhooked
from the bus), along with driver being bound to a device and about to be
unbound.

The usage I have for these are:

 - The 2 first ones are used to maintain the DMA operations for various
bus types via the new dev_sysdata addition to struct device (added by
a separate patch).

 - The other two ones have a completely different usage scenario. I have
cases where multiple devices and their drivers depend on each other. For
example, the IBM EMAC network driver needs to attach to a MAL DMA engine
which is a separate device, and a PHY interface which is also a separate
device. They are all of_platform_device's (well, about to be with my
upcoming patches) but there is no say in what precise order the core
will "probe" them and instanciate the various modules. The solution I
found for that is to have the drivers for emac to use multithread_probe,
and wait for a driver to be bound to the target MAL and PHY control
devices (the device-tree contains reference to the MAL and PHY interface
nodes, which I can then match to of_platform_devices). Right now, I've
been polling, but with that notifier, I can more cleanly wait (with a
timeout of course).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

This patch is already in Greg KH tree under the name

driver-core-add-notification-of-bus-events.patch

 drivers/base/bus.c     |   15 +++++++++++++++
 drivers/base/core.c    |   12 ++++++++++++
 drivers/base/dd.c      |   10 ++++++++++
 include/linux/device.h |   25 ++++++++++++++++++++++++-
 4 files changed, 61 insertions(+), 1 deletion(-)

Index: linux-cell/drivers/base/core.c
===================================================================
--- linux-cell.orig/drivers/base/core.c	2006-11-02 13:20:21.000000000 +1100
+++ linux-cell/drivers/base/core.c	2006-11-02 13:20:24.000000000 +1100
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/kdev_t.h>
+#include <linux/notifier.h>
 
 #include <asm/semaphore.h>
 
@@ -428,6 +429,11 @@ int device_add(struct device *dev)
 	if (platform_notify)
 		platform_notify(dev);
 
+	/* notify clients of device entry (new way) */
+	if (dev->bus)
+		blocking_notifier_call_chain(&dev->bus->bus_notifier,
+					     BUS_NOTIFY_ADD_DEVICE, dev);
+
 	dev->uevent_attr.attr.name = "uevent";
 	dev->uevent_attr.attr.mode = S_IWUSR;
 	if (dev->driver)
@@ -504,6 +510,9 @@ int device_add(struct device *dev)
  BusError:
 	device_pm_remove(dev);
  PMError:
+	if (dev->bus)
+		blocking_notifier_call_chain(&dev->bus->bus_notifier,
+					     BUS_NOTIFY_DEL_DEVICE, dev);
 	device_remove_groups(dev);
  GroupError:
  	device_remove_attrs(dev);
@@ -622,6 +631,9 @@ void device_del(struct device * dev)
 	 */
 	if (platform_notify_remove)
 		platform_notify_remove(dev);
+	if (dev->bus)
+		blocking_notifier_call_chain(&dev->bus->bus_notifier,
+					     BUS_NOTIFY_DEL_DEVICE, dev);
 	device_pm_remove(dev);
 	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
Index: linux-cell/include/linux/device.h
===================================================================
--- linux-cell.orig/include/linux/device.h	2006-10-25 12:50:17.000000000 +1000
+++ linux-cell/include/linux/device.h	2006-11-02 13:20:24.000000000 +1100
@@ -42,6 +42,8 @@ struct bus_type {
 	struct klist		klist_devices;
 	struct klist		klist_drivers;
 
+	struct blocking_notifier_head bus_notifier;
+
 	struct bus_attribute	* bus_attrs;
 	struct device_attribute	* dev_attrs;
 	struct driver_attribute	* drv_attrs;
@@ -75,6 +77,28 @@ int __must_check bus_for_each_drv(struct
 		struct device_driver *start, void *data,
 		int (*fn)(struct device_driver *, void *));
 
+/* Bus notifiers: Get notified of addition/removal of devices
+ * and binding/unbinding of drivers to devices.
+ * In the long run, it should be a replacement for the platform
+ * notify hooks.
+ */
+struct notifier_block;
+
+extern int register_bus_notifier(struct bus_type *bus,
+				 struct notifier_block *nb);
+extern int unregister_bus_notifier(struct bus_type *bus,
+				   struct notifier_block *nb);
+
+/* All 4 notifers below get called with the target struct device *
+ * as an argument. Note that those functions are likely to be called
+ * with the device semaphore held in the core, so be careful.
+ */
+#define BUS_NOTIFY_ADD_DEVICE		0x00000001 /* device added */
+#define BUS_NOTIFY_DEL_DEVICE		0x00000002 /* device removed */
+#define BUS_NOTIFY_BOUND_DRIVER		0x00000003 /* driver bound to device */
+#define BUS_NOTIFY_UNBIND_DRIVER	0x00000004 /* driver about to be
+						      unbound */
+
 /* driverfs interface for exporting bus attributes */
 
 struct bus_attribute {
@@ -427,7 +451,6 @@ extern int (*platform_notify)(struct dev
 
 extern int (*platform_notify_remove)(struct device * dev);
 
-
 /**
  * get_device - atomically increment the reference count for the device.
  *
Index: linux-cell/drivers/base/bus.c
===================================================================
--- linux-cell.orig/drivers/base/bus.c	2006-10-23 14:41:37.000000000 +1000
+++ linux-cell/drivers/base/bus.c	2006-11-02 13:20:24.000000000 +1100
@@ -724,6 +724,8 @@ int bus_register(struct bus_type * bus)
 {
 	int retval;
 
+	BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
+
 	retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);
 	if (retval)
 		goto out;
@@ -782,6 +784,16 @@ void bus_unregister(struct bus_type * bu
 	subsystem_unregister(&bus->subsys);
 }
 
+int register_bus_notifier(struct bus_type *bus, struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&bus->bus_notifier, nb);
+}
+
+int unregister_bus_notifier(struct bus_type *bus, struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&bus->bus_notifier, nb);
+}
+
 int __init buses_init(void)
 {
 	return subsystem_register(&bus_subsys);
@@ -798,3 +810,6 @@ EXPORT_SYMBOL_GPL(bus_rescan_devices);
 
 EXPORT_SYMBOL_GPL(bus_create_file);
 EXPORT_SYMBOL_GPL(bus_remove_file);
+
+EXPORT_SYMBOL_GPL(register_bus_notifier);
+EXPORT_SYMBOL_GPL(unregister_bus_notifier);
Index: linux-cell/drivers/base/dd.c
===================================================================
--- linux-cell.orig/drivers/base/dd.c	2006-10-30 08:00:39.000000000 +1100
+++ linux-cell/drivers/base/dd.c	2006-11-02 13:20:24.000000000 +1100
@@ -52,6 +52,11 @@ int device_bind_driver(struct device *de
 
 	pr_debug("bound device '%s' to driver '%s'\n",
 		 dev->bus_id, dev->driver->name);
+
+	if (dev->bus)
+		blocking_notifier_call_chain(&dev->bus->bus_notifier,
+					     BUS_NOTIFY_BOUND_DRIVER, dev);
+
 	klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
 	ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
 			  kobject_name(&dev->kobj));
@@ -288,6 +293,11 @@ static void __device_release_driver(stru
 		sysfs_remove_link(&dev->kobj, "driver");
 		klist_remove(&dev->knode_driver);
 
+		if (dev->bus)
+			blocking_notifier_call_chain(&dev->bus->bus_notifier,
+						     BUS_NOTIFY_UNBIND_DRIVER,
+						     dev);
+
 		if (dev->bus && dev->bus->remove)
 			dev->bus->remove(dev);
 		else if (drv->remove)

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

* [PATCH 4/32] arch provides generic iomap missing accessors
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 2/32] Call platform_notify_remove later Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 1/32] ibmveth: Remove ibmveth "liobn" field Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 3/32] Driver core: add notification of bus events Benjamin Herrenschmidt
                   ` (28 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

From: Linus Torvalds <torvalds@osdl.org>

Allow architectures to provide their own implementation of the big endian MMIO
accessors and "repeat" MMIO accessors for use by the generic iomap.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
More-or-less-tested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

---
 lib/iomap.c |   32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

Index: linux-cell/lib/iomap.c
===================================================================
--- linux-cell.orig/lib/iomap.c	2006-11-05 16:19:32.000000000 +1100
+++ linux-cell/lib/iomap.c	2006-11-05 16:19:40.000000000 +1100
@@ -50,6 +50,16 @@
 	}							\
 } while (0)
 
+#ifndef pio_read16be
+#define pio_read16be(port) swab16(inw(port))
+#define pio_read32be(port) swab32(inl(port))
+#endif
+
+#ifndef mmio_read16be
+#define mmio_read16be(addr) be16_to_cpu(__raw_readw(addr))
+#define mmio_read32be(addr) be32_to_cpu(__raw_readl(addr))
+#endif
+
 unsigned int fastcall ioread8(void __iomem *addr)
 {
 	IO_COND(addr, return inb(port), return readb(addr));
@@ -60,7 +70,7 @@
 }
 unsigned int fastcall ioread16be(void __iomem *addr)
 {
-	IO_COND(addr, return inw(port), return be16_to_cpu(__raw_readw(addr)));
+	IO_COND(addr, return pio_read16be(port), return mmio_read16be(addr));
 }
 unsigned int fastcall ioread32(void __iomem *addr)
 {
@@ -68,7 +78,7 @@
 }
 unsigned int fastcall ioread32be(void __iomem *addr)
 {
-	IO_COND(addr, return inl(port), return be32_to_cpu(__raw_readl(addr)));
+	IO_COND(addr, return pio_read32be(port), return mmio_read32be(addr));
 }
 EXPORT_SYMBOL(ioread8);
 EXPORT_SYMBOL(ioread16);
@@ -76,6 +86,16 @@
 EXPORT_SYMBOL(ioread32);
 EXPORT_SYMBOL(ioread32be);
 
+#ifndef pio_write16be
+#define pio_write16be(val,port) outw(swab16(val),port)
+#define pio_write32be(val,port) outl(swab32(val),port)
+#endif
+
+#ifndef mmio_write16be
+#define mmio_write16be(val,port) __raw_writew(be16_to_cpu(val),port)
+#define mmio_write32be(val,port) __raw_writel(be32_to_cpu(val),port)
+#endif
+
 void fastcall iowrite8(u8 val, void __iomem *addr)
 {
 	IO_COND(addr, outb(val,port), writeb(val, addr));
@@ -86,7 +106,7 @@
 }
 void fastcall iowrite16be(u16 val, void __iomem *addr)
 {
-	IO_COND(addr, outw(val,port), __raw_writew(cpu_to_be16(val), addr));
+	IO_COND(addr, pio_write16be(val,port), mmio_write16be(val, addr));
 }
 void fastcall iowrite32(u32 val, void __iomem *addr)
 {
@@ -94,7 +114,7 @@
 }
 void fastcall iowrite32be(u32 val, void __iomem *addr)
 {
-	IO_COND(addr, outl(val,port), __raw_writel(cpu_to_be32(val), addr));
+	IO_COND(addr, pio_write32be(val,port), mmio_write32be(val, addr));
 }
 EXPORT_SYMBOL(iowrite8);
 EXPORT_SYMBOL(iowrite16);
@@ -108,6 +128,7 @@
  * convert to CPU byte order. We write in "IO byte
  * order" (we also don't have IO barriers).
  */
+#ifndef mmio_insb
 static inline void mmio_insb(void __iomem *addr, u8 *dst, int count)
 {
 	while (--count >= 0) {
@@ -132,7 +153,9 @@
 		dst++;
 	}
 }
+#endif
 
+#ifndef mmio_outsb
 static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count)
 {
 	while (--count >= 0) {
@@ -154,6 +177,7 @@
 		src++;
 	}
 }
+#endif
 
 void fastcall ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
 {

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

* [PATCH 5/32] Add arch specific dev_sysdata to struct device
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (3 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 3/32] Driver core: add notification of bus events Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 6/32] Change ACPI to use dev_sysdata instead of firmware_data Benjamin Herrenschmidt
                   ` (26 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

Adds an arch specific struct dev_sysdata to struct device. This enables
architecture to add specific fields to every device in the system, like
DMA operation pointers, NUMA node ID, firmware specific data, etc...

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 include/asm-alpha/device.h     |   14 ++++++++++++++
 include/asm-arm/device.h       |   14 ++++++++++++++
 include/asm-arm26/device.h     |   14 ++++++++++++++
 include/asm-avr32/device.h     |   14 ++++++++++++++
 include/asm-cris/device.h      |   14 ++++++++++++++
 include/asm-frv/device.h       |   14 ++++++++++++++
 include/asm-generic/device.h   |   14 ++++++++++++++
 include/asm-h8300/device.h     |   14 ++++++++++++++
 include/asm-i386/device.h      |   14 ++++++++++++++
 include/asm-ia64/device.h      |   14 ++++++++++++++
 include/asm-m32r/device.h      |   14 ++++++++++++++
 include/asm-m68k/device.h      |   14 ++++++++++++++
 include/asm-m68knommu/device.h |   14 ++++++++++++++
 include/asm-mips/device.h      |   14 ++++++++++++++
 include/asm-parisc/device.h    |   14 ++++++++++++++
 include/asm-powerpc/device.h   |   14 ++++++++++++++
 include/asm-ppc/device.h       |   14 ++++++++++++++
 include/asm-s390/device.h      |   14 ++++++++++++++
 include/asm-sh/device.h        |   14 ++++++++++++++
 include/asm-sh64/device.h      |   14 ++++++++++++++
 include/asm-sparc/device.h     |   14 ++++++++++++++
 include/asm-sparc64/device.h   |   14 ++++++++++++++
 include/asm-um/device.h        |   14 ++++++++++++++
 include/asm-v850/device.h      |   14 ++++++++++++++
 include/asm-x86_64/device.h    |   14 ++++++++++++++
 include/asm-xtensa/device.h    |   14 ++++++++++++++
 include/linux/device.h         |    3 +++
 27 files changed, 367 insertions(+)

Index: linux-cell/include/asm-alpha/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-alpha/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-arm/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-arm/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-arm26/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-arm26/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-avr32/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-avr32/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-cris/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-cris/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-frv/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-frv/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-generic/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-generic/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-h8300/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-h8300/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-i386/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-i386/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-ia64/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-ia64/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-m32r/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-m32r/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-m68k/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-m68k/device.h	2006-11-09 11:20:28.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-m68knommu/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-m68knommu/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-mips/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-mips/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-parisc/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-parisc/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-powerpc/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-powerpc/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-ppc/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-ppc/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-s390/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-s390/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-sh/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-sh/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-sh64/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-sh64/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-sparc/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-sparc/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-sparc64/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-sparc64/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-um/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-um/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-v850/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-v850/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-x86_64/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-x86_64/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-xtensa/device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-xtensa/device.h	2006-11-09 11:20:29.000000000 +1100
@@ -0,0 +1,14 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ *
+ * See Documentation/driver-model/ for more information.
+ */
+#ifndef _ASM_DEVICE_H
+#define _ASM_DEVICE_H
+
+struct dev_sysdata {
+};
+
+#endif /* _ASM_DEVICE_H */
Index: linux-cell/include/linux/device.h
===================================================================
--- linux-cell.orig/include/linux/device.h	2006-11-08 15:09:35.000000000 +1100
+++ linux-cell/include/linux/device.h	2006-11-09 11:17:36.000000000 +1100
@@ -21,6 +21,7 @@
 #include <linux/pm.h>
 #include <asm/semaphore.h>
 #include <asm/atomic.h>
+#include <asm/device.h>
 
 #define DEVICE_NAME_SIZE	50
 #define DEVICE_NAME_HALF	__stringify(20)	/* Less than half to accommodate slop */
@@ -382,6 +383,8 @@ struct device {
 
 	struct dma_coherent_mem	*dma_mem; /* internal for coherent mem
 					     override */
+	/* arch specific additions */
+	struct dev_sysdata	sysdata;
 
 	/* class_device migration path */
 	struct list_head	node;

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

* [PATCH 6/32] Change ACPI to use dev_sysdata instead of firmware_data
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (4 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 5/32] Add arch specific dev_sysdata to struct device Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 7/32] powerpc: Make pci_read_irq_line the default Benjamin Herrenschmidt
                   ` (25 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch changes ACPI to use the new dev_sysdata on i386, x86_64
and amd64 (is there any other arch using ACPI ?) to store it's
acpi_handle.

It also removes the firmware_data field from struct device as this
was the only user.

Only build-tested on x86

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 drivers/acpi/glue.c         |   20 +++++++++++---------
 include/acpi/acpi_bus.h     |    2 +-
 include/asm-i386/device.h   |    3 +++
 include/asm-ia64/device.h   |    3 +++
 include/asm-x86_64/device.h |    3 +++
 include/linux/device.h      |    2 --
 6 files changed, 21 insertions(+), 12 deletions(-)

Index: linux-cell/drivers/acpi/glue.c
===================================================================
--- linux-cell.orig/drivers/acpi/glue.c	2006-10-06 13:48:00.000000000 +1000
+++ linux-cell/drivers/acpi/glue.c	2006-11-10 16:24:31.000000000 +1100
@@ -267,9 +267,9 @@ static int acpi_bind_one(struct device *
 {
 	acpi_status status;
 
-	if (dev->firmware_data) {
+	if (dev->sysdata.acpi_handle) {
 		printk(KERN_WARNING PREFIX
-		       "Drivers changed 'firmware_data' for %s\n", dev->bus_id);
+		       "Drivers changed 'acpi_handle' for %s\n", dev->bus_id);
 		return -EINVAL;
 	}
 	get_device(dev);
@@ -278,25 +278,26 @@ static int acpi_bind_one(struct device *
 		put_device(dev);
 		return -EINVAL;
 	}
-	dev->firmware_data = handle;
+	dev->sysdata.acpi_handle = handle;
 
 	return 0;
 }
 
 static int acpi_unbind_one(struct device *dev)
 {
-	if (!dev->firmware_data)
+	if (!dev->sysdata.acpi_handle)
 		return 0;
-	if (dev == acpi_get_physical_device(dev->firmware_data)) {
+	if (dev == acpi_get_physical_device(dev->sysdata.acpi_handle)) {
 		/* acpi_get_physical_device increase refcnt by one */
 		put_device(dev);
-		acpi_detach_data(dev->firmware_data, acpi_glue_data_handler);
-		dev->firmware_data = NULL;
+		acpi_detach_data(dev->sysdata.acpi_handle,
+				 acpi_glue_data_handler);
+		dev->sysdata.acpi_handle = NULL;
 		/* acpi_bind_one increase refcnt by one */
 		put_device(dev);
 	} else {
 		printk(KERN_ERR PREFIX
-		       "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id);
+		       "Oops, 'acpi_handle' corrupt for %s\n", dev->bus_id);
 	}
 	return 0;
 }
@@ -328,7 +329,8 @@ static int acpi_platform_notify(struct d
 	if (!ret) {
 		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 
-		acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer);
+		acpi_get_name(dev->sysdata.acpi_handle,
+			      ACPI_FULL_PATHNAME, &buffer);
 		DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer);
 		kfree(buffer.pointer);
 	} else
Index: linux-cell/include/acpi/acpi_bus.h
===================================================================
--- linux-cell.orig/include/acpi/acpi_bus.h	2006-10-06 13:48:20.000000000 +1000
+++ linux-cell/include/acpi/acpi_bus.h	2006-11-10 16:24:31.000000000 +1100
@@ -357,7 +357,7 @@ struct device *acpi_get_physical_device(
 /* helper */
 acpi_handle acpi_get_child(acpi_handle, acpi_integer);
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
-#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->firmware_data))
+#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->sysdata.acpi_handle))
 
 #endif /* CONFIG_ACPI */
 
Index: linux-cell/include/asm-i386/device.h
===================================================================
--- linux-cell.orig/include/asm-i386/device.h	2006-11-10 16:24:31.000000000 +1100
+++ linux-cell/include/asm-i386/device.h	2006-11-10 16:24:31.000000000 +1100
@@ -9,6 +9,9 @@
 #define _ASM_DEVICE_H
 
 struct dev_sysdata {
+#ifdef CONFIG_ACPI
+	void	*acpi_handle;
+#endif
 };
 
 #endif /* _ASM_DEVICE_H */
Index: linux-cell/include/linux/device.h
===================================================================
--- linux-cell.orig/include/linux/device.h	2006-11-10 16:24:31.000000000 +1100
+++ linux-cell/include/linux/device.h	2006-11-10 16:24:31.000000000 +1100
@@ -368,8 +368,6 @@ struct device {
 	void		*driver_data;	/* data private to the driver */
 	void		*platform_data;	/* Platform specific data, device
 					   core doesn't touch it */
-	void		*firmware_data; /* Firmware specific data (e.g. ACPI,
-					   BIOS data),reserved for device core*/
 	struct dev_pm_info	power;
 
 	u64		*dma_mask;	/* dma mask (if dma'able device) */
Index: linux-cell/include/asm-x86_64/device.h
===================================================================
--- linux-cell.orig/include/asm-x86_64/device.h	2006-11-10 16:24:31.000000000 +1100
+++ linux-cell/include/asm-x86_64/device.h	2006-11-10 16:24:31.000000000 +1100
@@ -9,6 +9,9 @@
 #define _ASM_DEVICE_H
 
 struct dev_sysdata {
+#ifdef CONFIG_ACPI
+	void	*acpi_handle;
+#endif
 };
 
 #endif /* _ASM_DEVICE_H */
Index: linux-cell/include/asm-ia64/device.h
===================================================================
--- linux-cell.orig/include/asm-ia64/device.h	2006-11-10 16:24:31.000000000 +1100
+++ linux-cell/include/asm-ia64/device.h	2006-11-10 17:51:50.000000000 +1100
@@ -9,6 +9,9 @@
 #define _ASM_DEVICE_H
 
 struct dev_sysdata {
+#ifdef CONFIG_ACPI
+	void	*acpi_handle;
+#endif
 };
 
 #endif /* _ASM_DEVICE_H */

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

* [PATCH 7/32] powerpc: Make pci_read_irq_line the default
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (5 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 6/32] Change ACPI to use dev_sysdata instead of firmware_data Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-14  5:47   ` Zang Roy-r61911
  2006-11-10  7:44 ` [PATCH 8/32] powerpc: Remove ppc_md.pci_map_irq & ppc_swizzle for ARCH=powerpc Benjamin Herrenschmidt
                   ` (24 subsequent siblings)
  31 siblings, 1 reply; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch reworks the way IRQs are fixed up on PCI for arch powerpc.

It makes pci_read_irq_line() called by default in the PCI code for
devices that are probed, and add an optional per-device fixup in
ppc_md for platforms that really need to correct what they obtain
from pci_read_irq_line().

It also removes ppc_md.irq_bus_setup which was only used by pSeries
and should not be needed anymore.

I've also removed the pSeries s7a workaround as it can't work with
the current interrupt code anyway. I'm trying to get one of these
machines working so I can test a proper fix for that problem.

I also haven't updated the old-style fixup code from 85xx_cds.c
because it's actually buggy :) It assigns pci_dev->irq hard coded
numbers which is no good with the new IRQ mapping code. It should
at least use irq_create_mapping(NULL, hard_coded_number); and possibly
also set_irq_type() to set them as level low.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/pci_32.c                      |   10 ++++
 arch/powerpc/kernel/pci_64.c                      |    8 ++-
 arch/powerpc/platforms/82xx/mpc82xx_ads.c         |   13 ------
 arch/powerpc/platforms/83xx/mpc834x_itx.c         |    3 -
 arch/powerpc/platforms/83xx/mpc834x_sys.c         |    3 -
 arch/powerpc/platforms/83xx/mpc83xx.h             |    1 
 arch/powerpc/platforms/83xx/pci.c                 |    9 ----
 arch/powerpc/platforms/85xx/mpc85xx_ads.c         |   11 -----
 arch/powerpc/platforms/86xx/mpc86xx_hpcn.c        |   10 ----
 arch/powerpc/platforms/cell/setup.c               |    9 ----
 arch/powerpc/platforms/chrp/chrp.h                |    1 
 arch/powerpc/platforms/chrp/pci.c                 |    9 ----
 arch/powerpc/platforms/chrp/setup.c               |    1 
 arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c |   16 ++-----
 arch/powerpc/platforms/maple/maple.h              |    2 
 arch/powerpc/platforms/maple/pci.c                |   45 ++++++++--------------
 arch/powerpc/platforms/maple/setup.c              |    2 
 arch/powerpc/platforms/pasemi/pasemi.h            |    1 
 arch/powerpc/platforms/pasemi/pci.c               |    8 ---
 arch/powerpc/platforms/pasemi/setup.c             |    1 
 arch/powerpc/platforms/powermac/pci.c             |   35 ++++++-----------
 arch/powerpc/platforms/powermac/pmac.h            |    2 
 arch/powerpc/platforms/powermac/setup.c           |    2 
 arch/powerpc/platforms/pseries/pci.c              |   35 -----------------
 arch/powerpc/platforms/pseries/setup.c            |    1 
 include/asm-powerpc/machdep.h                     |    2 
 include/asm-powerpc/ppc-pci.h                     |    1 
 27 files changed, 58 insertions(+), 183 deletions(-)

Index: linux-cell/arch/powerpc/kernel/pci_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_32.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_32.c	2006-11-06 15:04:50.000000000 +1100
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/bootmem.h>
 #include <linux/irq.h>
+#include <linux/list.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -1338,6 +1339,7 @@ void __init pcibios_fixup_bus(struct pci
 	struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
 	unsigned long io_offset;
 	struct resource *res;
+	struct pci_dev *dev;
 	int i;
 
 	io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
@@ -1390,8 +1392,16 @@ void __init pcibios_fixup_bus(struct pci
 		}
 	}
 
+	/* Platform specific bus fixups */
 	if (ppc_md.pcibios_fixup_bus)
 		ppc_md.pcibios_fixup_bus(bus);
+
+	/* Read default IRQs and fixup if necessary */
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		pci_read_irq_line(dev);
+		if (ppc_md.pci_irq_fixup)
+			ppc_md.pci_irq_fixup(dev);
+	}
 }
 
 char __init *pcibios_setup(char *str)
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_64.c	2006-11-06 15:02:21.000000000 +1100
@@ -1223,8 +1223,12 @@ static void __devinit do_bus_setup(struc
 	list_for_each_entry(dev, &bus->devices, bus_list)
 		ppc_md.iommu_dev_setup(dev);
 
-	if (ppc_md.irq_bus_setup)
-		ppc_md.irq_bus_setup(bus);
+	/* Read default IRQs and fixup if necessary */
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		pci_read_irq_line(dev);
+		if (ppc_md.pci_irq_fixup)
+			ppc_md.pci_irq_fixup(dev);
+	}
 }
 
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
Index: linux-cell/arch/powerpc/platforms/pseries/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pci.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pseries/pci.c	2006-11-06 15:02:21.000000000 +1100
@@ -29,8 +29,6 @@
 #include <asm/prom.h>
 #include <asm/ppc-pci.h>
 
-static int __devinitdata s7a_workaround = -1;
-
 #if 0
 void pcibios_name_device(struct pci_dev *dev)
 {
@@ -57,39 +55,6 @@ void pcibios_name_device(struct pci_dev 
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device);
 #endif
 
-static void __devinit check_s7a(void)
-{
-	struct device_node *root;
-	const char *model;
-
-	s7a_workaround = 0;
-	root = of_find_node_by_path("/");
-	if (root) {
-		model = get_property(root, "model", NULL);
-		if (model && !strcmp(model, "IBM,7013-S7A"))
-			s7a_workaround = 1;
-		of_node_put(root);
-	}
-}
-
-void __devinit pSeries_irq_bus_setup(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-
-	if (s7a_workaround < 0)
-		check_s7a();
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-		pci_read_irq_line(dev);
-		if (s7a_workaround) {
-			if (dev->irq > 16) {
-				dev->irq -= 3;
-				pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
-					dev->irq);
-			}
-		}
-	}
-}
-
 static void __init pSeries_request_regions(void)
 {
 	if (!isa_io_base)
Index: linux-cell/arch/powerpc/platforms/pseries/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/setup.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pseries/setup.c	2006-11-06 15:02:21.000000000 +1100
@@ -553,7 +553,6 @@ define_machine(pseries) {
 	.log_error		= pSeries_log_error,
 	.pcibios_fixup		= pSeries_final_fixup,
 	.pci_probe_mode		= pSeries_pci_probe_mode,
-	.irq_bus_setup		= pSeries_irq_bus_setup,
 	.restart		= rtas_restart,
 	.power_off		= rtas_power_off,
 	.halt			= rtas_halt,
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/include/asm-powerpc/machdep.h	2006-11-06 15:02:21.000000000 +1100
@@ -86,7 +86,6 @@ struct machdep_calls {
 	void		(*tce_flush)(struct iommu_table *tbl);
 	void		(*iommu_dev_setup)(struct pci_dev *dev);
 	void		(*iommu_bus_setup)(struct pci_bus *bus);
-	void		(*irq_bus_setup)(struct pci_bus *bus);
 #endif /* CONFIG_PPC64 */
 
 	int		(*probe)(void);
@@ -106,6 +105,7 @@ struct machdep_calls {
 	/* Called after scanning the bus, before allocating resources */
 	void		(*pcibios_fixup)(void);
 	int		(*pci_probe_mode)(struct pci_bus *);
+	void		(*pci_irq_fixup)(struct pci_dev *dev);
 
 	void		(*restart)(char *cmd);
 	void		(*power_off)(void);
Index: linux-cell/include/asm-powerpc/ppc-pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ppc-pci.h	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/include/asm-powerpc/ppc-pci.h	2006-11-06 15:02:21.000000000 +1100
@@ -47,7 +47,6 @@ unsigned long get_phb_buid (struct devic
 
 /* From pSeries_pci.h */
 extern void pSeries_final_fixup(void);
-extern void pSeries_irq_bus_setup(struct pci_bus *bus);
 
 extern unsigned long pci_probe_only;
 
Index: linux-cell/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/setup.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/setup.c	2006-11-06 15:02:21.000000000 +1100
@@ -80,14 +80,6 @@ static void cell_progress(char *s, unsig
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
-static void __init cell_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-
-	for_each_pci_dev(dev)
-		pci_read_irq_line(dev);
-}
-
 static void __init cell_init_irq(void)
 {
 	iic_init_IRQ();
@@ -180,7 +172,6 @@ define_machine(cell) {
 	.check_legacy_ioport	= cell_check_legacy_ioport,
 	.progress		= cell_progress,
 	.init_IRQ       	= cell_init_irq,
-	.pcibios_fixup		= cell_pcibios_fixup,
 #ifdef CONFIG_KEXEC
 	.machine_kexec		= default_machine_kexec,
 	.machine_kexec_prepare	= default_machine_kexec_prepare,
Index: linux-cell/arch/powerpc/platforms/maple/maple.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/maple/maple.h	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/maple/maple.h	2006-11-06 15:02:21.000000000 +1100
@@ -8,5 +8,5 @@ extern void maple_get_rtc_time(struct rt
 extern unsigned long maple_get_boot_time(void);
 extern void maple_calibrate_decr(void);
 extern void maple_pci_init(void);
-extern void maple_pcibios_fixup(void);
+extern void maple_pci_irq_fixup(struct pci_dev *dev);
 extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel);
Index: linux-cell/arch/powerpc/platforms/maple/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/maple/pci.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/maple/pci.c	2006-11-06 15:02:21.000000000 +1100
@@ -502,38 +502,29 @@ static int __init add_bridge(struct devi
 }
 
 
-void __init maple_pcibios_fixup(void)
+void __devinit maple_pci_irq_fixup(struct pci_dev *dev)
 {
-	struct pci_dev *dev = NULL;
+	DBG(" -> maple_pci_irq_fixup\n");
 
-	DBG(" -> maple_pcibios_fixup\n");
-
-	for_each_pci_dev(dev) {
-		/* Fixup IRQ for PCIe host */
-		if (u4_pcie != NULL && dev->bus->number == 0 &&
-		    pci_bus_to_host(dev->bus) == u4_pcie) {
-			printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n");
-			dev->irq = irq_create_mapping(NULL, 1);
-			if (dev->irq != NO_IRQ)
-				set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
-			continue;
-		}
-
-		/* Hide AMD8111 IDE interrupt when in legacy mode so
-		 * the driver calls pci_get_legacy_ide_irq()
-		 */
-		if (dev->vendor == PCI_VENDOR_ID_AMD &&
-		    dev->device == PCI_DEVICE_ID_AMD_8111_IDE &&
-		    (dev->class & 5) != 5) {
-			dev->irq = NO_IRQ;
-			continue;
-		}
+	/* Fixup IRQ for PCIe host */
+	if (u4_pcie != NULL && dev->bus->number == 0 &&
+	    pci_bus_to_host(dev->bus) == u4_pcie) {
+		printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n");
+		dev->irq = irq_create_mapping(NULL, 1);
+		if (dev->irq != NO_IRQ)
+			set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
+	}
 
-		/* For all others, map the interrupt from the device-tree */
-		pci_read_irq_line(dev);
+	/* Hide AMD8111 IDE interrupt when in legacy mode so
+	 * the driver calls pci_get_legacy_ide_irq()
+	 */
+	if (dev->vendor == PCI_VENDOR_ID_AMD &&
+	    dev->device == PCI_DEVICE_ID_AMD_8111_IDE &&
+	    (dev->class & 5) != 5) {
+		dev->irq = NO_IRQ;
 	}
 
-	DBG(" <- maple_pcibios_fixup\n");
+	DBG(" <- maple_pci_irq_fixup\n");
 }
 
 static void __init maple_fixup_phb_resources(void)
Index: linux-cell/arch/powerpc/platforms/maple/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/maple/setup.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/maple/setup.c	2006-11-06 15:02:21.000000000 +1100
@@ -312,7 +312,7 @@ define_machine(maple_md) {
 	.setup_arch		= maple_setup_arch,
 	.init_early		= maple_init_early,
 	.init_IRQ		= maple_init_IRQ,
-	.pcibios_fixup		= maple_pcibios_fixup,
+	.pci_irq_fixup		= maple_pci_irq_fixup,
 	.pci_get_legacy_ide_irq	= maple_pci_get_legacy_ide_irq,
 	.restart		= maple_restart,
 	.power_off		= maple_power_off,
Index: linux-cell/arch/powerpc/platforms/powermac/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/pci.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/powermac/pci.c	2006-11-06 15:02:21.000000000 +1100
@@ -985,30 +985,23 @@ static int __init add_bridge(struct devi
 	return 0;
 }
 
-void __init pmac_pcibios_fixup(void)
+void __devinit pmac_pci_irq_fixup(struct pci_dev *dev)
 {
-	struct pci_dev* dev = NULL;
-
-	for_each_pci_dev(dev) {
-		/* Read interrupt from the device-tree */
-		pci_read_irq_line(dev);
-
 #ifdef CONFIG_PPC32
-		/* Fixup interrupt for the modem/ethernet combo controller.
-		 * on machines with a second ohare chip.
-		 * 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.
-		 */
-		if (has_second_ohare &&
-		    dev->vendor == PCI_VENDOR_ID_DEC &&
-		    dev->device == PCI_DEVICE_ID_DEC_TULIP_PLUS) {
-			dev->irq = irq_create_mapping(NULL, 60);
-			set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
-		}
-#endif /* CONFIG_PPC32 */
+	/* Fixup interrupt for the modem/ethernet combo controller.
+	 * on machines with a second ohare chip.
+	 * 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.
+	 */
+	if (has_second_ohare &&
+	    dev->vendor == PCI_VENDOR_ID_DEC &&
+	    dev->device == PCI_DEVICE_ID_DEC_TULIP_PLUS) {
+		dev->irq = irq_create_mapping(NULL, 60);
+		set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
 	}
+#endif /* CONFIG_PPC32 */
 }
 
 #ifdef CONFIG_PPC64
Index: linux-cell/arch/powerpc/platforms/powermac/pmac.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/pmac.h	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/powermac/pmac.h	2006-11-06 15:02:21.000000000 +1100
@@ -20,7 +20,7 @@ extern void pmac_get_rtc_time(struct rtc
 extern int pmac_set_rtc_time(struct rtc_time *);
 extern void pmac_read_rtc_time(void);
 extern void pmac_calibrate_decr(void);
-extern void pmac_pcibios_fixup(void);
+extern void pmac_pci_irq_fixup(struct pci_dev *);
 extern void pmac_pci_init(void);
 extern unsigned long pmac_ide_get_base(int index);
 extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
Index: linux-cell/arch/powerpc/platforms/powermac/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/setup.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/powermac/setup.c	2006-11-06 15:02:21.000000000 +1100
@@ -727,7 +727,7 @@ define_machine(powermac) {
 	.show_cpuinfo		= pmac_show_cpuinfo,
 	.init_IRQ		= pmac_pic_init,
 	.get_irq		= NULL,	/* changed later */
-	.pcibios_fixup		= pmac_pcibios_fixup,
+	.pci_irq_fixup		= pmac_pci_irq_fixup,
 	.restart		= pmac_restart,
 	.power_off		= pmac_power_off,
 	.halt			= pmac_halt,
Index: linux-cell/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c	2006-11-06 15:02:21.000000000 +1100
@@ -89,7 +89,7 @@ u8 find_slot_by_devfn(unsigned int *inte
 /*
  * Scans the interrupt map for pci device
  */
-void mpc7448_hpc2_fixup_irq(struct pci_dev *dev)
+void __devinit mpc7448_hpc2_fixup_irq(struct pci_dev *dev)
 {
 	struct pci_controller *hose;
 	struct device_node *node;
@@ -117,19 +117,13 @@ void mpc7448_hpc2_fixup_irq(struct pci_d
 		pin = 1;
 	pin--;
 	dev->irq  = interrupt[slot*4*7 + pin*7 + 5];
+
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+
 	DBG("TSI_PCI: dev->irq = 0x%x\n", dev->irq);
 }
 /* temporary pci irq map fixup*/
 
-void __init mpc7448_hpc2_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-	for_each_pci_dev(dev) {
-		mpc7448_hpc2_fixup_irq(dev);
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-	}
-}
-
 static void __init mpc7448_hpc2_setup_arch(void)
 {
 	struct device_node *cpu;
@@ -300,7 +294,7 @@ define_machine(mpc7448_hpc2){
 	.init_IRQ 		= mpc7448_hpc2_init_IRQ,
 	.show_cpuinfo 		= mpc7448_hpc2_show_cpuinfo,
 	.get_irq 		= mpic_get_irq,
-	.pcibios_fixup 		= mpc7448_hpc2_pcibios_fixup,
+	.pci_irq_fixup 		= mpc7448_hpc2_fixup_irq,
 	.restart 		= mpc7448_hpc2_restart,
 	.calibrate_decr 	= generic_calibrate_decr,
 	.machine_check_exception= mpc7448_machine_check_exception,
Index: linux-cell/arch/powerpc/platforms/pasemi/pasemi.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pasemi/pasemi.h	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pasemi/pasemi.h	2006-11-06 15:02:21.000000000 +1100
@@ -3,6 +3,5 @@
 
 extern unsigned long pas_get_boot_time(void);
 extern void pas_pci_init(void);
-extern void pas_pcibios_fixup(void);
 
 #endif /* _PASEMI_PASEMI_H */
Index: linux-cell/arch/powerpc/platforms/pasemi/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pasemi/pci.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pasemi/pci.c	2006-11-06 15:02:21.000000000 +1100
@@ -148,14 +148,6 @@ static int __init add_bridge(struct devi
 }
 
 
-void __init pas_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-
-	for_each_pci_dev(dev)
-		pci_read_irq_line(dev);
-}
-
 static void __init pas_fixup_phb_resources(void)
 {
 	struct pci_controller *hose, *tmp;
Index: linux-cell/arch/powerpc/platforms/pasemi/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pasemi/setup.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pasemi/setup.c	2006-11-06 15:02:21.000000000 +1100
@@ -176,7 +176,6 @@ define_machine(pas) {
 	.init_early		= pas_init_early,
 	.init_IRQ		= pas_init_IRQ,
 	.get_irq		= mpic_get_irq,
-	.pcibios_fixup		= pas_pcibios_fixup,
 	.restart		= pas_restart,
 	.power_off		= pas_power_off,
 	.halt			= pas_halt,
Index: linux-cell/arch/powerpc/platforms/82xx/mpc82xx_ads.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/82xx/mpc82xx_ads.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/82xx/mpc82xx_ads.c	2006-11-06 15:02:21.000000000 +1100
@@ -515,16 +515,6 @@ static int m82xx_pci_exclude_device(u_ch
 		return PCIBIOS_SUCCESSFUL;
 }
 
-static void
-__init mpc82xx_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-
-	for_each_pci_dev(dev) {
-		pci_read_irq_line(dev);
-	}
-}
-
 void __init add_bridge(struct device_node *np)
 {
 	int len;
@@ -597,9 +587,6 @@ static void __init mpc82xx_ads_setup_arc
 		add_bridge(np);
 
 	of_node_put(np);
-	ppc_md.pci_map_irq = NULL;
-	ppc_md.pcibios_fixup = mpc82xx_pcibios_fixup;
-	ppc_md.pcibios_fixup_bus = NULL;
 #endif
 
 #ifdef  CONFIG_ROOT_NFS
Index: linux-cell/arch/powerpc/platforms/83xx/mpc834x_itx.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/83xx/mpc834x_itx.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/83xx/mpc834x_itx.c	2006-11-06 15:02:21.000000000 +1100
@@ -122,7 +122,4 @@ define_machine(mpc834x_itx) {
 	.time_init		= mpc83xx_time_init,
 	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= udbg_progress,
-#ifdef CONFIG_PCI
-	.pcibios_fixup		= mpc83xx_pcibios_fixup,
-#endif
 };
Index: linux-cell/arch/powerpc/platforms/83xx/mpc834x_sys.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/83xx/mpc834x_sys.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/83xx/mpc834x_sys.c	2006-11-06 15:02:21.000000000 +1100
@@ -137,7 +137,4 @@ define_machine(mpc834x_sys) {
 	.time_init		= mpc83xx_time_init,
 	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= udbg_progress,
-#ifdef CONFIG_PCI
-	.pcibios_fixup		= mpc83xx_pcibios_fixup,
-#endif
 };
Index: linux-cell/arch/powerpc/platforms/83xx/mpc83xx.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/83xx/mpc83xx.h	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/83xx/mpc83xx.h	2006-11-06 15:02:21.000000000 +1100
@@ -11,7 +11,6 @@
 
 extern int add_bridge(struct device_node *dev);
 extern int mpc83xx_exclude_device(u_char bus, u_char devfn);
-extern void mpc83xx_pcibios_fixup(void);
 extern void mpc83xx_restart(char *cmd);
 extern long mpc83xx_time_init(void);
 
Index: linux-cell/arch/powerpc/platforms/83xx/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/83xx/pci.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/83xx/pci.c	2006-11-06 15:02:21.000000000 +1100
@@ -45,15 +45,6 @@ int mpc83xx_exclude_device(u_char bus, u
 	return PCIBIOS_SUCCESSFUL;
 }
 
-void __init mpc83xx_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-
-	/* map all the PCI irqs */
-	for_each_pci_dev(dev)
-		pci_read_irq_line(dev);
-}
-
 int __init add_bridge(struct device_node *dev)
 {
 	int len;
Index: linux-cell/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c	2006-11-06 15:02:21.000000000 +1100
@@ -398,15 +398,6 @@ mpc86xx_hpcn_show_cpuinfo(struct seq_fil
 }
 
 
-void __init mpc86xx_hpcn_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-
-	for_each_pci_dev(dev)
-		pci_read_irq_line(dev);
-}
-
-
 /*
  * Called very early, device-tree isn't unflattened
  */
@@ -461,7 +452,6 @@ define_machine(mpc86xx_hpcn) {
 	.setup_arch		= mpc86xx_hpcn_setup_arch,
 	.init_IRQ		= mpc86xx_hpcn_init_irq,
 	.show_cpuinfo		= mpc86xx_hpcn_show_cpuinfo,
-	.pcibios_fixup		= mpc86xx_hpcn_pcibios_fixup,
 	.get_irq		= mpic_get_irq,
 	.restart		= mpc86xx_restart,
 	.time_init		= mpc86xx_time_init,
Index: linux-cell/arch/powerpc/platforms/chrp/chrp.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/chrp/chrp.h	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/chrp/chrp.h	2006-11-06 15:02:21.000000000 +1100
@@ -9,4 +9,3 @@ extern long chrp_time_init(void);
 
 extern void chrp_find_bridges(void);
 extern void chrp_event_scan(unsigned long);
-extern void chrp_pcibios_fixup(void);
Index: linux-cell/arch/powerpc/platforms/chrp/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/chrp/setup.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/chrp/setup.c	2006-11-06 15:02:21.000000000 +1100
@@ -600,7 +600,6 @@ define_machine(chrp) {
 	.init			= chrp_init2,
 	.show_cpuinfo		= chrp_show_cpuinfo,
 	.init_IRQ		= chrp_init_IRQ,
-	.pcibios_fixup		= chrp_pcibios_fixup,
 	.restart		= rtas_restart,
 	.power_off		= rtas_power_off,
 	.halt			= rtas_halt,
Index: linux-cell/arch/powerpc/platforms/85xx/mpc85xx_ads.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/85xx/mpc85xx_ads.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/85xx/mpc85xx_ads.c	2006-11-06 15:02:21.000000000 +1100
@@ -53,15 +53,6 @@ mpc85xx_exclude_device(u_char bus, u_cha
 	else
 		return PCIBIOS_SUCCESSFUL;
 }
-
-void __init
-mpc85xx_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-
-	for_each_pci_dev(dev)
-		pci_read_irq_line(dev);
-}
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_CPM2
@@ -253,8 +244,6 @@ static void __init mpc85xx_ads_setup_arc
 #ifdef CONFIG_PCI
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
 		add_bridge(np);
-
-	ppc_md.pcibios_fixup = mpc85xx_pcibios_fixup;
 	ppc_md.pci_exclude_device = mpc85xx_exclude_device;
 #endif
 
Index: linux-cell/arch/powerpc/platforms/chrp/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/chrp/pci.c	2006-11-06 15:02:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/chrp/pci.c	2006-11-06 15:02:21.000000000 +1100
@@ -156,15 +156,6 @@ hydra_init(void)
 	return 1;
 }
 
-void __init
-chrp_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-
-	for_each_pci_dev(dev)
-		pci_read_irq_line(dev);
-}
-
 #define PRG_CL_RESET_VALID 0x00010000
 
 static void __init

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

* [PATCH 8/32] powerpc: Remove ppc_md.pci_map_irq & ppc_swizzle for ARCH=powerpc
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (6 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 7/32] powerpc: Make pci_read_irq_line the default Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 9/32] powerpc: Generic DCR infrastructure Benjamin Herrenschmidt
                   ` (23 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

These were inherited from ARCH=ppc, but are not needed since parsing of interrupts
should be done via the of_* functions (who can do swizzling). If we ever need to
do non-standard swizzling on bridges without a device-node, then we might add
back a slightly different version of ppc_md.pci_swizzle but for now, that is not
the case.

I removed the couple of calls for these in 83xx. If that breaks something, then
there is a problem with the device-tree on these.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/pci_32.c              |   23 -----------------------
 arch/powerpc/platforms/83xx/mpc832x_mds.c |    2 --
 arch/powerpc/platforms/83xx/mpc8360e_pb.c |    2 --
 include/asm-powerpc/machdep.h             |    4 ----
 4 files changed, 31 deletions(-)

Index: linux-cell/arch/powerpc/kernel/pci_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_32.c	2006-11-06 15:04:50.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_32.c	2006-11-06 15:05:34.000000000 +1100
@@ -1283,10 +1283,6 @@ pcibios_init(void)
 	if (pci_assign_all_buses && have_of)
 		pcibios_make_OF_bus_map();
 
-	/* Do machine dependent PCI interrupt routing */
-	if (ppc_md.pci_swizzle && ppc_md.pci_map_irq)
-		pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq);
-
 	/* Call machine dependent fixup */
 	if (ppc_md.pcibios_fixup)
 		ppc_md.pcibios_fixup();
@@ -1309,25 +1305,6 @@ pcibios_init(void)
 
 subsys_initcall(pcibios_init);
 
-unsigned char __init
-common_swizzle(struct pci_dev *dev, unsigned char *pinp)
-{
-	struct pci_controller *hose = dev->sysdata;
-
-	if (dev->bus->number != hose->first_busno) {
-		u8 pin = *pinp;
-		do {
-			pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
-			/* Move up the chain of bridges. */
-			dev = dev->bus->self;
-		} while (dev->bus->self);
-		*pinp = pin;
-
-		/* The slot is the idsel of the last bridge. */
-	}
-	return PCI_SLOT(dev->devfn);
-}
-
 unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
 			     unsigned long start, unsigned long size)
 {
Index: linux-cell/arch/powerpc/platforms/83xx/mpc832x_mds.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/83xx/mpc832x_mds.c	2006-11-06 15:01:52.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/83xx/mpc832x_mds.c	2006-11-06 15:05:34.000000000 +1100
@@ -96,8 +96,6 @@ static void __init mpc832x_sys_setup_arc
 #ifdef CONFIG_PCI
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
 		add_bridge(np);
-
-	ppc_md.pci_swizzle = common_swizzle;
 	ppc_md.pci_exclude_device = mpc83xx_exclude_device;
 #endif
 
Index: linux-cell/arch/powerpc/platforms/83xx/mpc8360e_pb.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/83xx/mpc8360e_pb.c	2006-11-06 15:01:52.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/83xx/mpc8360e_pb.c	2006-11-06 15:05:34.000000000 +1100
@@ -102,8 +102,6 @@ static void __init mpc8360_sys_setup_arc
 #ifdef CONFIG_PCI
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
 		add_bridge(np);
-
-	ppc_md.pci_swizzle = common_swizzle;
 	ppc_md.pci_exclude_device = mpc83xx_exclude_device;
 #endif
 
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h	2006-11-06 15:02:21.000000000 +1100
+++ linux-cell/include/asm-powerpc/machdep.h	2006-11-06 15:05:34.000000000 +1100
@@ -199,10 +199,6 @@ struct machdep_calls {
 	 * Returns 0 to allow assignment/enabling of the device. */
 	int  (*pcibios_enable_device_hook)(struct pci_dev *, int initial);
 
-	/* For interrupt routing */
-	unsigned char (*pci_swizzle)(struct pci_dev *, unsigned char *);
-	int (*pci_map_irq)(struct pci_dev *, unsigned char, unsigned char);
-
 	/* Called in indirect_* to avoid touching devices */
 	int (*pci_exclude_device)(unsigned char, unsigned char);
 

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

* [PATCH 9/32] powerpc: Generic DCR infrastructure
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (7 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 8/32] powerpc: Remove ppc_md.pci_map_irq & ppc_swizzle for ARCH=powerpc Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 10/32] powerpc: Make EMAC use generic DCR access methods Benjamin Herrenschmidt
                   ` (22 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch adds new dcr_map/dcr_read/dcr_write accessors for DCRs that
can be used by drivers to transparently address either native DCRs or
memory mapped DCRs. The implementation for memory mapped DCRs is done
after the binding being currently worked on for SLOF and the Axon
chipset. This patch enables it for the cell native platform

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/Kconfig             |   16 ++++
 arch/powerpc/kernel/Makefile     |    1 
 arch/powerpc/sysdev/Makefile     |    3 
 arch/powerpc/sysdev/dcr-low.S    |   39 +++++++++++
 arch/powerpc/sysdev/dcr.c        |  137 +++++++++++++++++++++++++++++++++++++++
 arch/ppc/Kconfig                 |   11 +++
 include/asm-powerpc/dcr-mmio.h   |   51 ++++++++++++++
 include/asm-powerpc/dcr-native.h |   39 +++++++++++
 include/asm-powerpc/dcr.h        |   42 +++++++++++
 9 files changed, 337 insertions(+), 2 deletions(-)

Index: linux-cell/include/asm-powerpc/dcr.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-powerpc/dcr.h	2006-11-02 13:21:14.000000000 +1100
@@ -0,0 +1,42 @@
+/*
+ * (c) Copyright 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ASM_POWERPC_DCR_H
+#define _ASM_POWERPC_DCR_H
+#ifdef __KERNEL__
+
+#ifdef CONFIG_PPC_DCR_NATIVE
+#include <asm/dcr-native.h>
+#else
+#include <asm/dcr-mmio.h>
+#endif
+
+/*
+ * On CONFIG_PPC_MERGE, we have additional helpers to read the DCR
+ * base from the device-tree
+ */
+#ifdef CONFIG_PPC_MERGE
+extern unsigned int dcr_resource_start(struct device_node *np,
+				       unsigned int index);
+extern unsigned int dcr_resource_len(struct device_node *np,
+				     unsigned int index);
+#endif /* CONFIG_PPC_MERGE */
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_DCR_H */
Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig	2006-10-23 14:41:37.000000000 +1000
+++ linux-cell/arch/powerpc/Kconfig	2006-11-02 13:21:14.000000000 +1100
@@ -160,9 +160,11 @@ config PPC_86xx
 
 config 40x
 	bool "AMCC 40x"
+	select PPC_DCR_NATIVE
 
 config 44x
 	bool "AMCC 44x"
+	select PPC_DCR_NATIVE
 
 config 8xx
 	bool "Freescale 8xx"
@@ -208,6 +210,19 @@ config PPC_FPU
 	bool
 	default y if PPC64
 
+config PPC_DCR_NATIVE
+	bool
+	default n
+
+config PPC_DCR_MMIO
+	bool
+	default n
+
+config PPC_DCR
+	bool
+	depends on PPC_DCR_NATIVE || PPC_DCR_MMIO
+	default y
+
 config BOOKE
 	bool
 	depends on E200 || E500
@@ -445,6 +460,7 @@ config PPC_CELL
 config PPC_CELL_NATIVE
 	bool
 	select PPC_CELL
+	select PPC_DCR_MMIO
 	default n
 
 config PPC_IBM_CELL_BLADE
Index: linux-cell/include/asm-powerpc/dcr-mmio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-powerpc/dcr-mmio.h	2006-11-02 13:21:14.000000000 +1100
@@ -0,0 +1,51 @@
+/*
+ * (c) Copyright 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ASM_POWERPC_DCR_MMIO_H
+#define _ASM_POWERPC_DCR_MMIO_H
+#ifdef __KERNEL__
+
+#include <asm/io.h>
+
+typedef struct { void __iomem *token; unsigned int stride; } dcr_host_t;
+
+#define DCR_MAP_OK(host)	((host).token != NULL)
+
+extern dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
+			  unsigned int dcr_c);
+extern void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c);
+
+static inline u32 dcr_read(dcr_host_t host, unsigned int dcr_n)
+{
+	return in_be32(host.token + dcr_n * host.stride);
+}
+
+static inline void dcr_write(dcr_host_t host, unsigned int dcr_n, u32 value)
+{
+	out_be32(host.token + dcr_n * host.stride, value);
+}
+
+extern u64 of_translate_dcr_address(struct device_node *dev,
+				    unsigned int dcr_n,
+				    unsigned int *stride);
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_DCR_MMIO_H */
+
+
Index: linux-cell/include/asm-powerpc/dcr-native.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-powerpc/dcr-native.h	2006-11-02 13:21:14.000000000 +1100
@@ -0,0 +1,39 @@
+/*
+ * (c) Copyright 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ASM_POWERPC_DCR_NATIVE_H
+#define _ASM_POWERPC_DCR_NATIVE_H
+#ifdef __KERNEL__
+
+#include <asm/reg.h>
+
+typedef struct {} dcr_host_t;
+
+#define DCR_MAP_OK(host)	(1)
+
+#define dcr_map(dev, dcr_n, dcr_c)	{}
+#define dcr_unmap(host, dcr_n, dcr_c)	{}
+#define dcr_read(host, dcr_n)		mfdcr(dcr_n)
+#define dcr_write(host, dcr_n, value)	mtdcr(dcr_n, value)
+
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_DCR_NATIVE_H */
+
+
Index: linux-cell/arch/ppc/Kconfig
===================================================================
--- linux-cell.orig/arch/ppc/Kconfig	2006-10-06 13:47:55.000000000 +1000
+++ linux-cell/arch/ppc/Kconfig	2006-11-02 13:21:14.000000000 +1100
@@ -77,9 +77,11 @@ config 6xx
 
 config 40x
 	bool "40x"
+	select PPC_DCR_NATIVE
 
 config 44x
 	bool "44x"
+	select PPC_DCR_NATIVE
 
 config 8xx
 	bool "8xx"
@@ -95,6 +97,15 @@ endchoice
 config PPC_FPU
 	bool
 
+config PPC_DCR_NATIVE
+	bool
+	default n
+
+config PPC_DCR
+	bool
+	depends on PPC_DCR_NATIVE
+	default y
+
 config BOOKE
 	bool
 	depends on E200 || E500
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile	2006-11-02 13:16:16.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/Makefile	2006-11-02 13:21:14.000000000 +1100
@@ -59,6 +59,7 @@ obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_serial.o udbg_16550.o
+
 module-$(CONFIG_PPC64)		+= module_64.o
 obj-$(CONFIG_MODULES)		+= $(module-y)
 
Index: linux-cell/arch/powerpc/sysdev/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/Makefile	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/sysdev/Makefile	2006-11-02 13:21:14.000000000 +1100
@@ -5,8 +5,7 @@ endif
 obj-$(CONFIG_MPIC)		+= mpic.o
 obj-$(CONFIG_PPC_INDIRECT_PCI)	+= indirect_pci.o
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
-obj-$(CONFIG_BOOKE)		+= dcr.o
-obj-$(CONFIG_40x)		+= dcr.o
+obj-$(CONFIG_PPC_DCR)		+= dcr.o dcr-low.o
 obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
Index: linux-cell/arch/powerpc/sysdev/dcr-low.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/sysdev/dcr-low.S	2006-11-02 13:21:14.000000000 +1100
@@ -0,0 +1,39 @@
+/*
+ * "Indirect" DCR access
+ *
+ * Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+#define DCR_ACCESS_PROLOG(table) \
+	rlwinm  r3,r3,4,18,27;   \
+	lis     r5,table@h;      \
+	ori     r5,r5,table@l;   \
+	add     r3,r3,r5;        \
+	mtctr   r3;              \
+	bctr
+
+_GLOBAL(__mfdcr)
+	DCR_ACCESS_PROLOG(__mfdcr_table)
+
+_GLOBAL(__mtdcr)
+	DCR_ACCESS_PROLOG(__mtdcr_table)
+
+__mfdcr_table:
+	mfdcr  r3,0; blr
+__mtdcr_table:
+	mtdcr  0,r4; blr
+
+dcr     = 1
+        .rept   1023
+	mfdcr   r3,dcr; blr
+	mtdcr   dcr,r4; blr
+	dcr     = dcr + 1
+	.endr
Index: linux-cell/arch/powerpc/sysdev/dcr.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/sysdev/dcr.c	2006-11-02 13:21:14.000000000 +1100
@@ -0,0 +1,137 @@
+/*
+ * (c) Copyright 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <asm/prom.h>
+#include <asm/dcr.h>
+
+unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
+{
+	unsigned int ds;
+	const u32 *dr = get_property(np, "dcr-reg", &ds);
+
+	if (dr == NULL || ds & 1 || index >= (ds / 8))
+		return 0;
+
+	return dr[index * 2];
+}
+
+unsigned int dcr_resource_len(struct device_node *np, unsigned int index)
+{
+	unsigned int ds;
+	const u32 *dr = get_property(np, "dcr-reg", &ds);
+
+	if (dr == NULL || ds & 1 || index >= (ds / 8))
+		return 0;
+
+	return dr[index * 2 + 1];
+}
+
+#ifndef CONFIG_PPC_DCR_NATIVE
+
+static struct device_node * find_dcr_parent(struct device_node * node)
+{
+	struct device_node *par, *tmp;
+	const u32 *p;
+
+	for (par = of_node_get(node); par;) {
+		if (get_property(par, "dcr-controller", NULL))
+			break;
+		p = get_property(par, "dcr-parent", NULL);
+		tmp = par;
+		if (p == NULL)
+			par = of_get_parent(par);
+		else
+			par = of_find_node_by_phandle(*p);
+		of_node_put(tmp);
+	}
+	return par;
+}
+
+u64 of_translate_dcr_address(struct device_node *dev,
+			     unsigned int dcr_n,
+			     unsigned int *out_stride)
+{
+	struct device_node *dp;
+	const u32 *p;
+	unsigned int stride;
+	u64 ret;
+
+	dp = find_dcr_parent(dev);
+	if (dp == NULL)
+		return OF_BAD_ADDR;
+
+	/* Stride is not properly defined yet, default to 0x10 for Axon */
+	p = get_property(dp, "dcr-mmio-stride", NULL);
+	stride = (p == NULL) ? 0x10 : *p;
+
+	/* XXX FIXME: Which property name is to use of the 2 following ? */
+	p = get_property(dp, "dcr-mmio-range", NULL);
+	if (p == NULL)
+		p = get_property(dp, "dcr-mmio-space", NULL);
+	if (p == NULL)
+		return OF_BAD_ADDR;
+
+	/* Maybe could do some better range checking here */
+	ret = of_translate_address(dp, p);
+	if (ret != OF_BAD_ADDR)
+		ret += (u64)(stride) * (u64)dcr_n;
+	if (out_stride)
+		*out_stride = stride;
+	return ret;
+}
+
+dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
+		   unsigned int dcr_c)
+{
+	dcr_host_t ret = { .token = NULL, .stride = 0 };
+	u64 addr;
+
+	pr_debug("dcr_map(%s, 0x%x, 0x%x)\n",
+		 dev->full_name, dcr_n, dcr_c);
+
+	addr = of_translate_dcr_address(dev, dcr_n, &ret.stride);
+	pr_debug("translates to addr: 0x%lx, stride: 0x%x\n",
+		 addr, ret.stride);
+	if (addr == OF_BAD_ADDR)
+		return ret;
+	pr_debug("mapping 0x%x bytes\n", dcr_c * ret.stride);
+	ret.token = ioremap(addr, dcr_c * ret.stride);
+	if (ret.token == NULL)
+		return ret;
+	pr_debug("mapped at 0x%p -> base is 0x%p\n",
+		 ret.token, ret.token - dcr_n * ret.stride);
+	ret.token -= dcr_n * ret.stride;
+	return ret;
+}
+
+void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c)
+{
+	dcr_host_t h = host;
+
+	if (h.token == NULL)
+		return;
+	h.token -= dcr_n * h.stride;
+	iounmap(h.token);
+	h.token = NULL;
+}
+
+#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */

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

* [PATCH 10/32] powerpc: Make EMAC use generic DCR access methods
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (8 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 9/32] powerpc: Generic DCR infrastructure Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 11/32] powerpc: Support for DCR based MPIC Benjamin Herrenschmidt
                   ` (21 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch makes the EMAC driver use the new DCR access methods. It
doesn't yet uses dcr_map() and thus still only work with real DCRs.
This will be fixed in a later patch

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 drivers/net/ibm_emac/ibm_emac_mal.h |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

Index: linux-cell/drivers/net/ibm_emac/ibm_emac_mal.h
===================================================================
--- linux-cell.orig/drivers/net/ibm_emac/ibm_emac_mal.h	2006-10-11 13:01:59.000000000 +1000
+++ linux-cell/drivers/net/ibm_emac/ibm_emac_mal.h	2006-10-11 14:35:28.000000000 +1000
@@ -24,6 +24,7 @@
 #include <linux/netdevice.h>
 
 #include <asm/io.h>
+#include <asm/dcr.h>
 
 /*
  * These MAL "versions" probably aren't the real versions IBM uses for these 
@@ -191,6 +192,7 @@ struct mal_commac {
 
 struct ibm_ocp_mal {
 	int			dcrbase;
+	dcr_host_t		dcrhost;
 
 	struct list_head	poll_list;
 	struct net_device	poll_dev;
@@ -207,12 +209,12 @@ struct ibm_ocp_mal {
 
 static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
 {
-	return mfdcr(mal->dcrbase + reg);
+	return dcr_read(mal->dcrhost, mal->dcrbase + reg);
 }
 
 static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
 {
-	mtdcr(mal->dcrbase + reg, val);
+	dcr_write(mal->dcrhost, mal->dcrbase + reg, val);
 }
 
 /* Register MAL devices */

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

* [PATCH 11/32] powerpc: Support for DCR based MPIC
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (9 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 10/32] powerpc: Make EMAC use generic DCR access methods Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 12/32] powerpc: Improve MPIC driver auto-configuration from DT Benjamin Herrenschmidt
                   ` (20 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch implements support for DCR based MPIC implementations. Such
implementations have the MPIC_USES_DCR flag set and don't use the phys_addr
argument of mpic_alloc (they require a valid dcr mapping in the device node)

This version of the patch can use a little bif of cleanup still (I can
probably consolidate rb->dbase/doff, at least once I'm sure on how the
hardware is actually supposed to work vs. possible simulator issues) and
it should be possible to build a DCR-only version of the driver. I need
to cleanup a bit the CONFIG_* handling for that and probably introduce
CONFIG_MPIC_MMIO and CONFIG_MPIC_DCR.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>


 arch/powerpc/sysdev/mpic.c |  138 ++++++++++++++++++++++++++++++++-------------
 include/asm-powerpc/mpic.h |   35 ++++++++++-
 2 files changed, 132 insertions(+), 41 deletions(-)

Index: linux-cell/arch/powerpc/sysdev/mpic.c
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/mpic.c	2006-10-16 17:20:39.000000000 +1000
+++ linux-cell/arch/powerpc/sysdev/mpic.c	2006-10-16 17:29:50.000000000 +1000
@@ -147,33 +147,51 @@ static u32 mpic_infos[][MPIC_IDX_END] = 
  */
 
 
-static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base,
-			    unsigned int reg)
-{
-	if (be)
-		return in_be32(base + (reg >> 2));
-	else
-		return in_le32(base + (reg >> 2));
+static inline u32 _mpic_read(enum mpic_reg_type type,
+			     struct mpic_reg_bank *rb,
+			     unsigned int reg)
+{
+	switch(type) {
+#ifdef CONFIG_PPC_DCR
+	case mpic_access_dcr:
+		return dcr_read(rb->dhost,
+				rb->dbase + reg + rb->doff);
+#endif
+	case mpic_access_mmio_be:
+		return in_be32(rb->base + (reg >> 2));
+	case mpic_access_mmio_le:
+	default:
+		return in_le32(rb->base + (reg >> 2));
+	}
 }
 
-static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base,
-			      unsigned int reg, u32 value)
+static inline void _mpic_write(enum mpic_reg_type type,
+			       struct mpic_reg_bank *rb,
+ 			       unsigned int reg, u32 value)
 {
-	if (be)
-		out_be32(base + (reg >> 2), value);
-	else
-		out_le32(base + (reg >> 2), value);
+	switch(type) {
+#ifdef CONFIG_PPC_DCR
+	case mpic_access_dcr:
+		return dcr_write(rb->dhost,
+				 rb->dbase + reg + rb->doff, value);
+#endif
+	case mpic_access_mmio_be:
+		return out_be32(rb->base + (reg >> 2), value);
+	case mpic_access_mmio_le:
+	default:
+		return out_le32(rb->base + (reg >> 2), value);
+	}
 }
 
 static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi)
 {
-	unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0;
+	enum mpic_reg_type type = mpic->reg_type;
 	unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
 			      (ipi * MPIC_INFO(GREG_IPI_STRIDE));
 
-	if (mpic->flags & MPIC_BROKEN_IPI)
-		be = !be;
-	return _mpic_read(be, mpic->gregs, offset);
+	if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le)
+		type = mpic_access_mmio_be;
+	return _mpic_read(type, &mpic->gregs, offset);
 }
 
 static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value)
@@ -181,7 +199,7 @@ static inline void _mpic_ipi_write(struc
 	unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
 			      (ipi * MPIC_INFO(GREG_IPI_STRIDE));
 
-	_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value);
+	_mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
 }
 
 static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
@@ -190,8 +208,7 @@ static inline u32 _mpic_cpu_read(struct 
 
 	if (mpic->flags & MPIC_PRIMARY)
 		cpu = hard_smp_processor_id();
-	return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,
-			  mpic->cpuregs[cpu], reg);
+	return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg);
 }
 
 static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
@@ -201,7 +218,7 @@ static inline void _mpic_cpu_write(struc
 	if (mpic->flags & MPIC_PRIMARY)
 		cpu = hard_smp_processor_id();
 
-	_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg, value);
+	_mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value);
 }
 
 static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg)
@@ -209,7 +226,7 @@ static inline u32 _mpic_irq_read(struct 
 	unsigned int	isu = src_no >> mpic->isu_shift;
 	unsigned int	idx = src_no & mpic->isu_mask;
 
-	return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
+	return _mpic_read(mpic->reg_type, &mpic->isus[isu],
 			  reg + (idx * MPIC_INFO(IRQ_STRIDE)));
 }
 
@@ -219,12 +236,12 @@ static inline void _mpic_irq_write(struc
 	unsigned int	isu = src_no >> mpic->isu_shift;
 	unsigned int	idx = src_no & mpic->isu_mask;
 
-	_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
+	_mpic_write(mpic->reg_type, &mpic->isus[isu],
 		    reg + (idx * MPIC_INFO(IRQ_STRIDE)), value);
 }
 
-#define mpic_read(b,r)		_mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r))
-#define mpic_write(b,r,v)	_mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v))
+#define mpic_read(b,r)		_mpic_read(mpic->reg_type,&(b),(r))
+#define mpic_write(b,r,v)	_mpic_write(mpic->reg_type,&(b),(r),(v))
 #define mpic_ipi_read(i)	_mpic_ipi_read(mpic,(i))
 #define mpic_ipi_write(i,v)	_mpic_ipi_write(mpic,(i),(v))
 #define mpic_cpu_read(i)	_mpic_cpu_read(mpic,(i))
@@ -238,6 +255,38 @@ static inline void _mpic_irq_write(struc
  */
 
 
+static void _mpic_map_mmio(struct mpic *mpic, unsigned long phys_addr,
+			   struct mpic_reg_bank *rb, unsigned int offset,
+			   unsigned int size)
+{
+	rb->base = ioremap(phys_addr + offset, size);
+	BUG_ON(rb->base == NULL);
+}
+
+#ifdef CONFIG_PPC_DCR
+static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb,
+			  unsigned int offset, unsigned int size)
+{
+	rb->dbase = mpic->dcr_base;
+	rb->doff = offset;
+	rb->dhost = dcr_map(mpic->of_node, rb->dbase + rb->doff, size);
+	BUG_ON(!DCR_MAP_OK(rb->dhost));
+}
+
+static inline void mpic_map(struct mpic *mpic, unsigned long phys_addr,
+			    struct mpic_reg_bank *rb, unsigned int offset,
+			    unsigned int size)
+{
+	if (mpic->flags & MPIC_USES_DCR)
+		_mpic_map_dcr(mpic, rb, offset, size);
+	else
+		_mpic_map_mmio(mpic, phys_addr, rb, offset, size);
+}
+#else /* CONFIG_PPC_DCR */
+#define mpic_map(m,p,b,o,s)	_mpic_map_mmio(m,p,b,o,s)
+#endif /* !CONFIG_PPC_DCR */
+
+
 
 /* Check if we have one of those nice broken MPICs with a flipped endian on
  * reads from IPI registers
@@ -883,6 +932,7 @@ struct mpic * __init mpic_alloc(struct d
 	if (flags & MPIC_PRIMARY)
 		mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
 #endif /* CONFIG_MPIC_BROKEN_U3 */
+
 #ifdef CONFIG_SMP
 	mpic->hc_ipi = mpic_ipi_chip;
 	mpic->hc_ipi.typename = name;
@@ -897,11 +947,26 @@ struct mpic * __init mpic_alloc(struct d
 	mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
 #endif
 
+	/* default register type */
+	mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ?
+		mpic_access_mmio_be : mpic_access_mmio_le;
+
+#ifdef CONFIG_PPC_DCR
+	if (mpic->flags & MPIC_USES_DCR) {
+		const u32 *dbasep;
+		BUG_ON(mpic->of_node == NULL);
+		dbasep = get_property(mpic->of_node, "dcr-reg", NULL);
+		BUG_ON(dbasep == NULL);
+		mpic->dcr_base = *dbasep;
+		mpic->reg_type = mpic_access_dcr;
+	}
+#else
+	BUG_ON (mpic->flags & MPIC_USES_DCR);
+#endif /* CONFIG_PPC_DCR */
+
 	/* Map the global registers */
-	mpic->gregs = ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x1000);
-	mpic->tmregs = mpic->gregs +
-		       ((MPIC_INFO(TIMER_BASE) - MPIC_INFO(GREG_BASE)) >> 2);
-	BUG_ON(mpic->gregs == NULL);
+	mpic_map(mpic, phys_addr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
+	mpic_map(mpic, phys_addr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
 	/* Reset */
 	if (flags & MPIC_WANTS_RESET) {
@@ -926,17 +991,16 @@ struct mpic * __init mpic_alloc(struct d
 
 	/* Map the per-CPU registers */
 	for (i = 0; i < mpic->num_cpus; i++) {
-		mpic->cpuregs[i] = ioremap(phys_addr + MPIC_INFO(CPU_BASE) +
-					   i * MPIC_INFO(CPU_STRIDE), 0x1000);
-		BUG_ON(mpic->cpuregs[i] == NULL);
+		mpic_map(mpic, phys_addr, &mpic->cpuregs[i],
+			 MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE),
+			 0x1000);
 	}
 
 	/* Initialize main ISU if none provided */
 	if (mpic->isu_size == 0) {
 		mpic->isu_size = mpic->num_sources;
-		mpic->isus[0] = ioremap(phys_addr + MPIC_INFO(IRQ_BASE),
-					MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
-		BUG_ON(mpic->isus[0] == NULL);
+		mpic_map(mpic, phys_addr, &mpic->isus[0],
+			 MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
 	}
 	mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
 	mpic->isu_mask = (1 << mpic->isu_shift) - 1;
@@ -979,8 +1043,8 @@ void __init mpic_assign_isu(struct mpic 
 
 	BUG_ON(isu_num >= MPIC_MAX_ISU);
 
-	mpic->isus[isu_num] = ioremap(phys_addr,
-				      MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+	mpic_map(mpic, phys_addr, &mpic->isus[isu_num], 0,
+		 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
 	if ((isu_first + mpic->isu_size) > mpic->num_sources)
 		mpic->num_sources = isu_first + mpic->isu_size;
 }
Index: linux-cell/include/asm-powerpc/mpic.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/mpic.h	2006-10-16 17:20:39.000000000 +1000
+++ linux-cell/include/asm-powerpc/mpic.h	2006-10-16 17:26:46.000000000 +1000
@@ -3,6 +3,7 @@
 #ifdef __KERNEL__
 
 #include <linux/irq.h>
+#include <asm/dcr.h>
 
 /*
  * Global registers
@@ -225,6 +226,23 @@ struct mpic_irq_fixup
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
 
+enum mpic_reg_type {
+	mpic_access_mmio_le,
+	mpic_access_mmio_be,
+#ifdef CONFIG_PPC_DCR
+	mpic_access_dcr
+#endif
+};
+
+struct mpic_reg_bank {
+	u32 __iomem	*base;
+#ifdef CONFIG_PPC_DCR
+	dcr_host_t	dhost;
+	unsigned int	dbase;
+	unsigned int	doff;
+#endif /* CONFIG_PPC_DCR */
+};
+
 /* The instance data of a given MPIC */
 struct mpic
 {
@@ -264,11 +282,18 @@ struct mpic
 	spinlock_t		fixup_lock;
 #endif
 
+	/* Register access method */
+	enum mpic_reg_type	reg_type;
+
 	/* The various ioremap'ed bases */
-	volatile u32 __iomem	*gregs;
-	volatile u32 __iomem	*tmregs;
-	volatile u32 __iomem	*cpuregs[MPIC_MAX_CPUS];
-	volatile u32 __iomem	*isus[MPIC_MAX_ISU];
+	struct mpic_reg_bank	gregs;
+	struct mpic_reg_bank	tmregs;
+	struct mpic_reg_bank	cpuregs[MPIC_MAX_CPUS];
+	struct mpic_reg_bank	isus[MPIC_MAX_ISU];
+
+#ifdef CONFIG_PPC_DCR
+	unsigned int		dcr_base;
+#endif
 
 #ifdef CONFIG_MPIC_WEIRD
 	/* Pointer to HW info array */
@@ -305,6 +330,8 @@ struct mpic
 #define MPIC_SPV_EOI			0x00000020
 /* No passthrough disable */
 #define MPIC_NO_PTHROU_DIS		0x00000040
+/* DCR based MPIC */
+#define MPIC_USES_DCR			0x00000080
 
 /* MPIC HW modification ID */
 #define MPIC_REGSET_MASK		0xf0000000

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

* [PATCH 12/32] powerpc: Improve MPIC driver auto-configuration from DT
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (10 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 11/32] powerpc: Support for DCR based MPIC Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 13/32] powerpc: Native cell support for MPIC in southbridge Benjamin Herrenschmidt
                   ` (19 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch applies on top of the MPIC DCR support. It makes the MPIC
driver capable of a lot more auto-configuration based on the device-tree,
for example, it can retreive it's own physical address if not passed as
an argument, find out if it's DCR or MMIO mapped, and set the BIG_ENDIAN
flag automatically in the presence of a "big-endian" property in the
device-tree node.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/sysdev/mpic.c |   50 +++++++++++++++++++++++++++++++++------------
 include/asm-powerpc/mpic.h |    4 +--
 2 files changed, 39 insertions(+), 15 deletions(-)

Index: linux-cell/arch/powerpc/sysdev/mpic.c
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/mpic.c	2006-11-06 14:34:17.000000000 +1100
+++ linux-cell/arch/powerpc/sysdev/mpic.c	2006-11-06 14:36:45.000000000 +1100
@@ -894,7 +894,7 @@ static struct irq_host_ops mpic_host_ops
  */
 
 struct mpic * __init mpic_alloc(struct device_node *node,
-				unsigned long phys_addr,
+				phys_addr_t phys_addr,
 				unsigned int flags,
 				unsigned int isu_size,
 				unsigned int irq_count,
@@ -904,6 +904,7 @@ struct mpic * __init mpic_alloc(struct d
 	u32		reg;
 	const char	*vers;
 	int		i;
+	u64		paddr = phys_addr;
 
 	mpic = alloc_bootmem(sizeof(struct mpic));
 	if (mpic == NULL)
@@ -943,6 +944,11 @@ struct mpic * __init mpic_alloc(struct d
 	mpic->irq_count = irq_count;
 	mpic->num_sources = 0; /* so far */
 
+	/* Check for "big-endian" in device-tree */
+	if (node && get_property(node, "big-endian", NULL) != NULL)
+		mpic->flags |= MPIC_BIG_ENDIAN;
+
+
 #ifdef CONFIG_MPIC_WEIRD
 	mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
 #endif
@@ -951,11 +957,17 @@ struct mpic * __init mpic_alloc(struct d
 	mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ?
 		mpic_access_mmio_be : mpic_access_mmio_le;
 
+	/* If no physical address is passed in, a device-node is mandatory */
+	BUG_ON(paddr == 0 && node == NULL);
+
+	/* If no physical address passed in, check if it's dcr based */
+	if (paddr == 0 && get_property(node, "dcr-reg", NULL) != NULL)
+		mpic->flags |= MPIC_USES_DCR;
+
 #ifdef CONFIG_PPC_DCR
 	if (mpic->flags & MPIC_USES_DCR) {
 		const u32 *dbasep;
-		BUG_ON(mpic->of_node == NULL);
-		dbasep = get_property(mpic->of_node, "dcr-reg", NULL);
+		dbasep = get_property(node, "dcr-reg", NULL);
 		BUG_ON(dbasep == NULL);
 		mpic->dcr_base = *dbasep;
 		mpic->reg_type = mpic_access_dcr;
@@ -964,9 +976,20 @@ struct mpic * __init mpic_alloc(struct d
 	BUG_ON (mpic->flags & MPIC_USES_DCR);
 #endif /* CONFIG_PPC_DCR */
 
+	/* If the MPIC is not DCR based, and no physical address was passed
+	 * in, try to obtain one
+	 */
+	if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) {
+		const u32 *reg;
+		reg = get_property(node, "reg", NULL);
+		BUG_ON(reg == NULL);
+		paddr = of_translate_address(node, reg);
+		BUG_ON(paddr == OF_BAD_ADDR);
+	}
+
 	/* Map the global registers */
-	mpic_map(mpic, phys_addr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
-	mpic_map(mpic, phys_addr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
+	mpic_map(mpic, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
+	mpic_map(mpic, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
 	/* Reset */
 	if (flags & MPIC_WANTS_RESET) {
@@ -991,7 +1014,7 @@ struct mpic * __init mpic_alloc(struct d
 
 	/* Map the per-CPU registers */
 	for (i = 0; i < mpic->num_cpus; i++) {
-		mpic_map(mpic, phys_addr, &mpic->cpuregs[i],
+		mpic_map(mpic, paddr, &mpic->cpuregs[i],
 			 MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE),
 			 0x1000);
 	}
@@ -999,7 +1022,7 @@ struct mpic * __init mpic_alloc(struct d
 	/* Initialize main ISU if none provided */
 	if (mpic->isu_size == 0) {
 		mpic->isu_size = mpic->num_sources;
-		mpic_map(mpic, phys_addr, &mpic->isus[0],
+		mpic_map(mpic, paddr, &mpic->isus[0],
 			 MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
 	}
 	mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
@@ -1020,10 +1043,11 @@ struct mpic * __init mpic_alloc(struct d
 		vers = "<unknown>";
 		break;
 	}
-	printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max %d CPUs\n",
-	       name, vers, phys_addr, mpic->num_cpus);
-	printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size,
-	       mpic->isu_shift, mpic->isu_mask);
+	printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx,"
+	       " max %d CPUs\n",
+	       name, vers, (unsigned long long)paddr, mpic->num_cpus);
+	printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n",
+	       mpic->isu_size, mpic->isu_shift, mpic->isu_mask);
 
 	mpic->next = mpics;
 	mpics = mpic;
@@ -1037,13 +1061,13 @@ struct mpic * __init mpic_alloc(struct d
 }
 
 void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
-			    unsigned long phys_addr)
+			    phys_addr_t paddr)
 {
 	unsigned int isu_first = isu_num * mpic->isu_size;
 
 	BUG_ON(isu_num >= MPIC_MAX_ISU);
 
-	mpic_map(mpic, phys_addr, &mpic->isus[isu_num], 0,
+	mpic_map(mpic, paddr, &mpic->isus[isu_num], 0,
 		 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
 	if ((isu_first + mpic->isu_size) > mpic->num_sources)
 		mpic->num_sources = isu_first + mpic->isu_size;
Index: linux-cell/include/asm-powerpc/mpic.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/mpic.h	2006-11-06 14:34:17.000000000 +1100
+++ linux-cell/include/asm-powerpc/mpic.h	2006-11-06 14:34:38.000000000 +1100
@@ -364,7 +364,7 @@ struct mpic
  * that is senses[0] correspond to linux irq "irq_offset".
  */
 extern struct mpic *mpic_alloc(struct device_node *node,
-			       unsigned long phys_addr,
+			       phys_addr_t phys_addr,
 			       unsigned int flags,
 			       unsigned int isu_size,
 			       unsigned int irq_count,
@@ -377,7 +377,7 @@ extern struct mpic *mpic_alloc(struct de
  * @phys_addr:	physical address of the ISU
  */
 extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
-			    unsigned long phys_addr);
+			    phys_addr_t phys_addr);
 
 /* Set default sense codes
  *

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

* [PATCH 13/32] powerpc: Native cell support for MPIC in southbridge
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (11 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 12/32] powerpc: Improve MPIC driver auto-configuration from DT Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 14/32] powerpc: Souped-up of_platform_device support Benjamin Herrenschmidt
                   ` (18 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

Add support for southbridges using the MPIC interrupt controller to
the native cell platforms.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/Kconfig                |    1 
 arch/powerpc/platforms/cell/setup.c |   44 ++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig	2006-11-06 15:05:40.000000000 +1100
+++ linux-cell/arch/powerpc/Kconfig	2006-11-06 15:15:45.000000000 +1100
@@ -461,6 +461,7 @@ config PPC_CELL_NATIVE
 	bool
 	select PPC_CELL
 	select PPC_DCR_MMIO
+	select MPIC
 	default n
 
 config PPC_IBM_CELL_BLADE
Index: linux-cell/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/setup.c	2006-11-06 15:02:21.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/setup.c	2006-11-06 15:05:44.000000000 +1100
@@ -50,6 +50,7 @@
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
 #include <asm/udbg.h>
+#include <asm/mpic.h>
 
 #include "interrupt.h"
 #include "iommu.h"
@@ -80,10 +81,53 @@ static void cell_progress(char *s, unsig
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
+static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
+{
+	struct mpic *mpic = desc->handler_data;
+	unsigned int virq;
+
+	virq = mpic_get_one_irq(mpic);
+	if (virq != NO_IRQ)
+		generic_handle_irq(virq);
+	desc->chip->eoi(irq);
+}
+
+static void __init mpic_init_IRQ(void)
+{
+	struct device_node *dn;
+	struct mpic *mpic;
+	unsigned int virq;
+
+	for (dn = NULL;
+	     (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
+		if (!device_is_compatible(dn, "CBEA,platform-open-pic"))
+			continue;
+
+		/* The MPIC driver will get everything it needs from the
+		 * device-tree, just pass 0 to all arguments
+		 */
+		mpic = mpic_alloc(dn, 0, 0, 0, 0, " MPIC     ");
+		if (mpic == NULL)
+			continue;
+		mpic_init(mpic);
+
+		virq = irq_of_parse_and_map(dn, 0);
+		if (virq == NO_IRQ)
+			continue;
+
+		printk(KERN_INFO "%s : hooking up to IRQ %d\n",
+		       dn->full_name, virq);
+		set_irq_data(virq, mpic);
+		set_irq_chained_handler(virq, cell_mpic_cascade);
+	}
+}
+
+
 static void __init cell_init_irq(void)
 {
 	iic_init_IRQ();
 	spider_init_IRQ();
+	mpic_init_IRQ();
 }
 
 static void __init cell_setup_arch(void)

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

* [PATCH 14/32] powerpc: Souped-up of_platform_device support
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (12 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 13/32] powerpc: Native cell support for MPIC in southbridge Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 16/32] powerpc: Refactor 64 bits DMA operations Benjamin Herrenschmidt
                   ` (17 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch first splits of_device.c and of_platform.c, the later containing
the bits relative to of_platform_device's. On the "breaks" side of things,
drivers uisng of_platform_device(s) need to include asm/of_platform.h now
and of_(un)register_driver is now of_(un)register_platform_driver.

In addition to a few utility functions to locate of_platform_device(s),
the main new addition is of_platform_bus_probe() which allows the platform
code to trigger an automatic creation of of_platform_devices for a whole
tree of devices.

The function acts based on the type of the various "parent" devices encountered
from a provided root, using either a default known list of bus types that can be
"probed" or a passed-in list. It will only register devices on busses matching
that list, which mean that typically, it will not register PCI devices, as
expected (since they will be picked up by the PCI layer).

This will be used by Cell platforms using 4xx-type IOs in the Axon bridge
and can be used by any embedded-type device as well.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/Makefile            |    2 
 arch/powerpc/kernel/of_device.c         |  172 ++------------
 arch/powerpc/kernel/of_platform.c       |  372 ++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/powermac/setup.c |    1 
 drivers/macintosh/smu.c                 |    3 
 drivers/macintosh/therm_adt746x.c       |    2 
 drivers/macintosh/therm_pm72.c          |    5 
 drivers/macintosh/therm_windtunnel.c    |    7 
 drivers/video/platinumfb.c              |    5 
 include/asm-powerpc/of_device.h         |   34 --
 include/asm-powerpc/of_platform.h       |   60 +++++
 11 files changed, 476 insertions(+), 187 deletions(-)

Index: linux-cell/arch/powerpc/kernel/of_device.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/of_device.c	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/of_device.c	2006-11-06 15:16:35.000000000 +1100
@@ -9,30 +9,26 @@
 #include <asm/of_device.h>
 
 /**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
+ * of_match_node - Tell if an device_node has a matching of_match structure
  * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
+ * @node: the of device structure to match against
  *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
+ * Low level utility function used by device matching.
  */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-					const struct of_device *dev)
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+					 const struct device_node *node)
 {
-	if (!dev->node)
-		return NULL;
 	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
 		int match = 1;
 		if (matches->name[0])
-			match &= dev->node->name
-				&& !strcmp(matches->name, dev->node->name);
+			match &= node->name
+				&& !strcmp(matches->name, node->name);
 		if (matches->type[0])
-			match &= dev->node->type
-				&& !strcmp(matches->type, dev->node->type);
+			match &= node->type
+				&& !strcmp(matches->type, node->type);
 		if (matches->compatible[0])
-			match &= device_is_compatible(dev->node,
-				matches->compatible);
+			match &= device_is_compatible(node,
+						      matches->compatible);
 		if (match)
 			return matches;
 		matches++;
@@ -40,16 +36,21 @@ const struct of_device_id *of_match_devi
 	return NULL;
 }
 
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+					const struct of_device *dev)
 {
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-	const struct of_device_id * matches = of_drv->match_table;
-
-	if (!matches)
-		return 0;
-
-	return of_match_device(matches, of_dev) != NULL;
+	if (!dev->node)
+		return NULL;
+	return of_match_node(matches, dev->node);
 }
 
 struct of_device *of_dev_get(struct of_device *dev)
@@ -71,96 +72,8 @@ void of_dev_put(struct of_device *dev)
 		put_device(&dev->dev);
 }
 
-
-static int of_device_probe(struct device *dev)
-{
-	int error = -ENODEV;
-	struct of_platform_driver *drv;
-	struct of_device *of_dev;
-	const struct of_device_id *match;
-
-	drv = to_of_platform_driver(dev->driver);
-	of_dev = to_of_device(dev);
-
-	if (!drv->probe)
-		return error;
-
-	of_dev_get(of_dev);
-
-	match = of_match_device(drv->match_table, of_dev);
-	if (match)
-		error = drv->probe(of_dev, match);
-	if (error)
-		of_dev_put(of_dev);
-
-	return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-	if (dev->driver && drv->remove)
-		drv->remove(of_dev);
-	return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-	int error = 0;
-
-	if (dev->driver && drv->suspend)
-		error = drv->suspend(of_dev, state);
-	return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-	int error = 0;
-
-	if (dev->driver && drv->resume)
-		error = drv->resume(of_dev);
-	return error;
-}
-
-struct bus_type of_platform_bus_type = {
-       .name	= "of_platform",
-       .match	= of_platform_bus_match,
-       .probe	= of_device_probe,
-       .remove	= of_device_remove,
-       .suspend	= of_device_suspend,
-       .resume	= of_device_resume,
-};
-
-static int __init of_bus_driver_init(void)
-{
-	return bus_register(&of_platform_bus_type);
-}
-
-postcore_initcall(of_bus_driver_init);
-
-int of_register_driver(struct of_platform_driver *drv)
-{
-	/* initialize common driver fields */
-	drv->driver.name = drv->name;
-	drv->driver.bus = &of_platform_bus_type;
-
-	/* register with core */
-	return driver_register(&drv->driver);
-}
-
-void of_unregister_driver(struct of_platform_driver *drv)
-{
-	driver_unregister(&drv->driver);
-}
-
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t dev_show_devspec(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct of_device *ofdev;
 
@@ -208,41 +121,10 @@ void of_device_unregister(struct of_devi
 	device_unregister(&ofdev->dev);
 }
 
-struct of_device* of_platform_device_create(struct device_node *np,
-					    const char *bus_id,
-					    struct device *parent)
-{
-	struct of_device *dev;
-
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev)
-		return NULL;
-	memset(dev, 0, sizeof(*dev));
-
-	dev->node = of_node_get(np);
-	dev->dma_mask = 0xffffffffUL;
-	dev->dev.dma_mask = &dev->dma_mask;
-	dev->dev.parent = parent;
-	dev->dev.bus = &of_platform_bus_type;
-	dev->dev.release = of_release_dev;
-
-	strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
-
-	if (of_device_register(dev) != 0) {
-		kfree(dev);
-		return NULL;
-	}
-
-	return dev;
-}
 
 EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_platform_bus_type);
-EXPORT_SYMBOL(of_register_driver);
-EXPORT_SYMBOL(of_unregister_driver);
 EXPORT_SYMBOL(of_device_register);
 EXPORT_SYMBOL(of_device_unregister);
 EXPORT_SYMBOL(of_dev_get);
 EXPORT_SYMBOL(of_dev_put);
-EXPORT_SYMBOL(of_platform_device_create);
 EXPORT_SYMBOL(of_release_dev);
Index: linux-cell/include/asm-powerpc/of_device.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/of_device.h	2006-10-06 13:48:23.000000000 +1000
+++ linux-cell/include/asm-powerpc/of_device.h	2006-11-06 15:45:18.000000000 +1100
@@ -6,12 +6,6 @@
 #include <linux/mod_devicetable.h>
 #include <asm/prom.h>
 
-/*
- * The of_platform_bus_type is a bus type used by drivers that do not
- * attach to a macio or similar bus but still use OF probing
- * mechanism
- */
-extern struct bus_type of_platform_bus_type;
 
 /*
  * The of_device is a kind of "base class" that is a superset of
@@ -26,40 +20,16 @@ struct of_device
 };
 #define	to_of_device(d) container_of(d, struct of_device, dev)
 
+extern const struct of_device_id *of_match_node(
+	const struct of_device_id *matches, const struct device_node *node);
 extern const struct of_device_id *of_match_device(
 	const struct of_device_id *matches, const struct of_device *dev);
 
 extern struct of_device *of_dev_get(struct of_device *dev);
 extern void of_dev_put(struct of_device *dev);
 
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (of_platform_bus_type)
- */
-struct of_platform_driver
-{
-	char			*name;
-	struct of_device_id	*match_table;
-	struct module		*owner;
-
-	int	(*probe)(struct of_device* dev, const struct of_device_id *match);
-	int	(*remove)(struct of_device* dev);
-
-	int	(*suspend)(struct of_device* dev, pm_message_t state);
-	int	(*resume)(struct of_device* dev);
-	int	(*shutdown)(struct of_device* dev);
-
-	struct device_driver	driver;
-};
-#define	to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv);
-extern void of_unregister_driver(struct of_platform_driver *drv);
 extern int of_device_register(struct of_device *ofdev);
 extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
-						   const char *bus_id,
-						   struct device *parent);
 extern void of_release_dev(struct device *dev);
 
 #endif /* __KERNEL__ */
Index: linux-cell/arch/powerpc/kernel/of_platform.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/of_platform.c	2006-11-06 15:45:18.000000000 +1100
@@ -0,0 +1,372 @@
+/*
+ *    Copyright (C) 2006 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.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+#include <asm/dcr.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+
+
+/*
+ * The list of OF IDs below is used for matching bus types in the
+ * system whose devices are to be exposed as of_platform_devices.
+ *
+ * This is the default list valid for most platforms. This file provides
+ * functions who can take an explicit list if necessary though
+ *
+ * The search is always performed recursively looking for children of
+ * the provided device_node and recursively if such a children matches
+ * a bus type in the list
+ */
+
+static struct of_device_id of_default_bus_ids[] = {
+	{ .type = "soc", },
+	{ .compatible = "soc", },
+	{ .type = "spider", },
+	{ .type = "axon", },
+	{ .type = "plb5", },
+	{ .type = "plb4", },
+	{ .type = "opb", },
+	{},
+};
+
+/*
+ *
+ * OF platform device type definition & base infrastructure
+ *
+ */
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct of_device * of_dev = to_of_device(dev);
+	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
+	const struct of_device_id * matches = of_drv->match_table;
+
+	if (!matches)
+		return 0;
+
+	return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+	int error = -ENODEV;
+	struct of_platform_driver *drv;
+	struct of_device *of_dev;
+	const struct of_device_id *match;
+
+	drv = to_of_platform_driver(dev->driver);
+	of_dev = to_of_device(dev);
+
+	if (!drv->probe)
+		return error;
+
+	of_dev_get(of_dev);
+
+	match = of_match_device(drv->match_table, of_dev);
+	if (match)
+		error = drv->probe(of_dev, match);
+	if (error)
+		of_dev_put(of_dev);
+
+	return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+	struct of_device * of_dev = to_of_device(dev);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+
+	if (dev->driver && drv->remove)
+		drv->remove(of_dev);
+	return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+	struct of_device * of_dev = to_of_device(dev);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->suspend)
+		error = drv->suspend(of_dev, state);
+	return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+	struct of_device * of_dev = to_of_device(dev);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->resume)
+		error = drv->resume(of_dev);
+	return error;
+}
+
+struct bus_type of_platform_bus_type = {
+       .name	= "of_platform",
+       .match	= of_platform_bus_match,
+       .probe	= of_platform_device_probe,
+       .remove	= of_platform_device_remove,
+       .suspend	= of_platform_device_suspend,
+       .resume	= of_platform_device_resume,
+};
+EXPORT_SYMBOL(of_platform_bus_type);
+
+static int __init of_bus_driver_init(void)
+{
+	return bus_register(&of_platform_bus_type);
+}
+
+postcore_initcall(of_bus_driver_init);
+
+int of_register_platform_driver(struct of_platform_driver *drv)
+{
+	/* initialize common driver fields */
+	drv->driver.name = drv->name;
+	drv->driver.bus = &of_platform_bus_type;
+
+	/* register with core */
+	return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(of_register_platform_driver);
+
+void of_unregister_platform_driver(struct of_platform_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(of_unregister_platform_driver);
+
+static void of_platform_make_bus_id(struct of_device *dev)
+{
+	struct device_node *node = dev->node;
+	char *name = dev->dev.bus_id;
+	const u32 *reg;
+	u64 addr;
+
+	/*
+	 * If it's a DCR based device, use 'd' for native DCRs
+	 * and 'D' for MMIO DCRs.
+	 */
+#ifdef CONFIG_PPC_DCR
+	reg = get_property(node, "dcr-reg", NULL);
+	if (reg) {
+#ifdef CONFIG_PPC_DCR_NATIVE
+		snprintf(name, BUS_ID_SIZE, "d%x.%s",
+			 *reg, node->name);
+#else /* CONFIG_PPC_DCR_NATIVE */
+		addr = of_translate_dcr_address(node, *reg, NULL);
+		if (addr != OF_BAD_ADDR) {
+			snprintf(name, BUS_ID_SIZE,
+				 "D%llx.%s", (unsigned long long)addr,
+				 node->name);
+			return;
+		}
+#endif /* !CONFIG_PPC_DCR_NATIVE */
+	}
+#endif /* CONFIG_PPC_DCR */
+
+	/*
+	 * For MMIO, get the physical address
+	 */
+	reg = get_property(node, "reg", NULL);
+	if (reg) {
+		addr = of_translate_address(node, reg);
+		if (addr != OF_BAD_ADDR) {
+			snprintf(name, BUS_ID_SIZE,
+				 "%llx.%s", (unsigned long long)addr,
+				 node->name);
+			return;
+		}
+	}
+
+	/*
+	 * No BusID, use the node name and pray
+	 */
+	snprintf(name, BUS_ID_SIZE, "%s", node->name);
+}
+
+struct of_device* of_platform_device_create(struct device_node *np,
+					    const char *bus_id,
+					    struct device *parent)
+{
+	struct of_device *dev;
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
+
+	dev->node = of_node_get(np);
+	dev->dma_mask = 0xffffffffUL;
+	dev->dev.dma_mask = &dev->dma_mask;
+	dev->dev.parent = parent;
+	dev->dev.bus = &of_platform_bus_type;
+	dev->dev.release = of_release_dev;
+
+	if (bus_id)
+		strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
+	else
+		of_platform_make_bus_id(dev);
+
+	if (of_device_register(dev) != 0) {
+		kfree(dev);
+		return NULL;
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL(of_platform_device_create);
+
+
+
+/**
+ * of_platform_bus_create - Create an OF device for a bus node and all its
+ * children. Optionally recursively instanciate matching busses.
+ * @bus: device node of the bus to instanciate
+ * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
+ * disallow recursive creation of child busses
+ */
+static int of_platform_bus_create(struct device_node *bus,
+				  struct of_device_id *matches,
+				  struct device *parent)
+{
+	struct device_node *child;
+	struct of_device *dev;
+	int rc = 0;
+
+	for (child = NULL; (child = of_get_next_child(bus, child)); ) {
+		pr_debug("   create child: %s\n", child->full_name);
+		dev = of_platform_device_create(child, NULL, parent);
+		if (dev == NULL)
+			rc = -ENOMEM;
+		else if (!of_match_node(matches, child))
+			continue;
+		if (rc == 0) {
+			pr_debug("   and sub busses\n");
+			rc = of_platform_bus_create(child, matches, &dev->dev);
+		} if (rc) {
+			of_node_put(child);
+			break;
+		}
+	}
+	return rc;
+}
+
+/**
+ * of_platform_bus_probe - Probe the device-tree for platform busses
+ * @root: parent of the first level to probe or NULL for the root of the tree
+ * @matches: match table, NULL to use the default
+ * @parent: parent to hook devices from, NULL for toplevel
+ *
+ * Note that children of the provided root are not instanciated as devices
+ * unless the specified root itself matches the bus list and is not NULL.
+ */
+
+int of_platform_bus_probe(struct device_node *root,
+			  struct of_device_id *matches,
+			  struct device *parent)
+{
+	struct device_node *child;
+	struct of_device *dev;
+	int rc = 0;
+
+	if (matches == NULL)
+		matches = of_default_bus_ids;
+	if (matches == OF_NO_DEEP_PROBE)
+		return -EINVAL;
+	if (root == NULL)
+		root = of_find_node_by_path("/");
+	else
+		of_node_get(root);
+
+	pr_debug("of_platform_bus_probe()\n");
+	pr_debug(" starting at: %s\n", root->full_name);
+
+	/* Do a self check of bus type, if there's a match, create
+	 * children
+	 */
+	if (of_match_node(matches, root)) {
+		pr_debug(" root match, create all sub devices\n");
+		dev = of_platform_device_create(root, NULL, parent);
+		if (dev == NULL) {
+			rc = -ENOMEM;
+			goto bail;
+		}
+		pr_debug(" create all sub busses\n");
+		rc = of_platform_bus_create(root, matches, &dev->dev);
+		goto bail;
+	}
+	for (child = NULL; (child = of_get_next_child(root, child)); ) {
+		if (!of_match_node(matches, child))
+			continue;
+
+		pr_debug("  match: %s\n", child->full_name);
+		dev = of_platform_device_create(child, NULL, parent);
+		if (dev == NULL)
+			rc = -ENOMEM;
+		else
+			rc = of_platform_bus_create(child, matches, &dev->dev);
+		if (rc) {
+			of_node_put(child);
+			break;
+		}
+	}
+ bail:
+	of_node_put(root);
+	return rc;
+}
+EXPORT_SYMBOL(of_platform_bus_probe);
+
+static int of_dev_node_match(struct device *dev, void *data)
+{
+	return to_of_device(dev)->node == data;
+}
+
+struct of_device *of_find_device_by_node(struct device_node *np)
+{
+	struct device *dev;
+
+	dev = bus_find_device(&of_platform_bus_type,
+			      NULL, np, of_dev_node_match);
+	if (dev)
+		return to_of_device(dev);
+	return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
+static int of_dev_phandle_match(struct device *dev, void *data)
+{
+	phandle *ph = data;
+	return to_of_device(dev)->node->linux_phandle == *ph;
+}
+
+struct of_device *of_find_device_by_phandle(phandle ph)
+{
+	struct device *dev;
+
+	dev = bus_find_device(&of_platform_bus_type,
+			      NULL, &ph, of_dev_phandle_match);
+	if (dev)
+		return to_of_device(dev);
+	return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_phandle);
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile	2006-11-06 15:05:40.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/Makefile	2006-11-06 15:45:18.000000000 +1100
@@ -21,7 +21,7 @@ obj-$(CONFIG_PPC64)		+= setup_64.o binfm
 obj-$(CONFIG_PPC64)		+= vdso64/
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
 obj-$(CONFIG_PPC_970_NAP)	+= idle_power4.o
-obj-$(CONFIG_PPC_OF)		+= of_device.o prom_parse.o
+obj-$(CONFIG_PPC_OF)		+= of_device.o of_platform.o prom_parse.o
 procfs-$(CONFIG_PPC64)		:= proc_ppc64.o
 obj-$(CONFIG_PROC_FS)		+= $(procfs-y)
 rtaspci-$(CONFIG_PPC64)		:= rtas_pci.o
Index: linux-cell/drivers/macintosh/therm_pm72.c
===================================================================
--- linux-cell.orig/drivers/macintosh/therm_pm72.c	2006-10-06 13:48:04.000000000 +1000
+++ linux-cell/drivers/macintosh/therm_pm72.c	2006-11-06 15:16:35.000000000 +1100
@@ -129,6 +129,7 @@
 #include <asm/sections.h>
 #include <asm/of_device.h>
 #include <asm/macio.h>
+#include <asm/of_platform.h>
 
 #include "therm_pm72.h"
 
@@ -2236,14 +2237,14 @@ static int __init therm_pm72_init(void)
 		return -ENODEV;
 	}
 
-	of_register_driver(&fcu_of_platform_driver);
+	of_register_platform_driver(&fcu_of_platform_driver);
 	
 	return 0;
 }
 
 static void __exit therm_pm72_exit(void)
 {
-	of_unregister_driver(&fcu_of_platform_driver);
+	of_unregister_platform_driver(&fcu_of_platform_driver);
 
 	if (of_dev)
 		of_device_unregister(of_dev);
Index: linux-cell/include/asm-powerpc/of_platform.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-powerpc/of_platform.h	2006-11-06 15:16:35.000000000 +1100
@@ -0,0 +1,60 @@
+/*
+ *    Copyright (C) 2006 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.
+ *
+ */
+
+#include <asm/of_device.h>
+
+/*
+ * The of_platform_bus_type is a bus type used by drivers that do not
+ * attach to a macio or similar bus but still use OF probing
+ * mechanism
+ */
+extern struct bus_type of_platform_bus_type;
+
+/*
+ * An of_platform_driver driver is attached to a basic of_device on
+ * the "platform bus" (of_platform_bus_type)
+ */
+struct of_platform_driver
+{
+	char			*name;
+	struct of_device_id	*match_table;
+	struct module		*owner;
+
+	int	(*probe)(struct of_device* dev,
+			 const struct of_device_id *match);
+	int	(*remove)(struct of_device* dev);
+
+	int	(*suspend)(struct of_device* dev, pm_message_t state);
+	int	(*resume)(struct of_device* dev);
+	int	(*shutdown)(struct of_device* dev);
+
+	struct device_driver	driver;
+};
+#define	to_of_platform_driver(drv) \
+	container_of(drv,struct of_platform_driver, driver)
+
+/* Platform drivers register/unregister */
+extern int of_register_platform_driver(struct of_platform_driver *drv);
+extern void of_unregister_platform_driver(struct of_platform_driver *drv);
+
+/* Platform devices and busses creation */
+extern struct of_device *of_platform_device_create(struct device_node *np,
+						   const char *bus_id,
+						   struct device *parent);
+/* pseudo "matches" value to not do deep probe */
+#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1)
+
+extern int of_platform_bus_probe(struct device_node *root,
+				 struct of_device_id *matches,
+				 struct device *parent);
+
+extern struct of_device *of_find_device_by_node(struct device_node *np);
+extern struct of_device *of_find_device_by_phandle(phandle ph);
Index: linux-cell/arch/powerpc/platforms/powermac/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/setup.c	2006-11-06 15:02:21.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/powermac/setup.c	2006-11-06 15:18:34.000000000 +1100
@@ -70,6 +70,7 @@
 #include <asm/pmac_feature.h>
 #include <asm/time.h>
 #include <asm/of_device.h>
+#include <asm/of_platform.h>
 #include <asm/mmu_context.h>
 #include <asm/iommu.h>
 #include <asm/smu.h>
Index: linux-cell/drivers/macintosh/smu.c
===================================================================
--- linux-cell.orig/drivers/macintosh/smu.c	2006-10-09 12:03:33.000000000 +1000
+++ linux-cell/drivers/macintosh/smu.c	2006-11-06 15:16:35.000000000 +1100
@@ -46,6 +46,7 @@
 #include <asm/abs_addr.h>
 #include <asm/uaccess.h>
 #include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 #define VERSION "0.7"
 #define AUTHOR  "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
@@ -653,7 +654,7 @@ static int __init smu_init_sysfs(void)
 	 * I'm a bit too far from figuring out how that works with those
 	 * new chipsets, but that will come back and bite us
 	 */
-	of_register_driver(&smu_of_platform_driver);
+	of_register_platform_driver(&smu_of_platform_driver);
 	return 0;
 }
 
Index: linux-cell/drivers/video/platinumfb.c
===================================================================
--- linux-cell.orig/drivers/video/platinumfb.c	2006-10-23 14:41:38.000000000 +1000
+++ linux-cell/drivers/video/platinumfb.c	2006-11-06 15:16:35.000000000 +1100
@@ -34,6 +34,7 @@
 #include <asm/prom.h>
 #include <asm/pgtable.h>
 #include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 #include "macmodes.h"
 #include "platinumfb.h"
@@ -682,14 +683,14 @@ static int __init platinumfb_init(void)
 		return -ENODEV;
 	platinumfb_setup(option);
 #endif
-	of_register_driver(&platinum_driver);
+	of_register_platform_driver(&platinum_driver);
 
 	return 0;
 }
 
 static void __exit platinumfb_exit(void)
 {
-	of_unregister_driver(&platinum_driver);	
+	of_unregister_platform_driver(&platinum_driver);
 }
 
 MODULE_LICENSE("GPL");
Index: linux-cell/drivers/macintosh/therm_adt746x.c
===================================================================
--- linux-cell.orig/drivers/macintosh/therm_adt746x.c	2006-10-06 13:48:04.000000000 +1000
+++ linux-cell/drivers/macintosh/therm_adt746x.c	2006-11-06 15:45:42.000000000 +1100
@@ -30,7 +30,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/sections.h>
-#include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 #undef DEBUG
 
Index: linux-cell/drivers/macintosh/therm_windtunnel.c
===================================================================
--- linux-cell.orig/drivers/macintosh/therm_windtunnel.c	2006-10-06 13:48:04.000000000 +1000
+++ linux-cell/drivers/macintosh/therm_windtunnel.c	2006-11-06 15:46:39.000000000 +1100
@@ -36,12 +36,13 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/sections.h>
-#include <asm/of_device.h>
+#include <asm/of_platform.h>
 #include <asm/macio.h>
 
 #define LOG_TEMP		0			/* continously log temperature */
@@ -511,14 +512,14 @@ g4fan_init( void )
 		return -ENODEV;
 	}
 
-	of_register_driver( &therm_of_driver );
+	of_register_platform_driver( &therm_of_driver );
 	return 0;
 }
 
 static void __exit
 g4fan_exit( void )
 {
-	of_unregister_driver( &therm_of_driver );
+	of_unregister_platform_driver( &therm_of_driver );
 
 	if( x.of_dev )
 		of_device_unregister( x.of_dev );

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

* [PATCH 15/32] powerpc: Hook of_platform_bus_probe with cell
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (14 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 16/32] powerpc: Refactor 64 bits DMA operations Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 17/32] powerpc: Add DMA ops support for of_plaform_device to Cell Benjamin Herrenschmidt
                   ` (15 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

Hook up of_platform_bus_probe with the cell platform in order to publish
the non-PCI devices in the device-tree of cell blades as of_platform_device(s)

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/platforms/cell/setup.c |    9 +++++++++
 1 file changed, 9 insertions(+)

Index: linux-cell/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/setup.c	2006-10-26 16:41:49.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/setup.c	2006-10-26 16:42:30.000000000 +1000
@@ -51,6 +51,7 @@
 #include <asm/spu_priv1.h>
 #include <asm/udbg.h>
 #include <asm/mpic.h>
+#include <asm/of_platform.h>
 
 #include "interrupt.h"
 #include "iommu.h"
@@ -81,6 +82,14 @@ static void cell_progress(char *s, unsig
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
+static int __init cell_publish_devices(void)
+{
+	if (machine_is(cell))
+		of_platform_bus_probe(NULL, NULL, NULL);
+	return 0;
+}
+device_initcall(cell_publish_devices);
+
 static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
 {
 	struct mpic *mpic = desc->handler_data;

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

* [PATCH 16/32] powerpc: Refactor 64 bits DMA operations
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (13 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 14/32] powerpc: Souped-up of_platform_device support Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 15/32] powerpc: Hook of_platform_bus_probe with cell Benjamin Herrenschmidt
                   ` (16 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch completely refactors DMA operations for 64 bits powerpc. 32 bits
is untouched for now.

We use the new dev_sysdata structure to add the dma operations pointer
and associated data to struct device. While at it, we also add the OF node
pointer and numa node. In the future, we might want to look into merging
that with pci_dn as well.

The old vio, pci-iommu and pci-direct DMA ops are gone. They are now replaced
by a set of generic iommu and direct DMA ops (non PCI specific) that can be
used by bus types. The toplevel implementation is now inline.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/Makefile               |    3 
 arch/powerpc/kernel/dma_64.c               |  238 ++++++++++++++++-------------
 arch/powerpc/kernel/ibmebus.c              |    6 
 arch/powerpc/kernel/iommu.c                |    6 
 arch/powerpc/kernel/of_platform.c          |    9 -
 arch/powerpc/kernel/pci_64.c               |   26 ++-
 arch/powerpc/kernel/pci_direct_iommu.c     |   98 -----------
 arch/powerpc/kernel/pci_iommu.c            |  164 -------------------
 arch/powerpc/kernel/setup_64.c             |    1 
 arch/powerpc/kernel/vio.c                  |   94 ++---------
 arch/powerpc/platforms/cell/iommu.c        |   21 --
 arch/powerpc/platforms/iseries/iommu.c     |   12 -
 arch/powerpc/platforms/iseries/pci.c       |    2 
 arch/powerpc/platforms/pseries/iommu.c     |   90 +++++-----
 arch/powerpc/platforms/pseries/pci_dlpar.c |    4 
 arch/powerpc/sysdev/dart_iommu.c           |   31 +--
 include/asm-powerpc/device.h               |   12 +
 include/asm-powerpc/dma-mapping.h          |  180 +++++++++++++++++----
 include/asm-powerpc/ibmebus.h              |    1 
 include/asm-powerpc/iommu.h                |   20 +-
 include/asm-powerpc/iseries/iommu.h        |    4 
 include/asm-powerpc/machdep.h              |    4 
 include/asm-powerpc/of_device.h            |    2 
 include/asm-powerpc/pci.h                  |    8 
 include/asm-powerpc/vio.h                  |    1 
 25 files changed, 440 insertions(+), 597 deletions(-)

Index: linux-cell/arch/powerpc/kernel/dma_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/dma_64.c	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/dma_64.c	2006-11-10 18:40:55.000000000 +1100
@@ -1,151 +1,185 @@
 /*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation
  *
- * Implements the generic device dma API for ppc64. Handles
- * the pci and vio busses
+ * Provide default implementations of the DMA mapping callbacks for
+ * directly mapped busses and busses using the iommu infrastructure
  */
 
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
-/* 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>
+#include <asm/iommu.h>
+#include <asm/abs_addr.h>
 
-static struct dma_mapping_ops *get_dma_ops(struct device *dev)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type)
-		return &pci_dma_ops;
-#endif
-#ifdef CONFIG_IBMVIO
-	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;
-}
+/*
+ * Generic iommu implementation
+ */
 
-int dma_supported(struct device *dev, u64 mask)
+static inline unsigned long device_to_mask(struct device *dev)
 {
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+	if (dev->dma_mask && *dev->dma_mask)
+		return *dev->dma_mask;
+	/* Assume devices without mask can take 32 bit addresses */
+	return 0xfffffffful;
+}
 
-	BUG_ON(!dma_ops);
 
-	return dma_ops->dma_supported(dev, mask);
+/* Allocates a contiguous real buffer and creates mappings over it.
+ * Returns the virtual address of the buffer and sets dma_handle
+ * to the dma address (mapping) of the first page.
+ */
+static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
+				      dma_addr_t *dma_handle, gfp_t flag)
+{
+	return iommu_alloc_coherent(dev->sysdata.dma_data, size, dma_handle,
+				    device_to_mask(dev), flag,
+				    dev->sysdata.numa_node);
 }
-EXPORT_SYMBOL(dma_supported);
 
-int dma_set_mask(struct device *dev, u64 dma_mask)
+static void dma_iommu_free_coherent(struct device *dev, size_t size,
+				    void *vaddr, dma_addr_t dma_handle)
 {
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type)
-		return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
-#endif
-#ifdef CONFIG_IBMVIO
-	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;
+	iommu_free_coherent(dev->sysdata.dma_data, size, vaddr, dma_handle);
 }
-EXPORT_SYMBOL(dma_set_mask);
 
-void *dma_alloc_coherent(struct device *dev, size_t size,
-		dma_addr_t *dma_handle, gfp_t flag)
+/* Creates TCEs for a user provided buffer.  The user buffer must be
+ * contiguous real kernel storage (not vmalloc).  The address of the buffer
+ * passed here is the kernel (virtual) address of the buffer.  The buffer
+ * need not be page aligned, the dma_addr_t returned will point to the same
+ * byte within the page as vaddr.
+ */
+static dma_addr_t dma_iommu_map_single(struct device *dev, void *vaddr,
+				       size_t size,
+				       enum dma_data_direction direction)
 {
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-	BUG_ON(!dma_ops);
-
-	return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+	return iommu_map_single(dev->sysdata.dma_data, vaddr, size,
+			        device_to_mask(dev), direction);
 }
-EXPORT_SYMBOL(dma_alloc_coherent);
 
-void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-		dma_addr_t dma_handle)
+
+static void dma_iommu_unmap_single(struct device *dev, dma_addr_t dma_handle,
+				   size_t size,
+				   enum dma_data_direction direction)
 {
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+	iommu_unmap_single(dev->sysdata.dma_data, dma_handle, size, direction);
+}
 
-	BUG_ON(!dma_ops);
 
-	dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
+			    int nelems, enum dma_data_direction direction)
+{
+	return iommu_map_sg(dev->sysdata.dma_data, sglist, nelems,
+			    device_to_mask(dev), direction);
 }
-EXPORT_SYMBOL(dma_free_coherent);
 
-dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-		enum dma_data_direction direction)
+static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist,
+		int nelems, enum dma_data_direction direction)
 {
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-	BUG_ON(!dma_ops);
-
-	return dma_ops->map_single(dev, cpu_addr, size, direction);
+	iommu_unmap_sg(dev->sysdata.dma_data, sglist, nelems, direction);
 }
-EXPORT_SYMBOL(dma_map_single);
 
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		enum dma_data_direction direction)
+/* We support DMA to/from any memory page via the iommu */
+static int dma_iommu_dma_supported(struct device *dev, u64 mask)
 {
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+	struct iommu_table *tbl = dev->sysdata.dma_data;
 
-	BUG_ON(!dma_ops);
-
-	dma_ops->unmap_single(dev, dma_addr, size, direction);
+	if (!tbl || tbl->it_offset > mask) {
+		printk(KERN_INFO
+		       "Warning: IOMMU offset too big for device mask\n");
+		if (tbl)
+			printk(KERN_INFO
+			       "mask: 0x%08lx, table offset: 0x%08lx\n",
+				mask, tbl->it_offset);
+		else
+			printk(KERN_INFO "mask: 0x%08lx, table unavailable\n",
+				mask);
+		return 0;
+	} else
+		return 1;
 }
-EXPORT_SYMBOL(dma_unmap_single);
 
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-		unsigned long offset, size_t size,
-		enum dma_data_direction direction)
-{
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+struct dma_mapping_ops dma_iommu_ops = {
+	.alloc_coherent	= dma_iommu_alloc_coherent,
+	.free_coherent	= dma_iommu_free_coherent,
+	.map_single	= dma_iommu_map_single,
+	.unmap_single	= dma_iommu_unmap_single,
+	.map_sg		= dma_iommu_map_sg,
+	.unmap_sg	= dma_iommu_unmap_sg,
+	.dma_supported	= dma_iommu_dma_supported,
+};
+EXPORT_SYMBOL(dma_iommu_ops);
 
-	BUG_ON(!dma_ops);
+/*
+ * Generic direct DMA implementation
+ */
 
-	return dma_ops->map_single(dev, page_address(page) + offset, size,
-			direction);
+static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag)
+{
+	void *ret;
+
+	/* TODO: Maybe use the numa node here too ? */
+	ret = (void *)__get_free_pages(flag, get_order(size));
+	if (ret != NULL) {
+		memset(ret, 0, size);
+		*dma_handle = virt_to_abs(ret);
+	}
+	return ret;
 }
-EXPORT_SYMBOL(dma_map_page);
 
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-		enum dma_data_direction direction)
+static void dma_direct_free_coherent(struct device *dev, size_t size,
+				     void *vaddr, dma_addr_t dma_handle)
 {
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+	free_pages((unsigned long)vaddr, get_order(size));
+}
 
-	BUG_ON(!dma_ops);
+static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr,
+					size_t size,
+					enum dma_data_direction direction)
+{
+	return virt_to_abs(ptr);
+}
 
-	dma_ops->unmap_single(dev, dma_address, size, direction);
+static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr,
+				    size_t size,
+				    enum dma_data_direction direction)
+{
 }
-EXPORT_SYMBOL(dma_unmap_page);
 
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-		enum dma_data_direction direction)
+static int dma_direct_map_sg(struct device *dev, struct scatterlist *sg,
+			     int nents, enum dma_data_direction direction)
 {
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+	int i;
 
-	BUG_ON(!dma_ops);
+	for (i = 0; i < nents; i++, sg++) {
+		sg->dma_address = page_to_phys(sg->page) + sg->offset;
+		sg->dma_length = sg->length;
+	}
 
-	return dma_ops->map_sg(dev, sg, nents, direction);
+	return nents;
 }
-EXPORT_SYMBOL(dma_map_sg);
 
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-		enum dma_data_direction direction)
+static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
+				int nents, enum dma_data_direction direction)
 {
-	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-	BUG_ON(!dma_ops);
+}
 
-	dma_ops->unmap_sg(dev, sg, nhwentries, direction);
+static int dma_direct_dma_supported(struct device *dev, u64 mask)
+{
+	/* Could be improved to check for memory though it better be
+	 * done via some global so platforms can set the limit in case
+	 * they have limited DMA windows
+	 */
+	return mask >= DMA_32BIT_MASK;
 }
-EXPORT_SYMBOL(dma_unmap_sg);
+
+struct dma_mapping_ops dma_direct_ops = {
+	.alloc_coherent	= dma_direct_alloc_coherent,
+	.free_coherent	= dma_direct_free_coherent,
+	.map_single	= dma_direct_map_single,
+	.unmap_single	= dma_direct_unmap_single,
+	.map_sg		= dma_direct_map_sg,
+	.unmap_sg	= dma_direct_unmap_sg,
+	.dma_supported	= dma_direct_dma_supported,
+};
+EXPORT_SYMBOL(dma_direct_ops);
Index: linux-cell/arch/powerpc/kernel/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/iommu.c	2006-11-02 13:16:16.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/iommu.c	2006-11-10 18:11:14.000000000 +1100
@@ -258,9 +258,9 @@ static void iommu_free(struct iommu_tabl
 	spin_unlock_irqrestore(&(tbl->it_lock), flags);
 }
 
-int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
-		struct scatterlist *sglist, int nelems,
-		unsigned long mask, enum dma_data_direction direction)
+int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+		 int nelems, unsigned long mask,
+		 enum dma_data_direction direction)
 {
 	dma_addr_t dma_next = 0, dma_addr;
 	unsigned long flags;
Index: linux-cell/arch/powerpc/kernel/pci_direct_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_direct_iommu.c	2006-10-06 13:45:18.000000000 +1000
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,98 +0,0 @@
-/*
- * Support for DMA from PCI devices to main memory on
- * machines without an iommu or with directly addressable
- * RAM (typically a pmac with 2Gb of RAM or less)
- *
- * Copyright (C) 2003 Benjamin 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/abs_addr.h>
-#include <asm/ppc-pci.h>
-
-static void *pci_direct_alloc_coherent(struct device *hwdev, size_t size,
-				   dma_addr_t *dma_handle, gfp_t flag)
-{
-	void *ret;
-
-	ret = (void *)__get_free_pages(flag, get_order(size));
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_abs(ret);
-	}
-	return ret;
-}
-
-static void pci_direct_free_coherent(struct device *hwdev, size_t size,
-				 void *vaddr, dma_addr_t dma_handle)
-{
-	free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static dma_addr_t pci_direct_map_single(struct device *hwdev, void *ptr,
-		size_t size, enum dma_data_direction direction)
-{
-	return virt_to_abs(ptr);
-}
-
-static void pci_direct_unmap_single(struct device *hwdev, dma_addr_t dma_addr,
-		size_t size, enum dma_data_direction direction)
-{
-}
-
-static int pci_direct_map_sg(struct device *hwdev, struct scatterlist *sg,
-		int nents, enum dma_data_direction direction)
-{
-	int i;
-
-	for (i = 0; i < nents; i++, sg++) {
-		sg->dma_address = page_to_phys(sg->page) + sg->offset;
-		sg->dma_length = sg->length;
-	}
-
-	return nents;
-}
-
-static void pci_direct_unmap_sg(struct device *hwdev, struct scatterlist *sg,
-		int nents, enum dma_data_direction direction)
-{
-}
-
-static int pci_direct_dma_supported(struct device *dev, u64 mask)
-{
-	return mask < 0x100000000ull;
-}
-
-static struct dma_mapping_ops pci_direct_ops = {
-	.alloc_coherent = pci_direct_alloc_coherent,
-	.free_coherent = pci_direct_free_coherent,
-	.map_single = pci_direct_map_single,
-	.unmap_single = pci_direct_unmap_single,
-	.map_sg = pci_direct_map_sg,
-	.unmap_sg = pci_direct_unmap_sg,
-	.dma_supported = pci_direct_dma_supported,
-};
-
-void __init pci_direct_iommu_init(void)
-{
-	pci_dma_ops = pci_direct_ops;
-}
Index: linux-cell/arch/powerpc/kernel/pci_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_iommu.c	2006-10-06 13:45:18.000000000 +1000
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
- *
- * Rewrite, cleanup, new allocation schemes:
- * Copyright (C) 2004 Olof Johansson, IBM Corporation
- *
- * Dynamic DMA mapping support, platform-independent parts.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/iommu.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/ppc-pci.h>
-
-/*
- * We can use ->sysdata directly and avoid the extra work in
- * pci_device_to_OF_node since ->sysdata will have been initialised
- * in the iommu init code for all devices.
- */
-#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata))
-
-static inline struct iommu_table *device_to_table(struct device *hwdev)
-{
-	struct pci_dev *pdev;
-
-	if (!hwdev) {
-		pdev = ppc64_isabridge_dev;
-		if (!pdev)
-			return NULL;
-	} else
-		pdev = to_pci_dev(hwdev);
-
-	return PCI_DN(PCI_GET_DN(pdev))->iommu_table;
-}
-
-
-static inline unsigned long device_to_mask(struct device *hwdev)
-{
-	struct pci_dev *pdev;
-
-	if (!hwdev) {
-		pdev = ppc64_isabridge_dev;
-		if (!pdev) /* This is the best guess we can do */
-			return 0xfffffffful;
-	} else
-		pdev = to_pci_dev(hwdev);
-
-	if (pdev->dma_mask)
-		return pdev->dma_mask;
-
-	/* Assume devices without mask can take 32 bit addresses */
-	return 0xfffffffful;
-}
-
-
-/* Allocates a contiguous real buffer and creates mappings over it.
- * Returns the virtual address of the buffer and sets dma_handle
- * to the dma address (mapping) of the first page.
- */
-static void *pci_iommu_alloc_coherent(struct device *hwdev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag)
-{
-	return iommu_alloc_coherent(device_to_table(hwdev), size, dma_handle,
-			device_to_mask(hwdev), flag,
-			pcibus_to_node(to_pci_dev(hwdev)->bus));
-}
-
-static void pci_iommu_free_coherent(struct device *hwdev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
-{
-	iommu_free_coherent(device_to_table(hwdev), size, vaddr, dma_handle);
-}
-
-/* Creates TCEs for a user provided buffer.  The user buffer must be 
- * contiguous real kernel storage (not vmalloc).  The address of the buffer
- * passed here is the kernel (virtual) address of the buffer.  The buffer
- * need not be page aligned, the dma_addr_t returned will point to the same
- * byte within the page as vaddr.
- */
-static dma_addr_t pci_iommu_map_single(struct device *hwdev, void *vaddr,
-		size_t size, enum dma_data_direction direction)
-{
-	return iommu_map_single(device_to_table(hwdev), vaddr, size,
-			        device_to_mask(hwdev), direction);
-}
-
-
-static void pci_iommu_unmap_single(struct device *hwdev, dma_addr_t dma_handle,
-		size_t size, enum dma_data_direction direction)
-{
-	iommu_unmap_single(device_to_table(hwdev), dma_handle, size, direction);
-}
-
-
-static int pci_iommu_map_sg(struct device *pdev, struct scatterlist *sglist,
-		int nelems, enum dma_data_direction direction)
-{
-	return iommu_map_sg(pdev, device_to_table(pdev), sglist,
-			nelems, device_to_mask(pdev), direction);
-}
-
-static void pci_iommu_unmap_sg(struct device *pdev, struct scatterlist *sglist,
-		int nelems, enum dma_data_direction direction)
-{
-	iommu_unmap_sg(device_to_table(pdev), sglist, nelems, direction);
-}
-
-/* We support DMA to/from any memory page via the iommu */
-static int pci_iommu_dma_supported(struct device *dev, u64 mask)
-{
-	struct iommu_table *tbl = device_to_table(dev);
-
-	if (!tbl || tbl->it_offset > mask) {
-		printk(KERN_INFO "Warning: IOMMU table offset too big for device mask\n");
-		if (tbl)
-			printk(KERN_INFO "mask: 0x%08lx, table offset: 0x%08lx\n",
-				mask, tbl->it_offset);
-		else
-			printk(KERN_INFO "mask: 0x%08lx, table unavailable\n",
-				mask);
-		return 0;
-	} else
-		return 1;
-}
-
-struct dma_mapping_ops pci_iommu_ops = {
-	.alloc_coherent = pci_iommu_alloc_coherent,
-	.free_coherent = pci_iommu_free_coherent,
-	.map_single = pci_iommu_map_single,
-	.unmap_single = pci_iommu_unmap_single,
-	.map_sg = pci_iommu_map_sg,
-	.unmap_sg = pci_iommu_unmap_sg,
-	.dma_supported = pci_iommu_dma_supported,
-};
-
-void pci_iommu_init(void)
-{
-	pci_dma_ops = pci_iommu_ops;
-}
Index: linux-cell/include/asm-powerpc/dma-mapping.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/dma-mapping.h	2006-10-06 13:45:32.000000000 +1000
+++ linux-cell/include/asm-powerpc/dma-mapping.h	2006-11-10 18:39:25.000000000 +1100
@@ -44,26 +44,148 @@ extern void __dma_sync_page(struct page 
 #endif /* ! CONFIG_NOT_COHERENT_CACHE */
 
 #ifdef CONFIG_PPC64
+/*
+ * DMA operations are abstracted for G5 vs. i/pSeries, PCI vs. VIO
+ */
+struct dma_mapping_ops {
+	void *		(*alloc_coherent)(struct device *dev, size_t size,
+				dma_addr_t *dma_handle, gfp_t flag);
+	void		(*free_coherent)(struct device *dev, size_t size,
+				void *vaddr, dma_addr_t dma_handle);
+	dma_addr_t	(*map_single)(struct device *dev, void *ptr,
+				size_t size, enum dma_data_direction direction);
+	void		(*unmap_single)(struct device *dev, dma_addr_t dma_addr,
+				size_t size, enum dma_data_direction direction);
+	int		(*map_sg)(struct device *dev, struct scatterlist *sg,
+				int nents, enum dma_data_direction direction);
+	void		(*unmap_sg)(struct device *dev, struct scatterlist *sg,
+				int nents, enum dma_data_direction direction);
+	int		(*dma_supported)(struct device *dev, u64 mask);
+	int		(*dac_dma_supported)(struct device *dev, u64 mask);
+	int		(*set_dma_mask)(struct device *dev, u64 dma_mask);
+};
+
+static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
+{
+	/* We don't handle the NULL dev case for ISA for now. We could
+	 * do it via an out of line call but it is not needed for now. The
+	 * only ISA DMA device we support is the floppy and we have a hack
+	 * in the floppy driver directly to get a device for us.
+	 */
+	if (unlikely(dev == NULL || dev->sysdata.dma_ops == NULL))
+		return NULL;
+	return dev->sysdata.dma_ops;
+}
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (unlikely(dma_ops == NULL))
+		return 0;
+	if (dma_ops->dma_supported == NULL)
+		return 1;
+	return dma_ops->dma_supported(dev, mask);
+}
+
+static inline int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	if (unlikely(dma_ops == NULL))
+		return -EIO;
+	if (dma_ops->set_dma_mask != NULL)
+		return dma_ops->set_dma_mask(dev, dma_mask);
+	if (!dev->dma_mask || !dma_supported(dev, *dev->dma_mask))
+		return -EIO;
+	*dev->dma_mask = dma_mask;
+	return 0;
+}
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+				     void *cpu_addr, dma_addr_t dma_handle)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+}
+
+static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+					size_t size,
+					enum dma_data_direction direction)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	return dma_ops->map_single(dev, cpu_addr, size, direction);
+}
+
+static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+				    size_t size,
+				    enum dma_data_direction direction)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	dma_ops->unmap_single(dev, dma_addr, size, direction);
+}
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+				      unsigned long offset, size_t size,
+				      enum dma_data_direction direction)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	return dma_ops->map_single(dev, page_address(page) + offset, size,
+			direction);
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+				  size_t size,
+				  enum dma_data_direction direction)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	dma_ops->unmap_single(dev, dma_address, size, direction);
+}
+
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+			     int nents, enum dma_data_direction direction)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	return dma_ops->map_sg(dev, sg, nents, direction);
+}
+
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+				int nhwentries,
+				enum dma_data_direction direction)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	dma_ops->unmap_sg(dev, sg, nhwentries, direction);
+}
 
-extern int dma_supported(struct device *dev, u64 mask);
-extern int dma_set_mask(struct device *dev, u64 dma_mask);
-extern void *dma_alloc_coherent(struct device *dev, size_t size,
-		dma_addr_t *dma_handle, gfp_t flag);
-extern void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-		dma_addr_t dma_handle);
-extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-		size_t size, enum dma_data_direction direction);
-extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-		size_t size, enum dma_data_direction direction);
-extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
-		unsigned long offset, size_t size,
-		enum dma_data_direction direction);
-extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-		size_t size, enum dma_data_direction direction);
-extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-		enum dma_data_direction direction);
-extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-		int nhwentries, enum dma_data_direction direction);
+
+/*
+ * Available generic sets of operations
+ */
+extern struct dma_mapping_ops dma_iommu_ops;
+extern struct dma_mapping_ops dma_direct_ops;
 
 #else /* CONFIG_PPC64 */
 
@@ -261,25 +383,5 @@ static inline void dma_cache_sync(void *
 	__dma_sync(vaddr, size, (int)direction);
 }
 
-/*
- * DMA operations are abstracted for G5 vs. i/pSeries, PCI vs. VIO
- */
-struct dma_mapping_ops {
-	void *		(*alloc_coherent)(struct device *dev, size_t size,
-				dma_addr_t *dma_handle, gfp_t flag);
-	void		(*free_coherent)(struct device *dev, size_t size,
-				void *vaddr, dma_addr_t dma_handle);
-	dma_addr_t	(*map_single)(struct device *dev, void *ptr,
-				size_t size, enum dma_data_direction direction);
-	void		(*unmap_single)(struct device *dev, dma_addr_t dma_addr,
-				size_t size, enum dma_data_direction direction);
-	int		(*map_sg)(struct device *dev, struct scatterlist *sg,
-				int nents, enum dma_data_direction direction);
-	void		(*unmap_sg)(struct device *dev, struct scatterlist *sg,
-				int nents, enum dma_data_direction direction);
-	int		(*dma_supported)(struct device *dev, u64 mask);
-	int		(*dac_dma_supported)(struct device *dev, u64 mask);
-};
-
 #endif /* __KERNEL__ */
 #endif	/* _ASM_DMA_MAPPING_H */
Index: linux-cell/include/asm-powerpc/iommu.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/iommu.h	2006-11-02 13:16:17.000000000 +1100
+++ linux-cell/include/asm-powerpc/iommu.h	2006-11-10 18:39:21.000000000 +1100
@@ -87,22 +87,22 @@ extern void iommu_free_table(struct devi
 extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
 					    int nid);
 
-extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
-		struct scatterlist *sglist, int nelems, unsigned long mask,
-		enum dma_data_direction direction);
+extern int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+			int nelems, unsigned long mask,
+			enum dma_data_direction direction);
 extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
-		int nelems, enum dma_data_direction direction);
+			   int nelems, enum dma_data_direction direction);
 
 extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
-		dma_addr_t *dma_handle, unsigned long mask,
-		gfp_t flag, int node);
+				  dma_addr_t *dma_handle, unsigned long mask,
+				  gfp_t flag, int node);
 extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
-		void *vaddr, dma_addr_t dma_handle);
+				void *vaddr, dma_addr_t dma_handle);
 extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
-		size_t size, unsigned long mask,
-		enum dma_data_direction direction);
+				   size_t size, unsigned long mask,
+				   enum dma_data_direction direction);
 extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
-		size_t size, enum dma_data_direction direction);
+			       size_t size, enum dma_data_direction direction);
 
 extern void iommu_init_early_pSeries(void);
 extern void iommu_init_early_iSeries(void);
Index: linux-cell/arch/powerpc/kernel/vio.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vio.c	2006-11-02 13:16:16.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/vio.c	2006-11-10 18:11:14.000000000 +1100
@@ -81,15 +81,15 @@ static struct iommu_table *vio_build_iom
 		struct iommu_table *tbl;
 		unsigned long offset, size;
 
-		dma_window = get_property(dev->dev.platform_data,
-				"ibm,my-dma-window", NULL);
+		dma_window = get_property(dev->dev.sysdata.of_node,
+					  "ibm,my-dma-window", NULL);
 		if (!dma_window)
 			return NULL;
 
 		tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
 
-		of_parse_dma_window(dev->dev.platform_data, dma_window,
-				&tbl->it_index, &offset, &size);
+		of_parse_dma_window(dev->dev.sysdata.of_node, dma_window,
+				    &tbl->it_index, &offset, &size);
 
 		/* TCE table size - measured in tce entries */
 		tbl->it_size = size >> IOMMU_PAGE_SHIFT;
@@ -117,7 +117,8 @@ static const struct vio_device_id *vio_m
 {
 	while (ids->type[0] != '\0') {
 		if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
-		    device_is_compatible(dev->dev.platform_data, ids->compat))
+		    device_is_compatible(dev->dev.sysdata.of_node,
+					 ids->compat))
 			return ids;
 		ids++;
 	}
@@ -198,9 +199,9 @@ EXPORT_SYMBOL(vio_unregister_driver);
 /* vio_dev refcount hit 0 */
 static void __devinit vio_dev_release(struct device *dev)
 {
-	if (dev->platform_data) {
-		/* XXX free TCE table */
-		of_node_put(dev->platform_data);
+	if (dev->sysdata.of_node) {
+		/* XXX should free TCE table */
+		of_node_put(dev->sysdata.of_node);
 	}
 	kfree(to_vio_dev(dev));
 }
@@ -210,7 +211,7 @@ static void __devinit vio_dev_release(st
  * @of_node:	The OF node for this device.
  *
  * Creates and initializes a vio_dev structure from the data in
- * of_node (dev.platform_data) and adds it to the list of virtual devices.
+ * of_node and adds it to the list of virtual devices.
  * Returns a pointer to the created vio_dev or NULL if node has
  * NULL device_type or compatible fields.
  */
@@ -240,8 +241,6 @@ struct vio_dev * __devinit vio_register_
 	if (viodev == NULL)
 		return NULL;
 
-	viodev->dev.platform_data = of_node_get(of_node);
-
 	viodev->irq = irq_of_parse_and_map(of_node, 0);
 
 	snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
@@ -254,7 +253,10 @@ struct vio_dev * __devinit vio_register_
 		if (unit_address != NULL)
 			viodev->unit_address = *unit_address;
 	}
-	viodev->iommu_table = vio_build_iommu_table(viodev);
+	viodev->dev.sysdata.of_node = of_node_get(of_node);
+	viodev->dev.sysdata.dma_ops = &dma_iommu_ops;
+	viodev->dev.sysdata.dma_data = vio_build_iommu_table(viodev);
+	viodev->dev.sysdata.numa_node = of_node_to_nid(of_node);
 
 	/* init generic 'struct device' fields: */
 	viodev->dev.parent = &vio_bus_device.dev;
@@ -285,10 +287,11 @@ static int __init vio_bus_init(void)
 #ifdef CONFIG_PPC_ISERIES
 	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
 		iommu_vio_init();
-		vio_bus_device.iommu_table = &vio_iommu_table;
+		vio_bus_device.dev.sysdata.dma_ops = &dma_iommu_ops;
+		vio_bus_device.dev.sysdata.dma_data = &vio_iommu_table;
 		iSeries_vio_dev = &vio_bus_device.dev;
 	}
-#endif
+#endif /* CONFIG_PPC_ISERIES */
 
 	err = bus_register(&vio_bus_type);
 	if (err) {
@@ -336,7 +339,7 @@ static ssize_t name_show(struct device *
 static ssize_t devspec_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct device_node *of_node = dev->platform_data;
+	struct device_node *of_node = dev->sysdata.of_node;
 
 	return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none");
 }
@@ -353,62 +356,6 @@ void __devinit vio_unregister_device(str
 }
 EXPORT_SYMBOL(vio_unregister_device);
 
-static dma_addr_t vio_map_single(struct device *dev, void *vaddr,
-			  size_t size, enum dma_data_direction direction)
-{
-	return iommu_map_single(to_vio_dev(dev)->iommu_table, vaddr, size,
-			~0ul, direction);
-}
-
-static void vio_unmap_single(struct device *dev, dma_addr_t dma_handle,
-		      size_t size, enum dma_data_direction direction)
-{
-	iommu_unmap_single(to_vio_dev(dev)->iommu_table, dma_handle, size,
-			direction);
-}
-
-static int vio_map_sg(struct device *dev, struct scatterlist *sglist,
-		int nelems, enum dma_data_direction direction)
-{
-	return iommu_map_sg(dev, to_vio_dev(dev)->iommu_table, sglist,
-			nelems, ~0ul, direction);
-}
-
-static void vio_unmap_sg(struct device *dev, struct scatterlist *sglist,
-		int nelems, enum dma_data_direction direction)
-{
-	iommu_unmap_sg(to_vio_dev(dev)->iommu_table, sglist, nelems, direction);
-}
-
-static void *vio_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag)
-{
-	return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size,
-			dma_handle, ~0ul, flag, -1);
-}
-
-static void vio_free_coherent(struct device *dev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
-{
-	iommu_free_coherent(to_vio_dev(dev)->iommu_table, size, vaddr,
-			dma_handle);
-}
-
-static int vio_dma_supported(struct device *dev, u64 mask)
-{
-	return 1;
-}
-
-struct dma_mapping_ops vio_dma_ops = {
-	.alloc_coherent = vio_alloc_coherent,
-	.free_coherent = vio_free_coherent,
-	.map_single = vio_map_single,
-	.unmap_single = vio_unmap_single,
-	.map_sg = vio_map_sg,
-	.unmap_sg = vio_unmap_sg,
-	.dma_supported = vio_dma_supported,
-};
-
 static int vio_bus_match(struct device *dev, struct device_driver *drv)
 {
 	const struct vio_dev *vio_dev = to_vio_dev(dev);
@@ -422,13 +369,14 @@ static int vio_hotplug(struct device *de
 			char *buffer, int buffer_size)
 {
 	const struct vio_dev *vio_dev = to_vio_dev(dev);
-	struct device_node *dn = dev->platform_data;
+	struct device_node *dn;
 	const char *cp;
 	int length;
 
 	if (!num_envp)
 		return -ENOMEM;
 
+	dn = dev->sysdata.of_node;
 	if (!dn)
 		return -ENODEV;
 	cp = get_property(dn, "compatible", &length);
@@ -465,7 +413,7 @@ struct bus_type vio_bus_type = {
 */
 const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
 {
-	return get_property(vdev->dev.platform_data, which, length);
+	return get_property(vdev->dev.sysdata.of_node, which, length);
 }
 EXPORT_SYMBOL(vio_get_attribute);
 
Index: linux-cell/include/asm-powerpc/vio.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/vio.h	2006-10-06 13:48:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/vio.h	2006-11-10 18:11:14.000000000 +1100
@@ -45,7 +45,6 @@ struct iommu_table;
  * The vio_dev structure is used to describe virtual I/O devices.
  */
 struct vio_dev {
-	struct iommu_table *iommu_table;     /* vio_map_* uses this */
 	const char *name;
 	const char *type;
 	uint32_t unit_address;
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c	2006-11-10 18:11:14.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_64.c	2006-11-10 18:39:33.000000000 +1100
@@ -63,7 +63,7 @@ void iSeries_pcibios_init(void);
 
 LIST_HEAD(hose_list);
 
-struct dma_mapping_ops pci_dma_ops;
+struct dma_mapping_ops *pci_dma_ops;
 EXPORT_SYMBOL(pci_dma_ops);
 
 int global_phb_number;		/* Global phb counter */
@@ -1213,15 +1213,35 @@ void __devinit pcibios_fixup_device_reso
 }
 EXPORT_SYMBOL(pcibios_fixup_device_resources);
 
+void __devinit pcibios_setup_new_device(struct pci_dev *dev)
+{
+	struct dev_sysdata *sd = &dev->dev.sysdata;
+
+	sd->of_node = pci_device_to_OF_node(dev);
+
+	DBG("PCI device %s OF node: %s\n", pci_name(dev),
+	    sd->of_node ? sd->of_node->full_name : "<none>");
+
+	sd->dma_ops = pci_dma_ops;
+#ifdef CONFIG_NUMA
+	sd->numa_node = pcibus_to_node(dev->bus);
+#else
+	sd->numa_node = -1;
+#endif
+	if (ppc_md.pci_dma_dev_setup)
+		ppc_md.pci_dma_dev_setup(dev);
+}
+EXPORT_SYMBOL(pcibios_setup_new_device);
 
 static void __devinit do_bus_setup(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
 
-	ppc_md.iommu_bus_setup(bus);
+	if (ppc_md.pci_dma_bus_setup)
+		ppc_md.pci_dma_bus_setup(bus);
 
 	list_for_each_entry(dev, &bus->devices, bus_list)
-		ppc_md.iommu_dev_setup(dev);
+		pcibios_setup_new_device(dev);
 
 	/* Read default IRQs and fixup if necessary */
 	list_for_each_entry(dev, &bus->devices, bus_list) {
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c	2006-10-27 15:39:09.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup_64.c	2006-11-10 18:39:28.000000000 +1100
@@ -33,6 +33,7 @@
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/bootmem.h>
+#include <linux/pci.h>
 #include <asm/io.h>
 #include <asm/kdump.h>
 #include <asm/prom.h>
Index: linux-cell/arch/powerpc/platforms/pseries/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/iommu.c	2006-11-02 13:16:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pseries/iommu.c	2006-11-10 18:11:14.000000000 +1100
@@ -309,7 +309,7 @@ static void iommu_table_setparms_lpar(st
 	tbl->it_size = size >> IOMMU_PAGE_SHIFT;
 }
 
-static void iommu_bus_setup_pSeries(struct pci_bus *bus)
+static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
 {
 	struct device_node *dn;
 	struct iommu_table *tbl;
@@ -318,10 +318,9 @@ static void iommu_bus_setup_pSeries(stru
 	struct pci_dn *pci;
 	int children;
 
-	DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self);
-
 	dn = pci_bus_to_OF_node(bus);
-	pci = PCI_DN(dn);
+
+	DBG("pci_dma_bus_setup_pSeries: setting up bus %s\n", dn->full_name);
 
 	if (bus->self) {
 		/* This is not a root bus, any setup will be done for the
@@ -329,6 +328,7 @@ static void iommu_bus_setup_pSeries(stru
 		 */
 		return;
 	}
+	pci = PCI_DN(dn);
 
 	/* Check if the ISA bus on the system is under
 	 * this PHB.
@@ -390,17 +390,17 @@ static void iommu_bus_setup_pSeries(stru
 }
 
 
-static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
+static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
 {
 	struct iommu_table *tbl;
 	struct device_node *dn, *pdn;
 	struct pci_dn *ppci;
 	const void *dma_window = NULL;
 
-	DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
-
 	dn = pci_bus_to_OF_node(bus);
 
+	DBG("pci_dma_bus_setup_pSeriesLP: setting up bus %s\n", dn->full_name);
+
 	/* Find nearest ibm,dma-window, walking up the device tree */
 	for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
 		dma_window = get_property(pdn, "ibm,dma-window", NULL);
@@ -409,11 +409,15 @@ static void iommu_bus_setup_pSeriesLP(st
 	}
 
 	if (dma_window == NULL) {
-		DBG("iommu_bus_setup_pSeriesLP: bus %s seems to have no ibm,dma-window property\n", dn->full_name);
+		DBG("  no ibm,dma-window property !\n");
 		return;
 	}
 
 	ppci = PCI_DN(pdn);
+
+	DBG("  parent is %s, iommu_table: 0x%p\n",
+	    pdn->full_name, ppci->iommu_table);
+
 	if (!ppci->iommu_table) {
 		/* Bussubno hasn't been copied yet.
 		 * Do it now because iommu_table_setparms_lpar needs it.
@@ -427,6 +431,7 @@ static void iommu_bus_setup_pSeriesLP(st
 		iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
 
 		ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
+		DBG("  created table: %p\n", ppci->iommu_table);
 	}
 
 	if (pdn != dn)
@@ -434,27 +439,27 @@ static void iommu_bus_setup_pSeriesLP(st
 }
 
 
-static void iommu_dev_setup_pSeries(struct pci_dev *dev)
+static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
 {
-	struct device_node *dn, *mydn;
+	struct device_node *dn;
 	struct iommu_table *tbl;
 
-	DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, pci_name(dev));
+	DBG("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev));
 
-	mydn = dn = pci_device_to_OF_node(dev);
+	dn = dev->dev.sysdata.of_node;
 
 	/* If we're the direct child of a root bus, then we need to allocate
 	 * an iommu table ourselves. The bus setup code should have setup
 	 * the window sizes already.
 	 */
 	if (!dev->bus->self) {
+		struct pci_controller *phb = PCI_DN(dn)->phb;
+
 		DBG(" --> first child, no bridge. Allocating iommu table.\n");
 		tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
-				   PCI_DN(dn)->phb->node);
-		iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl);
-		PCI_DN(dn)->iommu_table = iommu_init_table(tbl,
-						PCI_DN(dn)->phb->node);
-
+				   phb->node);
+		iommu_table_setparms(phb, dn, tbl);
+		dev->dev.sysdata.dma_data = iommu_init_table(tbl, phb->node);
 		return;
 	}
 
@@ -465,11 +470,11 @@ static void iommu_dev_setup_pSeries(stru
 	while (dn && PCI_DN(dn) && PCI_DN(dn)->iommu_table == NULL)
 		dn = dn->parent;
 
-	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));
-	}
+	if (dn && PCI_DN(dn))
+		dev->dev.sysdata.dma_data = PCI_DN(dn)->iommu_table;
+	else
+		printk(KERN_WARNING "iommu: Device %s has no iommu table\n",
+		       pci_name(dev));
 }
 
 static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
@@ -495,13 +500,15 @@ static struct notifier_block iommu_recon
 	.notifier_call = iommu_reconfig_notifier,
 };
 
-static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
+static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
 {
 	struct device_node *pdn, *dn;
 	struct iommu_table *tbl;
 	const void *dma_window = NULL;
 	struct pci_dn *pci;
 
+	DBG("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev));
+
 	/* dev setup for LPAR is a little tricky, since the device tree might
 	 * contain the dma-window properties per-device and not neccesarily
 	 * for the bus. So we need to search upwards in the tree until we
@@ -509,9 +516,7 @@ static void iommu_dev_setup_pSeriesLP(st
 	 * already allocated.
 	 */
 	dn = pci_device_to_OF_node(dev);
-
-	DBG("iommu_dev_setup_pSeriesLP, dev %p (%s) %s\n",
-	     dev, pci_name(dev), dn->full_name);
+	DBG("  node is %s\n", dn->full_name);
 
 	for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
 	     pdn = pdn->parent) {
@@ -520,16 +525,17 @@ static void iommu_dev_setup_pSeriesLP(st
 			break;
 	}
 
+	DBG("  parent is %s\n", pdn->full_name);
+
 	/* Check for parent == NULL so we don't try to setup the empty EADS
 	 * slots on POWER4 machines.
 	 */
 	if (dma_window == NULL || pdn->parent == NULL) {
-		DBG("No dma window for device, linking to parent\n");
-		PCI_DN(dn)->iommu_table = PCI_DN(pdn)->iommu_table;
+		DBG("  no dma window for device, linking to parent\n");
+		dev->dev.sysdata.dma_data = PCI_DN(pdn)->iommu_table;
 		return;
-	} else {
-		DBG("Found DMA window, allocating table\n");
 	}
+	DBG("  found DMA window, table: %p\n", pci->iommu_table);
 
 	pci = PCI_DN(pdn);
 	if (!pci->iommu_table) {
@@ -542,24 +548,20 @@ static void iommu_dev_setup_pSeriesLP(st
 		iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
 
 		pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
+		DBG("  created table: %p\n", pci->iommu_table);
 	}
 
-	if (pdn != dn)
-		PCI_DN(dn)->iommu_table = pci->iommu_table;
+	dev->dev.sysdata.dma_data = pci->iommu_table;
 }
 
-static void iommu_bus_setup_null(struct pci_bus *b) { }
-static void iommu_dev_setup_null(struct pci_dev *d) { }
-
 /* These are called very early. */
 void iommu_init_early_pSeries(void)
 {
 	if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) {
 		/* Direct I/O, IOMMU off */
-		ppc_md.iommu_dev_setup = iommu_dev_setup_null;
-		ppc_md.iommu_bus_setup = iommu_bus_setup_null;
-		pci_direct_iommu_init();
-
+		ppc_md.pci_dma_dev_setup = NULL;
+		ppc_md.pci_dma_bus_setup = NULL;
+		pci_dma_ops = &dma_direct_ops;
 		return;
 	}
 
@@ -572,19 +574,19 @@ void iommu_init_early_pSeries(void)
 			ppc_md.tce_free	 = tce_free_pSeriesLP;
 		}
 		ppc_md.tce_get   = tce_get_pSeriesLP;
-		ppc_md.iommu_bus_setup = iommu_bus_setup_pSeriesLP;
-		ppc_md.iommu_dev_setup = iommu_dev_setup_pSeriesLP;
+		ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP;
+		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP;
 	} else {
 		ppc_md.tce_build = tce_build_pSeries;
 		ppc_md.tce_free  = tce_free_pSeries;
 		ppc_md.tce_get   = tce_get_pseries;
-		ppc_md.iommu_bus_setup = iommu_bus_setup_pSeries;
-		ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
+		ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeries;
+		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeries;
 	}
 
 
 	pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
 
-	pci_iommu_init();
+	pci_dma_ops = &dma_iommu_ops;
 }
 
Index: linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pci_dlpar.c	2006-09-08 17:17:11.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c	2006-11-10 18:39:29.000000000 +1100
@@ -93,8 +93,8 @@ pcibios_fixup_new_pci_devices(struct pci
 		if (list_empty(&dev->global_list)) {
 			int i;
 
-			/* Need to setup IOMMU tables */
-			ppc_md.iommu_dev_setup(dev);
+			/* Fill device sysdata and setup iommu table */
+			pcibios_setup_new_device(dev);
 
 			if(fix_bus)
 				pcibios_fixup_device_resources(dev, bus);
Index: linux-cell/arch/powerpc/sysdev/dart_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/dart_iommu.c	2006-11-02 13:16:16.000000000 +1100
+++ linux-cell/arch/powerpc/sysdev/dart_iommu.c	2006-11-10 18:39:21.000000000 +1100
@@ -289,24 +289,15 @@ static void iommu_table_dart_setup(void)
 	set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
 }
 
-static void iommu_dev_setup_dart(struct pci_dev *dev)
+static void pci_dma_dev_setup_dart(struct pci_dev *dev)
 {
-	struct device_node *dn;
-
 	/* We only have one iommu table on the mac for now, which makes
 	 * things simple. Setup all PCI devices to point to this table
-	 *
-	 * We must use pci_device_to_OF_node() to make sure that
-	 * we get the real "final" pointer to the device in the
-	 * pci_dev sysdata and not the temporary PHB one
 	 */
-	dn = pci_device_to_OF_node(dev);
-
-	if (dn)
-		PCI_DN(dn)->iommu_table = &iommu_table_dart;
+	dev->dev.sysdata.dma_data = &iommu_table_dart;
 }
 
-static void iommu_bus_setup_dart(struct pci_bus *bus)
+static void pci_dma_bus_setup_dart(struct pci_bus *bus)
 {
 	struct device_node *dn;
 
@@ -321,9 +312,6 @@ static void iommu_bus_setup_dart(struct 
 		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_dart(void)
 {
 	struct device_node *dn;
@@ -344,22 +332,21 @@ void iommu_init_early_dart(void)
 
 	/* Initialize the DART HW */
 	if (dart_init(dn) == 0) {
-		ppc_md.iommu_dev_setup = iommu_dev_setup_dart;
-		ppc_md.iommu_bus_setup = iommu_bus_setup_dart;
+		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart;
+		ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
 
 		/* Setup pci_dma ops */
-		pci_iommu_init();
-
+		pci_dma_ops = &dma_iommu_ops;
 		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;
+	ppc_md.pci_dma_dev_setup = NULL;
+	ppc_md.pci_dma_bus_setup = NULL;
 
 	/* Setup pci_dma ops */
-	pci_direct_iommu_init();
+	pci_dma_ops = &dma_direct_ops;
 }
 
 
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h	2006-11-10 18:11:14.000000000 +1100
+++ linux-cell/include/asm-powerpc/machdep.h	2006-11-10 18:39:29.000000000 +1100
@@ -84,8 +84,8 @@ struct machdep_calls {
 	unsigned long	(*tce_get)(struct iommu_table *tbl,
 				    long index);
 	void		(*tce_flush)(struct iommu_table *tbl);
-	void		(*iommu_dev_setup)(struct pci_dev *dev);
-	void		(*iommu_bus_setup)(struct pci_bus *bus);
+	void		(*pci_dma_dev_setup)(struct pci_dev *dev);
+	void		(*pci_dma_bus_setup)(struct pci_bus *bus);
 #endif /* CONFIG_PPC64 */
 
 	int		(*probe)(void);
Index: linux-cell/include/asm-powerpc/pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci.h	2006-10-06 13:48:23.000000000 +1000
+++ linux-cell/include/asm-powerpc/pci.h	2006-11-10 18:11:14.000000000 +1100
@@ -76,15 +76,15 @@ static inline int pcibios_prep_mwi(struc
 	return 0;
 }
 
-extern struct dma_mapping_ops pci_dma_ops;
+extern struct dma_mapping_ops *pci_dma_ops;
 
 /* For DAC DMA, we currently don't support it by default, but
  * we let 64-bit platforms override this.
  */
 static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
 {
-	if (pci_dma_ops.dac_dma_supported)
-		return pci_dma_ops.dac_dma_supported(&hwdev->dev, mask);
+	if (pci_dma_ops && pci_dma_ops->dac_dma_supported)
+		return pci_dma_ops->dac_dma_supported(&hwdev->dev, mask);
 	return 0;
 }
 
@@ -216,6 +216,8 @@ extern int remap_bus_range(struct pci_bu
 extern void pcibios_fixup_device_resources(struct pci_dev *dev,
 			struct pci_bus *bus);
 
+extern void pcibios_setup_new_device(struct pci_dev *dev);
+
 extern void pcibios_claim_one_bus(struct pci_bus *b);
 
 extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile	2006-11-10 18:11:14.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/Makefile	2006-11-10 18:39:28.000000000 +1100
@@ -63,8 +63,7 @@ obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_s
 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
+pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o iomap.o
 pci32-$(CONFIG_PPC32)		:= pci_32.o
 obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32-y)
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
Index: linux-cell/arch/powerpc/kernel/ibmebus.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ibmebus.c	2006-10-11 11:48:41.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ibmebus.c	2006-11-10 18:11:14.000000000 +1100
@@ -112,7 +112,7 @@ static int ibmebus_dma_supported(struct 
 	return 1;
 }
 
-struct dma_mapping_ops ibmebus_dma_ops = {
+static struct dma_mapping_ops ibmebus_dma_ops = {
 	.alloc_coherent = ibmebus_alloc_coherent,
 	.free_coherent  = ibmebus_free_coherent,
 	.map_single     = ibmebus_map_single,
@@ -176,6 +176,10 @@ static struct ibmebus_dev* __devinit ibm
 	dev->ofdev.dev.bus     = &ibmebus_bus_type;
 	dev->ofdev.dev.release = ibmebus_dev_release;
 
+	dev->ofdev.dev.sysdata.of_node = dev->ofdev.node;
+	dev->ofdev.dev.sysdata.dma_ops = &ibmebus_dma_ops;
+	dev->ofdev.dev.sysdata.numa_node = of_node_to_nid(dev->ofdev.node);
+
 	/* An ibmebusdev is based on a of_device. We have to change the
 	 * bus type to use our own DMA mapping operations. 
 	 */       
Index: linux-cell/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.c	2006-10-09 12:03:33.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/iommu.c	2006-11-10 18:39:28.000000000 +1100
@@ -255,9 +255,6 @@ static void enable_mapping(void __iomem 
 	set_iost_origin(mmio_base);
 }
 
-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;
@@ -306,12 +303,15 @@ static void cell_do_map_iommu(struct cel
 	}
 }
 
-static void iommu_devnode_setup(struct device_node *d)
+static void pci_dma_cell_bus_setup(struct pci_bus *b)
 {
 	const unsigned int *ioid;
 	unsigned long map_start, map_size, token;
 	const unsigned long *dma_window;
 	struct cell_iommu *iommu;
+	struct device_node *d;
+
+	d = pci_bus_to_OF_node(b);
 
 	ioid = get_property(d, "ioid", NULL);
 	if (!ioid)
@@ -330,12 +330,6 @@ static void iommu_devnode_setup(struct d
 	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)
 {
@@ -499,16 +493,13 @@ void cell_init_iommu(void)
 
 		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;
+			ppc_md.pci_dma_bus_setup = pci_dma_cell_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 = cell_iommu_ops;
+	pci_dma_ops = &cell_iommu_ops;
 }
Index: linux-cell/include/asm-powerpc/ibmebus.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ibmebus.h	2006-10-11 11:48:41.000000000 +1000
+++ linux-cell/include/asm-powerpc/ibmebus.h	2006-11-10 18:11:14.000000000 +1100
@@ -44,7 +44,6 @@
 #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 {	
Index: linux-cell/include/asm-powerpc/of_device.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/of_device.h	2006-11-10 18:11:14.000000000 +1100
+++ linux-cell/include/asm-powerpc/of_device.h	2006-11-10 18:11:14.000000000 +1100
@@ -14,7 +14,7 @@
  */
 struct of_device
 {
-	struct device_node	*node;		/* OF device node */
+	struct device_node	*node;		/* to be obsoleted */
 	u64			dma_mask;	/* DMA mask */
 	struct device		dev;		/* Generic device interface */
 };
Index: linux-cell/arch/powerpc/kernel/of_platform.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/of_platform.c	2006-11-10 18:11:14.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/of_platform.c	2006-11-10 18:39:29.000000000 +1100
@@ -22,7 +22,7 @@
 #include <asm/dcr.h>
 #include <asm/of_device.h>
 #include <asm/of_platform.h>
-
+#include <asm/topology.h>
 
 /*
  * The list of OF IDs below is used for matching bus types in the
@@ -221,6 +221,13 @@ struct of_device* of_platform_device_cre
 	dev->dev.parent = parent;
 	dev->dev.bus = &of_platform_bus_type;
 	dev->dev.release = of_release_dev;
+	dev->dev.sysdata.of_node = np;
+	dev->dev.sysdata.numa_node = of_node_to_nid(np);
+
+	/* We do not fill the DMA ops for platform devices by default.
+	 * This is currently the responsibility of the platform code
+	 * to do such, possibly using a device notifier
+	 */
 
 	if (bus_id)
 		strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
Index: linux-cell/arch/powerpc/platforms/iseries/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/iommu.c	2006-11-02 13:16:16.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/iseries/iommu.c	2006-11-10 18:11:14.000000000 +1100
@@ -27,6 +27,7 @@
 #include <linux/types.h>
 #include <linux/dma-mapping.h>
 #include <linux/list.h>
+#include <linux/pci.h>
 
 #include <asm/iommu.h>
 #include <asm/tce.h>
@@ -168,7 +169,7 @@ static struct iommu_table *iommu_table_f
 }
 
 
-void iommu_devnode_init_iSeries(struct device_node *dn)
+void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn)
 {
 	struct iommu_table *tbl;
 	struct pci_dn *pdn = PCI_DN(dn);
@@ -186,19 +187,14 @@ void iommu_devnode_init_iSeries(struct d
 		pdn->iommu_table = iommu_init_table(tbl, -1);
 	else
 		kfree(tbl);
+	pdev->dev.sysdata.dma_data = pdn->iommu_table;
 }
 #endif
 
-static void iommu_dev_setup_iSeries(struct pci_dev *dev) { }
-static void iommu_bus_setup_iSeries(struct pci_bus *bus) { }
-
 void iommu_init_early_iSeries(void)
 {
 	ppc_md.tce_build = tce_build_iSeries;
 	ppc_md.tce_free  = tce_free_iSeries;
 
-	ppc_md.iommu_dev_setup = iommu_dev_setup_iSeries;
-	ppc_md.iommu_bus_setup = iommu_bus_setup_iSeries;
-
-	pci_iommu_init();
+	pci_dma_ops = &dma_iommu_ops;
 }
Index: linux-cell/arch/powerpc/platforms/iseries/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/pci.c	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/iseries/pci.c	2006-11-10 18:39:28.000000000 +1100
@@ -253,7 +253,7 @@ void __init iSeries_pci_final_fixup(void
 			PCI_DN(node)->pcidev = pdev;
 			allocate_device_bars(pdev);
 			iSeries_Device_Information(pdev, DeviceCount);
-			iommu_devnode_init_iSeries(node);
+			iommu_devnode_init_iSeries(pdev, node);
 		} else
 			printk("PCI: Device Tree not found for 0x%016lX\n",
 					(unsigned long)pdev);
Index: linux-cell/include/asm-powerpc/iseries/iommu.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/iseries/iommu.h	2006-10-06 13:45:32.000000000 +1000
+++ linux-cell/include/asm-powerpc/iseries/iommu.h	2006-11-10 18:11:14.000000000 +1100
@@ -21,11 +21,13 @@
  * Boston, MA  02111-1307  USA
  */
 
+struct pci_dev;
 struct device_node;
 struct iommu_table;
 
 /* Creates table for an individual device node */
-extern void iommu_devnode_init_iSeries(struct device_node *dn);
+extern void iommu_devnode_init_iSeries(struct pci_dev *pdev,
+				       struct device_node *dn);
 
 /* Get table parameters from HV */
 extern void iommu_table_getparms_iSeries(unsigned long busno,
Index: linux-cell/include/asm-powerpc/device.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/device.h	2006-11-10 18:11:14.000000000 +1100
+++ linux-cell/include/asm-powerpc/device.h	2006-11-10 18:11:14.000000000 +1100
@@ -8,7 +8,19 @@
 #ifndef _ASM_DEVICE_H
 #define _ASM_DEVICE_H
 
+struct dma_mapping_ops;
+struct device_node;
+
 struct dev_sysdata {
+	/* Optional pointer to an OF device node */
+	struct device_node	*of_node;
+
+	/* DMA operations on that device */
+	struct dma_mapping_ops	*dma_ops;
+	void			*dma_data;
+
+	/* NUMA node if applicable */
+	int			numa_node;
 };
 
 #endif /* _ASM_DEVICE_H */

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

* [PATCH 17/32] powerpc: Add DMA ops support for of_plaform_device to Cell
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (15 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 15/32] powerpc: Hook of_platform_bus_probe with cell Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:44 ` [PATCH 18/32] powerpc: Resolve the parent address of a PCI bus range Benjamin Herrenschmidt
                   ` (14 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

This patch adds a bus device notifier to the of_platform bus type on
cell to setup the DMA operations for of_platform_devices. We currently
use the PCI operations as Cell use a special version of them that
happens to be suitable for our needs.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/platforms/cell/setup.c |   37 +++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)

Index: linux-cell/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/setup.c	2006-11-10 16:24:37.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/setup.c	2006-11-10 16:44:51.000000000 +1100
@@ -30,6 +30,7 @@
 #include <linux/console.h>
 #include <linux/mutex.h>
 #include <linux/memory_hotplug.h>
+#include <linux/notifier.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -82,10 +83,41 @@ static void cell_progress(char *s, unsig
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
+static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action,
+			      void *data)
+{
+	struct device *dev = data;
+
+	if (action != BUS_NOTIFY_ADD_DEVICE)
+		return 0;
+
+	/* For now, we just use the PCI DMA ops for everything, though
+	 * we'll need something better when we have a real iommu
+	 * implementation.
+	 */
+	dev->sysdata.dma_ops = pci_dma_ops;
+
+	return 0;
+}
+
+static struct notifier_block cell_of_bus_notifier = {
+	.notifier_call = cell_of_bus_notify
+};
+
+
 static int __init cell_publish_devices(void)
 {
-	if (machine_is(cell))
-		of_platform_bus_probe(NULL, NULL, NULL);
+	if (!machine_is(cell))
+		return 0;
+
+	/* Register callbacks on OF platform device addition/removal
+	 * to handle linking them to the right DMA operations
+	 */
+	register_bus_notifier(&of_platform_bus_type, &cell_of_bus_notifier);
+
+	/* Publish OF platform devices for southbridge IOs */
+	of_platform_bus_probe(NULL, NULL, NULL);
+
 	return 0;
 }
 device_initcall(cell_publish_devices);
@@ -154,7 +186,6 @@ static void __init cell_setup_arch(void)
 #ifdef CONFIG_SMP
 	smp_init_cell();
 #endif
-
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_jiffy = 50000000;
 

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

* [PATCH 18/32] powerpc: Resolve the parent address of a PCI bus range
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (16 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 17/32] powerpc: Add DMA ops support for of_plaform_device to Cell Benjamin Herrenschmidt
@ 2006-11-10  7:44 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 19/32] powerpc: Resolve the BUID fir RTAS PCI config space accesses Benjamin Herrenschmidt
                   ` (13 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:44 UTC (permalink / raw)
  To: linuxppc-dev

When parsing the OF "ranges" properties of PCI host busses to determine
the mapping of a PCI bus, we need to translate the "parent" address using
the prom_parse.c routines in order to obtain a CPU physical address.

This wasn't necessary while PCI busses were always at the root of the
device-tree but this is no longer the case on Cell where they can be
anywhere in the tree.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/pci_64.c |    6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c	2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_64.c	2006-11-10 16:40:42.000000000 +1100
@@ -975,11 +975,7 @@ void __devinit pci_process_bridge_OF_ran
 		res = NULL;
 		pci_space = ranges[0];
 		pci_addr = ((unsigned long)ranges[1] << 32) | ranges[2];
-
-		cpu_phys_addr = ranges[3];
-		if (na >= 2)
-			cpu_phys_addr = (cpu_phys_addr << 32) | ranges[4];
-
+		cpu_phys_addr = of_translate_address(dev, &ranges[3]);
 		size = ((unsigned long)ranges[na+3] << 32) | ranges[na+4];
 		ranges += np;
 		if (size == 0)

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

* [PATCH 19/32] powerpc: Resolve the BUID fir RTAS PCI config space accesses
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (17 preceding siblings ...)
  2006-11-10  7:44 ` [PATCH 18/32] powerpc: Resolve the parent address of a PCI bus range Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 20/32] powerpc: Add "parent" struct device for PCI host bridges Benjamin Herrenschmidt
                   ` (12 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

The BUID is the first entry of a PCI host bridge "reg" property.

Now that PCI busses can be anywhere in the device-tree, we need to
fully translate the value there to a CPU physical address before
we can use it with RTAS.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/rtas_pci.c |   27 ++++-----------------------
 1 file changed, 4 insertions(+), 23 deletions(-)

Index: linux-cell/arch/powerpc/kernel/rtas_pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/rtas_pci.c	2006-10-26 17:32:35.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/rtas_pci.c	2006-10-26 17:34:21.000000000 +1000
@@ -231,32 +231,13 @@ void __init init_pci_config_tokens (void
 
 unsigned long __devinit get_phb_buid (struct device_node *phb)
 {
-	int addr_cells;
-	const unsigned int *buid_vals;
-	unsigned int len;
-	unsigned long buid;
-
-	if (ibm_read_pci_config == -1) return 0;
+	struct resource r;
 
-	/* PHB's will always be children of the root node,
-	 * or so it is promised by the current firmware. */
-	if (phb->parent == NULL)
-		return 0;
-	if (phb->parent->parent)
+	if (ibm_read_pci_config == -1)
 		return 0;
-
-	buid_vals = get_property(phb, "reg", &len);
-	if (buid_vals == NULL)
+	if (of_address_to_resource(phb, 0, &r))
 		return 0;
-
-	addr_cells = prom_n_addr_cells(phb);
-	if (addr_cells == 1) {
-		buid = (unsigned long) buid_vals[0];
-	} else {
-		buid = (((unsigned long)buid_vals[0]) << 32UL) |
-			(((unsigned long)buid_vals[1]) & 0xffffffff);
-	}
-	return buid;
+	return r.start;
 }
 
 static int phb_set_bus_ranges(struct device_node *dev,

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

* [PATCH 20/32] powerpc: Add "parent" struct device for PCI host bridges
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (18 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 19/32] powerpc: Resolve the BUID fir RTAS PCI config space accesses Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 21/32] powerpc: Generic OF platform driver " Benjamin Herrenschmidt
                   ` (11 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

Add a "parent" struct device to our PCI host bridge data structure so that
PCI can be rooted off another device in sysfs.

Note that arch/ppc doesn't use it, only arch/powerpc, though it's available
for both 32 and 64 bits.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> 

 arch/powerpc/kernel/pci_32.c     |    5 ++++-
 arch/powerpc/kernel/pci_64.c     |    2 +-
 include/asm-powerpc/pci-bridge.h |    1 +
 include/asm-ppc/pci-bridge.h     |    1 +
 4 files changed, 7 insertions(+), 2 deletions(-)

Index: linux-cell/arch/powerpc/kernel/pci_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_32.c	2006-11-10 16:24:32.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_32.c	2006-11-10 16:40:49.000000000 +1100
@@ -1269,7 +1269,10 @@ pcibios_init(void)
 		if (pci_assign_all_buses)
 			hose->first_busno = next_busno;
 		hose->last_busno = 0xff;
-		bus = pci_scan_bus(hose->first_busno, hose->ops, hose);
+		bus = pci_scan_bus_parented(hose->parent, hose->first_busno,
+					    hose->ops, hose);
+		if (bus)
+			pci_bus_add_devices(bus);
 		hose->last_busno = bus->subordinate;
 		if (pci_assign_all_buses || next_busno <= hose->last_busno)
 			next_busno = hose->last_busno + pcibios_assign_bus_offset;
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c	2006-11-10 16:40:42.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_64.c	2006-11-10 16:40:49.000000000 +1100
@@ -517,7 +517,7 @@ void __devinit scan_phb(struct pci_contr
 
 	DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
 
-	bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node);
+	bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node);
 	if (bus == NULL) {
 		printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
 		       hose->global_number);
Index: linux-cell/include/asm-powerpc/pci-bridge.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci-bridge.h	2006-10-09 12:03:34.000000000 +1000
+++ linux-cell/include/asm-powerpc/pci-bridge.h	2006-11-10 16:40:49.000000000 +1100
@@ -25,6 +25,7 @@ struct pci_controller {
 	int node;
 	void *arch_data;
 	struct list_head list_node;
+	struct device *parent;
 
 	int first_busno;
 	int last_busno;
Index: linux-cell/include/asm-ppc/pci-bridge.h
===================================================================
--- linux-cell.orig/include/asm-ppc/pci-bridge.h	2006-01-14 14:43:33.000000000 +1100
+++ linux-cell/include/asm-ppc/pci-bridge.h	2006-11-10 16:40:49.000000000 +1100
@@ -43,6 +43,7 @@ struct pci_controller {
 	struct pci_controller *next;
         struct pci_bus *bus;
 	void *arch_data;
+	struct device *parent;
 
 	int first_busno;
 	int last_busno;

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

* [PATCH 21/32] powerpc: Generic OF platform driver for PCI host bridges.
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (19 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 20/32] powerpc: Add "parent" struct device for PCI host bridges Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 22/32] powerpc: Cell fixup DMA offset for new southbridge Benjamin Herrenschmidt
                   ` (10 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

When enabled in Kconfig, it will pick up any of_platform_device
matching it's match list (currently type "pci", "pcix", "pcie",
or "ht" and setup a PHB for it.

Platform must provide a ppc_md.pci_setup_phb() for it to work
(for doing the necessary initialisations specific to a given PHB
like setting up the config space ops).

It's currently only available on 64 bits as the 32 bits PCI code
can't quite cope with it in it's current form. I will fix that
later.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/Kconfig                       |    6 +
 arch/powerpc/kernel/of_platform.c          |  103 +++++++++++++++++++++++++++++
 arch/powerpc/kernel/pci_64.c               |    9 ++
 arch/powerpc/kernel/rtas_pci.c             |    7 +
 arch/powerpc/platforms/cell/setup.c        |    1 
 arch/powerpc/platforms/pseries/pci_dlpar.c |    2 
 include/asm-powerpc/machdep.h              |    4 +
 include/asm-powerpc/ppc-pci.h              |   12 +--
 8 files changed, 134 insertions(+), 10 deletions(-)

Index: linux-cell/arch/powerpc/kernel/of_platform.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/of_platform.c	2006-11-10 16:44:22.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/of_platform.c	2006-11-10 16:45:04.000000000 +1100
@@ -1,6 +1,7 @@
 /*
  *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
  *			 <benh@kernel.crashing.org>
+ *    and		 Arnd Bergmann, IBM Corp.
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -17,12 +18,15 @@
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
+#include <linux/pci.h>
 
 #include <asm/errno.h>
 #include <asm/dcr.h>
 #include <asm/of_device.h>
 #include <asm/of_platform.h>
 #include <asm/topology.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
 
 /*
  * The list of OF IDs below is used for matching bus types in the
@@ -377,3 +381,102 @@ struct of_device *of_find_device_by_phan
 	return NULL;
 }
 EXPORT_SYMBOL(of_find_device_by_phandle);
+
+
+#ifdef CONFIG_PPC_OF_PLATFORM_PCI
+
+/* The probing of PCI controllers from of_platform is currently
+ * 64 bits only, mostly due to gratuitous differences between
+ * the 32 and 64 bits PCI code on PowerPC and the 32 bits one
+ * lacking some bits needed here.
+ */
+
+static int __devinit of_pci_phb_probe(struct of_device *dev,
+				      const struct of_device_id *match)
+{
+	struct pci_controller *phb;
+
+	/* Check if we can do that ... */
+	if (ppc_md.pci_setup_phb == NULL)
+		return -ENODEV;
+
+	printk(KERN_INFO "Setting up PCI bus %s\n", dev->node->full_name);
+
+	/* Alloc and setup PHB data structure */
+	phb = pcibios_alloc_controller(dev->node);
+	if (!phb)
+		return -ENODEV;
+
+	/* Setup parent in sysfs */
+	phb->parent = &dev->dev;
+
+	/* Setup the PHB using arch provided callback */
+	if (ppc_md.pci_setup_phb(phb)) {
+		pcibios_free_controller(phb);
+		return -ENODEV;
+	}
+
+	/* Process "ranges" property */
+	pci_process_bridge_OF_ranges(phb, dev->node, 0);
+
+	/* Setup IO space.
+	 * This will not work properly for ISA IOs, something needs to be done
+	 * about it if we ever generalize that way of probing PCI brigdes
+	 */
+	pci_setup_phb_io_dynamic(phb, 0);
+
+	/* Init pci_dn data structures */
+	pci_devs_phb_init_dynamic(phb);
+
+	/* Register devices with EEH */
+#ifdef CONFIG_EEH
+	if (dev->node->child)
+		eeh_add_device_tree_early(dev->node);
+#endif /* CONFIG_EEH */
+
+	/* Scan the bus */
+	scan_phb(phb);
+
+	/* Claim resources. This might need some rework as well depending
+	 * wether we are doing probe-only or not, like assigning unassigned
+	 * resources etc...
+	 */
+	pcibios_claim_one_bus(phb->bus);
+
+	/* Finish EEH setup */
+#ifdef CONFIG_EEH
+	eeh_add_device_tree_late(phb->bus);
+#endif
+
+	/* Add probed PCI devices to the device model */
+	pci_bus_add_devices(phb->bus);
+
+	return 0;
+}
+
+static struct of_device_id of_pci_phb_ids[] = {
+	{ .type = "pci", },
+	{ .type = "pcix", },
+	{ .type = "pcie", },
+	{ .type = "pciex", },
+	{ .type = "ht", },
+	{}
+};
+
+static struct of_platform_driver of_pci_phb_driver = {
+       .name = "of-pci",
+       .match_table = of_pci_phb_ids,
+       .probe = of_pci_phb_probe,
+       .driver = {
+	       .multithread_probe = 1,
+       },
+};
+
+static __init int of_pci_phb_init(void)
+{
+	return of_register_platform_driver(&of_pci_phb_driver);
+}
+
+device_initcall(of_pci_phb_init);
+
+#endif /* CONFIG_PPC_OF_PLATFORM_PCI */
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c	2006-11-10 16:45:01.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_64.c	2006-11-10 16:45:04.000000000 +1100
@@ -212,6 +212,10 @@ struct pci_controller * pcibios_alloc_co
 
 void pcibios_free_controller(struct pci_controller *phb)
 {
+	spin_lock(&hose_spinlock);
+	list_del(&phb->list_node);
+	spin_unlock(&hose_spinlock);
+
 	if (phb->is_dynamic)
 		kfree(phb);
 }
@@ -1250,6 +1254,11 @@ static void __devinit do_bus_setup(struc
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
 	struct pci_dev *dev = bus->self;
+	struct device_node *np;
+
+	np = pci_bus_to_OF_node(bus);
+
+	DBG("pcibios_fixup_bus(%s)\n", np ? np->full_name : "<???>");
 
 	if (dev && pci_probe_only &&
 	    (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h	2006-11-10 16:44:22.000000000 +1100
+++ linux-cell/include/asm-powerpc/machdep.h	2006-11-10 16:45:04.000000000 +1100
@@ -26,6 +26,7 @@ struct device_node;
 struct iommu_table;
 struct rtc_time;
 struct file;
+struct pci_controller;
 #ifdef CONFIG_KEXEC
 struct kimage;
 #endif
@@ -107,6 +108,9 @@ struct machdep_calls {
 	int		(*pci_probe_mode)(struct pci_bus *);
 	void		(*pci_irq_fixup)(struct pci_dev *dev);
 
+	/* To setup PHBs when using automatic OF platform driver for PCI */
+	int		(*pci_setup_phb)(struct pci_controller *host);
+
 	void		(*restart)(char *cmd);
 	void		(*power_off)(void);
 	void		(*halt)(void);
Index: linux-cell/arch/powerpc/kernel/rtas_pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/rtas_pci.c	2006-11-10 16:45:00.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/rtas_pci.c	2006-11-10 16:45:04.000000000 +1100
@@ -257,8 +257,10 @@ static int phb_set_bus_ranges(struct dev
 	return 0;
 }
 
-int __devinit setup_phb(struct device_node *dev, struct pci_controller *phb)
+int __devinit rtas_setup_phb(struct pci_controller *phb)
 {
+	struct device_node *dev = phb->arch_data;
+
 	if (is_python(dev))
 		python_countermeasures(dev);
 
@@ -290,7 +292,7 @@ unsigned long __init find_and_init_phbs(
 		phb = pcibios_alloc_controller(node);
 		if (!phb)
 			continue;
-		setup_phb(node, phb);
+		rtas_setup_phb(phb);
 		pci_process_bridge_OF_ranges(phb, node, 0);
 		pci_setup_phb_io(phb, index == 0);
 		index++;
@@ -362,7 +364,6 @@ int pcibios_remove_root_bus(struct pci_c
 		}
 	}
 
-	list_del(&phb->list_node);
 	pcibios_free_controller(phb);
 
 	return 0;
Index: linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pci_dlpar.c	2006-11-10 16:44:22.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c	2006-11-10 16:45:04.000000000 +1100
@@ -195,7 +195,7 @@ struct pci_controller * __devinit init_p
 	phb = pcibios_alloc_controller(dn);
 	if (!phb)
 		return NULL;
-	setup_phb(dn, phb);
+	rtas_setup_phb(phb);
 	pci_process_bridge_OF_ranges(phb, dn, 0);
 
 	pci_setup_phb_io_dynamic(phb, primary);
Index: linux-cell/include/asm-powerpc/ppc-pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ppc-pci.h	2006-11-10 16:44:22.000000000 +1100
+++ linux-cell/include/asm-powerpc/ppc-pci.h	2006-11-10 16:45:04.000000000 +1100
@@ -36,14 +36,14 @@ typedef void *(*traverse_func)(struct de
 void *traverse_pci_devices(struct device_node *start, traverse_func pre,
 		void *data);
 
-void pci_devs_phb_init(void);
-void pci_devs_phb_init_dynamic(struct pci_controller *phb);
-int setup_phb(struct device_node *dev, struct pci_controller *phb);
-void __devinit scan_phb(struct pci_controller *hose);
+extern void pci_devs_phb_init(void);
+extern void pci_devs_phb_init_dynamic(struct pci_controller *phb);
+extern void scan_phb(struct pci_controller *hose);
 
 /* From rtas_pci.h */
-void init_pci_config_tokens (void);
-unsigned long get_phb_buid (struct device_node *);
+extern void init_pci_config_tokens (void);
+extern unsigned long get_phb_buid (struct device_node *);
+extern int rtas_setup_phb(struct pci_controller *phb);
 
 /* From pSeries_pci.h */
 extern void pSeries_final_fixup(void);
Index: linux-cell/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/setup.c	2006-11-10 16:44:51.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/setup.c	2006-11-10 16:45:04.000000000 +1100
@@ -256,6 +256,7 @@ define_machine(cell) {
 	.check_legacy_ioport	= cell_check_legacy_ioport,
 	.progress		= cell_progress,
 	.init_IRQ       	= cell_init_irq,
+	.pci_setup_phb		= rtas_setup_phb,
 #ifdef CONFIG_KEXEC
 	.machine_kexec		= default_machine_kexec,
 	.machine_kexec_prepare	= default_machine_kexec_prepare,
Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig	2006-11-10 16:44:22.000000000 +1100
+++ linux-cell/arch/powerpc/Kconfig	2006-11-10 16:45:04.000000000 +1100
@@ -223,6 +223,11 @@ config PPC_DCR
 	depends on PPC_DCR_NATIVE || PPC_DCR_MMIO
 	default y
 
+config PPC_OF_PLATFORM_PCI
+	bool
+	depends on PPC64 # not supported on 32 bits yet
+	default n
+
 config BOOKE
 	bool
 	depends on E200 || E500
@@ -461,6 +466,7 @@ config PPC_CELL_NATIVE
 	bool
 	select PPC_CELL
 	select PPC_DCR_MMIO
+	select PPC_OF_PLATFORM_PCI
 	select MPIC
 	default n
 

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

* [PATCH 22/32] powerpc: Cell fixup DMA offset for new southbridge
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (20 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 21/32] powerpc: Generic OF platform driver " Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 23/32] powerpc: Allow hooking of PCI MMIO & PIO accessors on 64 bits Benjamin Herrenschmidt
                   ` (9 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

This patch makes the Cell DMA code work on both the Spider and the Axon
south bridges by turning cell_dma_valid into a variable instead of a
constant. This is a temporary patch until we have full iommu support.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/platforms/cell/iommu.c |   14 +++++++++++---
 arch/powerpc/platforms/cell/iommu.h |    8 +++++---
 2 files changed, 16 insertions(+), 6 deletions(-)

Index: linux-cell/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.c	2006-10-27 15:42:15.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/iommu.c	2006-10-27 15:55:13.000000000 +1000
@@ -46,6 +46,8 @@
 
 #include "iommu.h"
 
+static dma_addr_t cell_dma_valid = SPIDER_DMA_VALID;
+
 static inline unsigned long 
 get_iopt_entry(unsigned long real_address, unsigned long ioid,
 			 unsigned long prot)
@@ -423,7 +425,7 @@ static void *cell_alloc_coherent(struct 
 	ret = (void *)__get_free_pages(flag, get_order(size));
 	if (ret != NULL) {
 		memset(ret, 0, size);
-		*dma_handle = virt_to_abs(ret) | CELL_DMA_VALID;
+		*dma_handle = virt_to_abs(ret) | cell_dma_valid;
 	}
 	return ret;
 }
@@ -437,7 +439,7 @@ static void cell_free_coherent(struct de
 static dma_addr_t cell_map_single(struct device *hwdev, void *ptr,
 		size_t size, enum dma_data_direction direction)
 {
-	return virt_to_abs(ptr) | CELL_DMA_VALID;
+	return virt_to_abs(ptr) | cell_dma_valid;
 }
 
 static void cell_unmap_single(struct device *hwdev, dma_addr_t dma_addr,
@@ -452,7 +454,7 @@ static int cell_map_sg(struct device *hw
 
 	for (i = 0; i < nents; i++, sg++) {
 		sg->dma_address = (page_to_phys(sg->page) + sg->offset)
-					| CELL_DMA_VALID;
+					| cell_dma_valid;
 		sg->dma_length = sg->length;
 	}
 
@@ -483,6 +485,12 @@ void cell_init_iommu(void)
 {
 	int setup_bus = 0;
 
+	/* If we have an Axon bridge, clear the DMA valid mask. This is fairly
+	 * hackish but will work well enough until we have proper iommu code.
+	 */
+	if (of_find_node_by_name(NULL, "axon"))
+		cell_dma_valid = 0;
+
 	if (of_find_node_by_path("/mambo")) {
 		pr_info("Not using iommu on systemsim\n");
 	} else {
Index: linux-cell/arch/powerpc/platforms/cell/iommu.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.h	2006-10-27 15:49:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/iommu.h	2006-10-27 15:52:19.000000000 +1000
@@ -53,9 +53,11 @@ enum {
 	IOC_ST_ORIGIN     = 0x918,
 	IOC_CONF	  = 0x930,
 
-	/* The high bit needs to be set on every DMA address,
-	   only 2GB are addressable */
-	CELL_DMA_VALID	  = 0x80000000,
+	/* The high bit needs to be set on every DMA address when using
+	 * a spider bridge and only 2GB are addressable with the current
+	 * iommu code.
+	 */
+	SPIDER_DMA_VALID  = 0x80000000,
 	CELL_DMA_MASK	  = 0x7fffffff,
 };
 

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

* [PATCH 23/32] powerpc: Allow hooking of PCI MMIO & PIO accessors on 64 bits
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (21 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 22/32] powerpc: Cell fixup DMA offset for new southbridge Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 24/32] powerpc: Cell "Spider" MMIO workarounds Benjamin Herrenschmidt
                   ` (8 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

This patch reworks the way iSeries hooks on PCI IO operations (both MMIO
and PIO) and provides a generic way for other platforms to do so (we
have need to do that for various other platforms).

While reworking the IO ops, I ended up doing some spring cleaning in
io.h and eeh.h which I might want to split into 2 or 3 patches (among
others, eeh.h had a lot of useless stuff in it).

A side effect is that EEH for PIO should work now (it used to pass IO
ports down to the eeh address check functions which is bogus).

Also, new are MMIO "repeat" ops, which other archs like ARM already had,
and that we have too now: readsb, readsw, readsl, writesb, writesw,
writesl.

In the long run, I might also make EEH use the hooks instead
of wrapping at the toplevel, which would make things even cleaner and
relegate EEH completely in platforms/iseries, but we have to measure the
performance impact there (though it's really only on MMIO reads)

Since I also need to hook on ioremap, I shuffled the functions a bit
there. I introduced ioremap_flags() to use by drivers who want to pass
explicit flags to ioremap (and it can be hooked). The old __ioremap() is
still there as a low level and cannot be hooked, thus drivers who use it
should migrate unless they know they want the low level version.

The patch "arch provides generic iomap missing accessors" (should be
number 4 in this series) is a pre-requisite to provide full iomap
API support with this patch.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/Kconfig                   |   10 
 arch/powerpc/kernel/Makefile           |    6 
 arch/powerpc/kernel/io.c               |   18 
 arch/powerpc/kernel/pci_64.c           |    2 
 arch/powerpc/kernel/setup_64.c         |    7 
 arch/powerpc/mm/pgtable_64.c           |   46 +-
 arch/powerpc/platforms/iseries/pci.c   |  370 +++++++-----------
 arch/powerpc/platforms/iseries/setup.c |   12 
 include/asm-powerpc/eeh.h              |  118 +-----
 include/asm-powerpc/ide.h              |    7 
 include/asm-powerpc/io-defs.h          |   56 ++
 include/asm-powerpc/io.h               |  645 +++++++++++++++++++--------------
 include/asm-powerpc/machdep.h          |    4 
 include/asm-ppc/io.h                   |   12 
 14 files changed, 703 insertions(+), 610 deletions(-)

Index: linux-cell/include/asm-powerpc/io.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/io.h	2006-11-02 13:16:17.000000000 +1100
+++ linux-cell/include/asm-powerpc/io.h	2006-11-10 16:41:13.000000000 +1100
@@ -31,57 +31,122 @@ extern int check_legacy_ioport(unsigned 
 
 #define SLOW_DOWN_IO
 
+/*
+ *
+ * Low level MMIO accessors
+ *
+ * This provides the non-bus specific accessors to MMIO. Those are PowerPC
+ * specific and thus shouldn't be used in generic code. The accessors
+ * provided here are:
+ *
+ *	in_8, in_le16, in_be16, in_le32, in_be32, in_le64, in_be64
+ *	out_8, out_le16, out_be16, out_le32, out_be32, out_le64, out_be64
+ *	_insb, _insw_ns, _insl_ns, _outsb, _outsw_ns, _outsl_ns
+ *
+ * Those operate directly on a kernel virtual address. Note that the prototype
+ * for the out_* accessors has the arguments in opposite order from the usual
+ * linux PCI accessors. Unlike those, they take the address first and the value
+ * next.
+ *
+ * Note: I might drop the _ns suffix on the stream operations soon as it is
+ * simply normal for stream operations to not swap in the first place.
+ *
+ */
+
+#define IO_SET_SYNC_FLAG()	do { get_paca()->io_sync = 1; } while(0)
+
+#define DEF_MMIO_IN(name, type, insn)					\
+static inline type name(const volatile type __iomem *addr)		\
+{									\
+	type ret;							\
+	__asm__ __volatile__("sync;" insn ";twi 0,%0,0;isync"		\
+ 		: "=r" (ret) : "r" (addr), "m" (*addr));		\
+	return ret;							\
+}
+
+#define DEF_MMIO_OUT(name, type, insn)					\
+static inline void name(volatile type __iomem *addr, type val)		\
+{									\
+	__asm__ __volatile__("sync;" insn				\
+ 		: "=m" (*addr) : "r" (val), "r" (addr));		\
+	IO_SET_SYNC_FLAG();					\
+}
+
+
+#define DEF_MMIO_IN_BE(name, size, insn) \
+	DEF_MMIO_IN(name, u##size, __stringify(insn)"%U2%X2 %0,%2")
+#define DEF_MMIO_IN_LE(name, size, insn) \
+	DEF_MMIO_IN(name, u##size, __stringify(insn)" %0,0,%1")
+
+#define DEF_MMIO_OUT_BE(name, size, insn) \
+	DEF_MMIO_OUT(name, u##size, __stringify(insn)"%U0%X0 %1,%0")
+#define DEF_MMIO_OUT_LE(name, size, insn) \
+	DEF_MMIO_OUT(name, u##size, __stringify(insn)" %1,0,%2")
+
+DEF_MMIO_IN_BE(in_8,     8, lbz);
+DEF_MMIO_IN_BE(in_be16, 16, lhz);
+DEF_MMIO_IN_BE(in_be32, 32, lwz);
+DEF_MMIO_IN_BE(in_be64, 64, ld);
+DEF_MMIO_IN_LE(in_le16, 16, lhbrx);
+DEF_MMIO_IN_LE(in_le32, 32, lwbrx);
+
+DEF_MMIO_OUT_BE(out_8,     8, stb);
+DEF_MMIO_OUT_BE(out_be16, 16, sth);
+DEF_MMIO_OUT_BE(out_be32, 32, stw);
+DEF_MMIO_OUT_BE(out_be64, 64, std);
+DEF_MMIO_OUT_LE(out_le16, 16, sthbrx);
+DEF_MMIO_OUT_LE(out_le32, 32, stwbrx);
+
+/* There is no asm instructions for 64 bits reverse loads and stores */
+static inline u64 in_le64(const volatile u64 __iomem *addr)
+{
+	return le64_to_cpu(in_be64(addr));
+}
+
+static inline void out_le64(volatile u64 __iomem *addr, u64 val)
+{
+	out_be64(addr, cpu_to_le64(val));
+}
+
+/*
+ * Low level IO stream instructions are defined out of line for now
+ */
+extern void _insb(const volatile u8 __iomem *addr, void *buf, long count);
+extern void _outsb(volatile u8 __iomem *addr,const void *buf,long count);
+extern void _insw_ns(const volatile u16 __iomem *addr, void *buf, long count);
+extern void _outsw_ns(volatile u16 __iomem *addr, const void *buf, long count);
+extern void _insl_ns(const volatile u32 __iomem *addr, void *buf, long count);
+extern void _outsl_ns(volatile u32 __iomem *addr, const void *buf, long count);
+
+/* The _ns naming is historical and will be removed. For now, just #define
+ * the non _ns equivalent names
+ */
+#define _insw	_insw_ns
+#define _insl	_insl_ns
+#define _outsw	_outsw_ns
+#define _outsl	_outsl_ns
+
+/*
+ *
+ * PCI and standard ISA accessors
+ *
+ * Those are globally defined linux accessors for devices on PCI or ISA
+ * busses. They follow the Linux defined semantics. The current implementation
+ * for PowerPC is as close as possible to the x86 version of these, and thus
+ * provides fairly heavy weight barriers for the non-raw versions
+ *
+ * In addition, they support a hook mechanism when CONFIG_PPC_INDIRECT_IO
+ * allowing the platform to provide its own implementation of some or all
+ * of the accessors.
+ */
+
 extern unsigned long isa_io_base;
 extern unsigned long pci_io_base;
 
-#ifdef CONFIG_PPC_ISERIES
 
-extern int in_8(const volatile unsigned char __iomem *addr);
-extern void out_8(volatile unsigned char __iomem *addr, int val);
-extern int in_le16(const volatile unsigned short __iomem *addr);
-extern int in_be16(const volatile unsigned short __iomem *addr);
-extern void out_le16(volatile unsigned short __iomem *addr, int val);
-extern void out_be16(volatile unsigned short __iomem *addr, int val);
-extern unsigned in_le32(const volatile unsigned __iomem *addr);
-extern unsigned in_be32(const volatile unsigned __iomem *addr);
-extern void out_le32(volatile unsigned __iomem *addr, int val);
-extern void out_be32(volatile unsigned __iomem *addr, int val);
-extern unsigned long in_le64(const volatile unsigned long __iomem *addr);
-extern unsigned long in_be64(const volatile unsigned long __iomem *addr);
-extern void out_le64(volatile unsigned long __iomem *addr, unsigned long val);
-extern void out_be64(volatile unsigned long __iomem *addr, unsigned long val);
-
-extern unsigned char __raw_readb(const volatile void __iomem *addr);
-extern unsigned short __raw_readw(const volatile void __iomem *addr);
-extern unsigned int __raw_readl(const volatile void __iomem *addr);
-extern unsigned long __raw_readq(const volatile void __iomem *addr);
-extern void __raw_writeb(unsigned char v, volatile void __iomem *addr);
-extern void __raw_writew(unsigned short v, volatile void __iomem *addr);
-extern void __raw_writel(unsigned int v, volatile void __iomem *addr);
-extern void __raw_writeq(unsigned long v, volatile void __iomem *addr);
-
-extern void memset_io(volatile void __iomem *addr, int c, unsigned long n);
-extern void memcpy_fromio(void *dest, const volatile void __iomem *src,
-                                 unsigned long n);
-extern void memcpy_toio(volatile void __iomem *dest, const void *src,
-                                 unsigned long n);
-
-#else /* CONFIG_PPC_ISERIES */
-
-#define in_8(addr)		__in_8((addr))
-#define out_8(addr, val)	__out_8((addr), (val))
-#define in_le16(addr)		__in_le16((addr))
-#define in_be16(addr)		__in_be16((addr))
-#define out_le16(addr, val)	__out_le16((addr), (val))
-#define out_be16(addr, val)	__out_be16((addr), (val))
-#define in_le32(addr)		__in_le32((addr))
-#define in_be32(addr)		__in_be32((addr))
-#define out_le32(addr, val)	__out_le32((addr), (val))
-#define out_be32(addr, val)	__out_be32((addr), (val))
-#define in_le64(addr)		__in_le64((addr))
-#define in_be64(addr)		__in_be64((addr))
-#define out_le64(addr, val)	__out_le64((addr), (val))
-#define out_be64(addr, val)	__out_be64((addr), (val))
+/*
+ * Non ordered and non-swapping "raw" accessors
+ */
 
 static inline unsigned char __raw_readb(const volatile void __iomem *addr)
 {
@@ -115,52 +180,203 @@ static inline void __raw_writeq(unsigned
 {
 	*(volatile unsigned long __force *)addr = v;
 }
-#define memset_io(a,b,c)	eeh_memset_io((a),(b),(c))
-#define memcpy_fromio(a,b,c)	eeh_memcpy_fromio((a),(b),(c))
-#define memcpy_toio(a,b,c)	eeh_memcpy_toio((a),(b),(c))
-
-#endif /* CONFIG_PPC_ISERIES */
-
-/*
- * The insw/outsw/insl/outsl macros don't do byte-swapping.
- * They are only used in practice for transferring buffers which
- * are arrays of bytes, and byte-swapping is not appropriate in
- * that case.  - paulus */
-#define insb(port, buf, ns)	eeh_insb((port), (buf), (ns))
-#define insw(port, buf, ns)	eeh_insw_ns((port), (buf), (ns))
-#define insl(port, buf, nl)	eeh_insl_ns((port), (buf), (nl))
-
-#define outsb(port, buf, ns)  _outsb((u8 __iomem *)((port)+pci_io_base), (buf), (ns))
-#define outsw(port, buf, ns)  _outsw_ns((u16 __iomem *)((port)+pci_io_base), (buf), (ns))
-#define outsl(port, buf, nl)  _outsl_ns((u32 __iomem *)((port)+pci_io_base), (buf), (nl))
-
-#define readb(addr)		eeh_readb(addr)
-#define readw(addr)		eeh_readw(addr)
-#define readl(addr)		eeh_readl(addr)
-#define readq(addr)		eeh_readq(addr)
-#define writeb(data, addr)	eeh_writeb((data), (addr))
-#define writew(data, addr)	eeh_writew((data), (addr))
-#define writel(data, addr)	eeh_writel((data), (addr))
-#define writeq(data, addr)	eeh_writeq((data), (addr))
-#define inb(port)		eeh_inb((unsigned long)port)
-#define outb(val, port)		eeh_outb(val, (unsigned long)port)
-#define inw(port)		eeh_inw((unsigned long)port)
-#define outw(val, port)		eeh_outw(val, (unsigned long)port)
-#define inl(port)		eeh_inl((unsigned long)port)
-#define outl(val, port)		eeh_outl(val, (unsigned long)port)
 
+
+/*
+ *
+ * PCI PIO and MMIO accessors.
+ *
+ */
+
+#include <asm/eeh.h>
+
+/* Shortcut to the MMIO argument pointer */
+#define PCI_IO_ADDR	volatile void __iomem *
+
+/* Indirect IO address tokens:
+ *
+ * When CONFIG_PPC_INDIRECT_IO is set, the platform can provide hooks
+ * on all IOs.
+ *
+ * To help platforms who may need to differenciate MMIO addresses in
+ * their hooks, a bitfield is reserved for use by the platform near the
+ * top of MMIO addresses (not PIO, those have to cope the hard way).
+ *
+ * This bit field is 12 bits and is at the top of the IO virtual
+ * addresses PCI_IO_INDIRECT_TOKEN_MASK.
+ *
+ * The kernel virtual space is thus:
+ *
+ *  0xD000000000000000		: vmalloc
+ *  0xD000080000000000		: PCI PHB IO space
+ *  0xD000080080000000		: ioremap
+ *  0xD0000fffffffffff		: end of ioremap region
+ *
+ * Since the top 4 bits are reserved as the region ID, we use thus
+ * the next 12 bits and keep 4 bits available for the future if the
+ * virtual address space is ever to be extended.
+ *
+ * The direct IO mapping operations will then mask off those bits
+ * before doing the actual access, though that only happen when
+ * CONFIG_PPC_INDIRECT_IO is set, thus be careful when you use that
+ * mechanism
+ */
+
+#ifdef CONFIG_PPC_INDIRECT_IO
+#define PCI_IO_IND_TOKEN_MASK	0x0fff000000000000ul
+#define PCI_IO_IND_TOKEN_SHIFT	48
+#define PCI_FIX_ADDR(addr)						\
+	((PCI_IO_ADDR)(((unsigned long)(addr)) & ~PCI_IO_IND_TOKEN_MASK))
+#define PCI_GET_ADDR_TOKEN(addr)					\
+	(((unsigned long)(addr) & PCI_IO_IND_TOKEN_MASK) >> 		\
+		PCI_IO_IND_TOKEN_SHIFT)
+#define PCI_SET_ADDR_TOKEN(addr, token) 				\
+do {									\
+	unsigned long __a = (unsigned long)(addr);			\
+	__a &= ~PCI_IO_IND_TOKEN_MASK;					\
+	__a |= ((unsigned long)(token)) << PCI_IO_IND_TOKEN_SHIFT;	\
+	(addr) = (void __iomem *)__a;					\
+} while(0)
+#else
+#define PCI_FIX_ADDR(addr) (addr)
+#endif
+
+/* The "__do_*" operations below provide the actual "base" implementation
+ * for each of the defined acccessor. Some of them use the out_* functions
+ * directly, some of them still use EEH, though we might change that in the
+ * future. Those macros below provide the necessary argument swapping and
+ * handling of the IO base for PIO.
+ *
+ * They are themselves used by the macros that define the actual accessors
+ * and can be used by the hooks if any.
+ *
+ * Note that PIO operations are always defined in terms of their corresonding
+ * MMIO operations. That allows platforms like iSeries who want to modify the
+ * behaviour of both to only hook on the MMIO version and get both. It's also
+ * possible to hook directly at the toplevel PIO operation if they have to
+ * be handled differently
+ */
+#define __do_writeb(val, addr)	out_8(PCI_FIX_ADDR(addr), val)
+#define __do_writew(val, addr)	out_le16(PCI_FIX_ADDR(addr), val)
+#define __do_writel(val, addr)	out_le32(PCI_FIX_ADDR(addr), val)
+#define __do_writeq(val, addr)	out_le64(PCI_FIX_ADDR(addr), val)
+#define __do_writew_be(val, addr) out_be16(PCI_FIX_ADDR(addr), val)
+#define __do_writel_be(val, addr) out_be32(PCI_FIX_ADDR(addr), val)
+#define __do_writeq_be(val, addr) out_be64(PCI_FIX_ADDR(addr), val)
+#define __do_readb(addr)	eeh_readb(PCI_FIX_ADDR(addr))
+#define __do_readw(addr)	eeh_readw(PCI_FIX_ADDR(addr))
+#define __do_readl(addr)	eeh_readl(PCI_FIX_ADDR(addr))
+#define __do_readq(addr)	eeh_readq(PCI_FIX_ADDR(addr))
+#define __do_readw_be(addr)	eeh_readw_be(PCI_FIX_ADDR(addr))
+#define __do_readl_be(addr)	eeh_readl_be(PCI_FIX_ADDR(addr))
+#define __do_readq_be(addr)	eeh_readq_be(PCI_FIX_ADDR(addr))
+
+#define __do_outb(val, port)	writeb(val,(PCI_IO_ADDR)pci_io_base+port);
+#define __do_outw(val, port)	writew(val,(PCI_IO_ADDR)pci_io_base+port);
+#define __do_outl(val, port)	writel(val,(PCI_IO_ADDR)pci_io_base+port);
+#define __do_inb(port)		readb((PCI_IO_ADDR)pci_io_base + port);
+#define __do_inw(port)		readw((PCI_IO_ADDR)pci_io_base + port);
+#define __do_inl(port)		readl((PCI_IO_ADDR)pci_io_base + port);
+
+#define __do_readsb(a, b, n)	eeh_readsb(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsw(a, b, n)	eeh_readsw(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsl(a, b, n)	eeh_readsl(PCI_FIX_ADDR(a), (b), (n))
+#define __do_writesb(a, b, n)	_outsb(PCI_FIX_ADDR(a),(b),(n))
+#define __do_writesw(a, b, n)	_outsw(PCI_FIX_ADDR(a),(b),(n))
+#define __do_writesl(a, b, n)	_outsl(PCI_FIX_ADDR(a),(b),(n))
+
+#define __do_insb(p, b, n)	readsb((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
+#define __do_insw(p, b, n)	readsw((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
+#define __do_insl(p, b, n)	readsl((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
+#define __do_outsb(p, b, n)	writesb((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
+#define __do_outsw(p, b, n)	writesw((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
+#define __do_outsl(p, b, n)	writesl((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
+
+#define __do_memset_io(addr, c, n)	eeh_memset_io(PCI_FIX_ADDR(addr), c, n)
+#define __do_memcpy_fromio(dst, src, n)	eeh_memcpy_fromio(dst, \
+						PCI_FIX_ADDR(src), n)
+#define __do_memcpy_toio(dst, src, n)	eeh_memcpy_toio(PCI_FIX_ADDR(dst), \
+						src, n)
+
+#ifdef CONFIG_PPC_INDIRECT_IO
+#define DEF_PCI_HOOK(x)		x
+#else
+#define DEF_PCI_HOOK(x)		NULL
+#endif
+
+/* Structure containing all the hooks */
+extern struct ppc_pci_io {
+
+#define DEF_PCI_AC_RET(name, ret, at, al)	ret (*name) at;
+#define DEF_PCI_AC_NORET(name, at, al)		void (*name) at;
+
+#include <asm/io-defs.h>
+
+#undef DEF_PCI_AC_RET
+#undef DEF_PCI_AC_NORET
+
+} ppc_pci_io;
+
+/* The inline wrappers */
+#define DEF_PCI_AC_RET(name, ret, at, al)			\
+static inline ret name at					\
+{								\
+	if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL)		\
+		return ppc_pci_io.name al;			\
+	return __do_##name al;					\
+}
+
+#define DEF_PCI_AC_NORET(name, at, al)				\
+static inline void name at					\
+{								\
+	if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL)		\
+		ppc_pci_io.name al;				\
+	else							\
+		__do_##name al;					\
+}
+
+#include <asm/io-defs.h>
+
+#undef DEF_PCI_AC_RET
+#undef DEF_PCI_AC_NORET
+
+/* Some drivers check for the presence of readq & writeq with
+ * a #ifdef, so we make them happy here.
+ */
+#define readq	readq
+#define writeq	writeq
+
+/* Nothing to do for cache stuff x*/
+
+#define dma_cache_inv(_start,_size)		do { } while (0)
+#define dma_cache_wback(_start,_size)		do { } while (0)
+#define dma_cache_wback_inv(_start,_size)	do { } while (0)
+
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)	__va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)	p
+
+/*
+ * We don't do relaxed operations yet, at least not with this semantic
+ */
 #define readb_relaxed(addr) readb(addr)
 #define readw_relaxed(addr) readw(addr)
 #define readl_relaxed(addr) readl(addr)
 #define readq_relaxed(addr) readq(addr)
 
-extern void _insb(volatile u8 __iomem *port, void *buf, long count);
-extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
-extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
-extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
-extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
-extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
-
+/*
+ * Enforce synchronisation of stores vs. spin_unlock
+ * (this does it explicitely, though our implementation of spin_unlock
+ * does it implicitely too)
+ */
 static inline void mmiowb(void)
 {
 	unsigned long tmp;
@@ -170,6 +386,23 @@ static inline void mmiowb(void)
 	: "memory");
 }
 
+static inline void iosync(void)
+{
+        __asm__ __volatile__ ("sync" : : : "memory");
+}
+
+/* Enforce in-order execution of data I/O.
+ * No distinction between read/write on PPC; use eieio for all three.
+ * Those are fairly week though. They don't provide a barrier between
+ * MMIO and cacheable storage nor do they provide a barrier vs. locks,
+ * they only provide barriers between 2 __raw MMIO operations and
+ * possibly break write combining.
+ */
+#define iobarrier_rw() eieio()
+#define iobarrier_r()  eieio()
+#define iobarrier_w()  eieio()
+
+
 /*
  * output pause versions need a delay at least for the
  * w83c105 ide controller in a p610.
@@ -185,11 +418,6 @@ static inline void mmiowb(void)
 #define IO_SPACE_LIMIT ~(0UL)
 
 
-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,
-		       unsigned long flags);
-
 /**
  * ioremap     -   map bus memory into CPU space
  * @address:   bus address of the memory
@@ -200,14 +428,70 @@ extern void __iomem *__ioremap(unsigned 
  * writew/writel functions and the other mmio helpers. The returned
  * address is not guaranteed to be usable directly as a virtual
  * address.
+ *
+ * We provide a few variations of it:
+ *
+ * * ioremap is the standard one and provides non-cacheable guarded mappings
+ *   and can be hooked by the platform via ppc_md
+ *
+ * * ioremap_flags allows to specify the page flags as an argument and can
+ *   also be hooked by the platform via ppc_md
+ *
+ * * ioremap_nocache is identical to ioremap
+ *
+ * * iounmap undoes such a mapping and can be hooked
+ *
+ * * __ioremap_explicit (and the pending __iounmap_explicit) are low level
+ *   functions to create hand-made mappings for use only by the PCI code
+ *   and cannot currently be hooked.
+ *
+ * * __ioremap is the low level implementation used by ioremap and
+ *   ioremap_flags and cannot be hooked (but can be used by a hook on one
+ *   of the previous ones)
+ *
+ * * __iounmap, is the low level implementation used by iounmap and cannot
+ *   be hooked (but can be used by a hook on iounmap)
+ *
  */
 extern void __iomem *ioremap(unsigned long address, unsigned long size);
-
+extern void __iomem *ioremap_flags(unsigned long address, unsigned long size,
+				   unsigned long flags);
 #define ioremap_nocache(addr, size)	ioremap((addr), (size))
-extern int iounmap_explicit(volatile void __iomem *addr, unsigned long size);
-extern void iounmap(volatile void __iomem *addr);
+extern void iounmap(void __iomem *addr);
+
+extern void __iomem *__ioremap(unsigned long address, unsigned long size,
+			       unsigned long flags);
+extern void __iounmap(void __iomem *addr);
+
+extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr,
+		     	      unsigned long size, unsigned long flags);
+extern int __iounmap_explicit(void __iomem *start, unsigned long size);
+
 extern void __iomem * reserve_phb_iospace(unsigned long size);
 
+
+/*
+ * When CONFIG_PPC_INDIRECT_IO is set, we use the generic iomap implementation
+ * which needs some additional definitions here. They basically allow PIO
+ * space overall to be 1GB. This will work as long as we never try to use
+ * iomap to map MMIO below 1GB which should be fine on ppc64
+ */
+#define HAVE_ARCH_PIO_SIZE		1
+#define PIO_OFFSET			0x00000000UL
+#define PIO_MASK			0x3fffffffUL
+#define PIO_RESERVED			0x40000000UL
+
+#define mmio_read16be(addr)		readw_be(addr)
+#define mmio_read32be(addr)		readl_be(addr)
+#define mmio_write16be(val, addr)	writew_be(val, addr)
+#define mmio_write32be(val, addr)	writel_be(val, addr)
+#define mmio_insb(addr, dst, count)	readsb(addr, dst, count)
+#define mmio_insw(addr, dst, count)	readsw(addr, dst, count)
+#define mmio_insl(addr, dst, count)	readsl(addr, dst, count)
+#define mmio_outsb(addr, src, count)	writesb(addr, src, count)
+#define mmio_outsw(addr, src, count)	writesw(addr, src, count)
+#define mmio_outsl(addr, src, count)	writesl(addr, src, count)
+
 /**
  *	virt_to_phys	-	map virtual addresses to physical
  *	@address: address to remap
@@ -254,177 +538,6 @@ static inline void * phys_to_virt(unsign
  */
 #define BIO_VMERGE_BOUNDARY	0
 
-static inline void iosync(void)
-{
-        __asm__ __volatile__ ("sync" : : : "memory");
-}
-
-/* Enforce in-order execution of data I/O. 
- * No distinction between read/write on PPC; use eieio for all three.
- */
-#define iobarrier_rw() eieio()
-#define iobarrier_r()  eieio()
-#define iobarrier_w()  eieio()
-
-/*
- * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
- * These routines do not perform EEH-related I/O address translation,
- * and should not be used directly by device drivers.  Use inb/readb
- * instead.
- */
-static inline int __in_8(const volatile unsigned char __iomem *addr)
-{
-	int ret;
-
-	__asm__ __volatile__("sync; lbz%U1%X1 %0,%1; twi 0,%0,0; isync"
-			     : "=r" (ret) : "m" (*addr));
-	return ret;
-}
-
-static inline void __out_8(volatile unsigned char __iomem *addr, int val)
-{
-	__asm__ __volatile__("sync; stb%U0%X0 %1,%0"
-			     : "=m" (*addr) : "r" (val));
-	get_paca()->io_sync = 1;
-}
-
-static inline int __in_le16(const volatile unsigned short __iomem *addr)
-{
-	int ret;
-
-	__asm__ __volatile__("sync; lhbrx %0,0,%1; twi 0,%0,0; isync"
-			     : "=r" (ret) : "r" (addr), "m" (*addr));
-	return ret;
-}
-
-static inline int __in_be16(const volatile unsigned short __iomem *addr)
-{
-	int ret;
-
-	__asm__ __volatile__("sync; lhz%U1%X1 %0,%1; twi 0,%0,0; isync"
-			     : "=r" (ret) : "m" (*addr));
-	return ret;
-}
-
-static inline void __out_le16(volatile unsigned short __iomem *addr, int val)
-{
-	__asm__ __volatile__("sync; sthbrx %1,0,%2"
-			     : "=m" (*addr) : "r" (val), "r" (addr));
-	get_paca()->io_sync = 1;
-}
-
-static inline void __out_be16(volatile unsigned short __iomem *addr, int val)
-{
-	__asm__ __volatile__("sync; sth%U0%X0 %1,%0"
-			     : "=m" (*addr) : "r" (val));
-	get_paca()->io_sync = 1;
-}
-
-static inline unsigned __in_le32(const volatile unsigned __iomem *addr)
-{
-	unsigned ret;
-
-	__asm__ __volatile__("sync; lwbrx %0,0,%1; twi 0,%0,0; isync"
-			     : "=r" (ret) : "r" (addr), "m" (*addr));
-	return ret;
-}
-
-static inline unsigned __in_be32(const volatile unsigned __iomem *addr)
-{
-	unsigned ret;
-
-	__asm__ __volatile__("sync; lwz%U1%X1 %0,%1; twi 0,%0,0; isync"
-			     : "=r" (ret) : "m" (*addr));
-	return ret;
-}
-
-static inline void __out_le32(volatile unsigned __iomem *addr, int val)
-{
-	__asm__ __volatile__("sync; stwbrx %1,0,%2" : "=m" (*addr)
-			     : "r" (val), "r" (addr));
-	get_paca()->io_sync = 1;
-}
-
-static inline void __out_be32(volatile unsigned __iomem *addr, int val)
-{
-	__asm__ __volatile__("sync; stw%U0%X0 %1,%0"
-			     : "=m" (*addr) : "r" (val));
-	get_paca()->io_sync = 1;
-}
-
-static inline unsigned long __in_le64(const volatile unsigned long __iomem *addr)
-{
-	unsigned long tmp, ret;
-
-	__asm__ __volatile__(
-			     "sync\n"
-			     "ld %1,0(%2)\n"
-			     "twi 0,%1,0\n"
-			     "isync\n"
-			     "rldimi %0,%1,5*8,1*8\n"
-			     "rldimi %0,%1,3*8,2*8\n"
-			     "rldimi %0,%1,1*8,3*8\n"
-			     "rldimi %0,%1,7*8,4*8\n"
-			     "rldicl %1,%1,32,0\n"
-			     "rlwimi %0,%1,8,8,31\n"
-			     "rlwimi %0,%1,24,16,23\n"
-			     : "=r" (ret) , "=r" (tmp) : "b" (addr) , "m" (*addr));
-	return ret;
-}
-
-static inline unsigned long __in_be64(const volatile unsigned long __iomem *addr)
-{
-	unsigned long ret;
-
-	__asm__ __volatile__("sync; ld%U1%X1 %0,%1; twi 0,%0,0; isync"
-			     : "=r" (ret) : "m" (*addr));
-	return ret;
-}
-
-static inline void __out_le64(volatile unsigned long __iomem *addr, unsigned long val)
-{
-	unsigned long tmp;
-
-	__asm__ __volatile__(
-			     "rldimi %0,%1,5*8,1*8\n"
-			     "rldimi %0,%1,3*8,2*8\n"
-			     "rldimi %0,%1,1*8,3*8\n"
-			     "rldimi %0,%1,7*8,4*8\n"
-			     "rldicl %1,%1,32,0\n"
-			     "rlwimi %0,%1,8,8,31\n"
-			     "rlwimi %0,%1,24,16,23\n"
-			     "sync\n"
-			     "std %0,0(%3)"
-			     : "=&r" (tmp) , "=&r" (val) : "1" (val) , "b" (addr) , "m" (*addr));
-	get_paca()->io_sync = 1;
-}
-
-static inline void __out_be64(volatile unsigned long __iomem *addr, unsigned long val)
-{
-	__asm__ __volatile__("sync; std%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
-	get_paca()->io_sync = 1;
-}
-
-#include <asm/eeh.h>
-
-/* Nothing to do */
-
-#define dma_cache_inv(_start,_size)		do { } while (0)
-#define dma_cache_wback(_start,_size)		do { } while (0)
-#define dma_cache_wback_inv(_start,_size)	do { } while (0)
-
-
-/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p)	__va(p)
-
-/*
- * Convert a virtual cached pointer to an uncached pointer
- */
-#define xlate_dev_kmem_ptr(p)	p
-
 #endif /* __KERNEL__ */
 
 #endif /* CONFIG_PPC64 */
Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig	2006-11-10 16:40:53.000000000 +1100
+++ linux-cell/arch/powerpc/Kconfig	2006-11-10 16:41:13.000000000 +1100
@@ -394,6 +394,7 @@ config PPC_PSERIES
 config PPC_ISERIES
 	bool "IBM Legacy iSeries"
 	depends on PPC_MULTIPLATFORM && PPC64
+	select PPC_INDIRECT_IO
 
 config PPC_CHRP
 	bool "Common Hardware Reference Platform (CHRP) based machines"
@@ -540,6 +541,15 @@ config PPC_970_NAP
 	bool
 	default n
 
+config PPC_INDIRECT_IO
+	bool
+	select GENERIC_IOMAP
+	default n
+
+config GENERIC_IOMAP
+	bool
+	default n
+
 source "drivers/cpufreq/Kconfig"
 
 config CPU_FREQ_PMAC
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c	2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/setup_64.c	2006-11-10 16:41:13.000000000 +1100
@@ -599,3 +599,10 @@ void __init setup_per_cpu_areas(void)
 	}
 }
 #endif
+
+
+#ifdef CONFIG_PPC_INDIRECT_IO
+struct ppc_pci_io ppc_pci_io;
+EXPORT_SYMBOL(ppc_pci_io);
+#endif /* CONFIG_PPC_INDIRECT_IO */
+
Index: linux-cell/arch/powerpc/platforms/iseries/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/pci.c	2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/iseries/pci.c	2006-11-10 16:41:13.000000000 +1100
@@ -156,53 +156,6 @@ static void pci_Log_Error(char *Error_Te
 }
 
 /*
- * iSeries_pcibios_init
- *
- * Description:
- *   This function checks for all possible system PCI host bridges that connect
- *   PCI buses.  The system hypervisor is queried as to the guest partition
- *   ownership status.  A pci_controller is built for any bus which is partially
- *   owned or fully owned by this guest partition.
- */
-void iSeries_pcibios_init(void)
-{
-	struct pci_controller *phb;
-	struct device_node *root = of_find_node_by_path("/");
-	struct device_node *node = NULL;
-
-	if (root == NULL) {
-		printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
-				"of device tree\n");
-		return;
-	}
-	while ((node = of_get_next_child(root, node)) != NULL) {
-		HvBusNumber bus;
-		const u32 *busp;
-
-		if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
-			continue;
-
-		busp = get_property(node, "bus-range", NULL);
-		if (busp == NULL)
-			continue;
-		bus = *busp;
-		printk("bus %d appears to exist\n", bus);
-		phb = pcibios_alloc_controller(node);
-		if (phb == NULL)
-			continue;
-
-		phb->pci_mem_offset = phb->local_number = bus;
-		phb->first_busno = bus;
-		phb->last_busno = bus;
-		phb->ops = &iSeries_pci_ops;
-	}
-
-	of_node_put(root);
-
-	pci_devs_phb_init();
-}
-
-/*
  * iSeries_pci_final_fixup(void)
  */
 void __init iSeries_pci_final_fixup(void)
@@ -438,11 +391,7 @@ static inline struct device_node *xlate_
 /*
  * Read MM I/O Instructions for the iSeries
  * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal
- * else, data is returned in big Endian format.
- *
- * iSeries_Read_Byte = Read Byte  ( 8 bit)
- * iSeries_Read_Word = Read Word  (16 bit)
- * iSeries_Read_Long = Read Long  (32 bit)
+ * else, data is returned in Big Endian format.
  */
 static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
 {
@@ -462,14 +411,15 @@ static u8 iSeries_Read_Byte(const volati
 			num_printed = 0;
 		}
 		if (num_printed++ < 10)
-			printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", IoAddress);
+			printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n",
+			       IoAddress);
 		return 0xff;
 	}
 	do {
 		HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0);
 	} while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0);
 
-	return (u8)ret.value;
+	return ret.value;
 }
 
 static u16 iSeries_Read_Word(const volatile void __iomem *IoAddress)
@@ -490,7 +440,8 @@ static u16 iSeries_Read_Word(const volat
 			num_printed = 0;
 		}
 		if (num_printed++ < 10)
-			printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n", IoAddress);
+			printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n",
+			       IoAddress);
 		return 0xffff;
 	}
 	do {
@@ -498,7 +449,7 @@ static u16 iSeries_Read_Word(const volat
 				BarOffset, 0);
 	} while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0);
 
-	return swab16((u16)ret.value);
+	return ret.value;
 }
 
 static u32 iSeries_Read_Long(const volatile void __iomem *IoAddress)
@@ -519,7 +470,8 @@ static u32 iSeries_Read_Long(const volat
 			num_printed = 0;
 		}
 		if (num_printed++ < 10)
-			printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n", IoAddress);
+			printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n",
+			       IoAddress);
 		return 0xffffffff;
 	}
 	do {
@@ -527,15 +479,12 @@ static u32 iSeries_Read_Long(const volat
 				BarOffset, 0);
 	} while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0);
 
-	return swab32((u32)ret.value);
+	return ret.value;
 }
 
 /*
  * Write MM I/O Instructions for the iSeries
  *
- * iSeries_Write_Byte = Write Byte (8 bit)
- * iSeries_Write_Word = Write Word(16 bit)
- * iSeries_Write_Long = Write Long(32 bit)
  */
 static void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress)
 {
@@ -581,11 +530,12 @@ static void iSeries_Write_Word(u16 data,
 			num_printed = 0;
 		}
 		if (num_printed++ < 10)
-			printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n", IoAddress);
+			printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n",
+			       IoAddress);
 		return;
 	}
 	do {
-		rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0);
+		rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, data, 0);
 	} while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0);
 }
 
@@ -607,231 +557,221 @@ static void iSeries_Write_Long(u32 data,
 			num_printed = 0;
 		}
 		if (num_printed++ < 10)
-			printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n", IoAddress);
+			printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n",
+			       IoAddress);
 		return;
 	}
 	do {
-		rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0);
+		rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, data, 0);
 	} while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0);
 }
 
-extern unsigned char __raw_readb(const volatile void __iomem *addr)
-{
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	return *(volatile unsigned char __force *)addr;
-}
-EXPORT_SYMBOL(__raw_readb);
-
-extern unsigned short __raw_readw(const volatile void __iomem *addr)
+static u8 iseries_readb(const volatile void __iomem *addr)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	return *(volatile unsigned short __force *)addr;
+	return iSeries_Read_Byte(addr);
 }
-EXPORT_SYMBOL(__raw_readw);
 
-extern unsigned int __raw_readl(const volatile void __iomem *addr)
+static u16 iseries_readw(const volatile void __iomem *addr)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	return *(volatile unsigned int __force *)addr;
+	return le16_to_cpu(iSeries_Read_Word(addr));
 }
-EXPORT_SYMBOL(__raw_readl);
 
-extern unsigned long __raw_readq(const volatile void __iomem *addr)
+static u32 iseries_readl(const volatile void __iomem *addr)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	return *(volatile unsigned long __force *)addr;
+	return le32_to_cpu(iSeries_Read_Long(addr));
 }
-EXPORT_SYMBOL(__raw_readq);
 
-extern void __raw_writeb(unsigned char v, volatile void __iomem *addr)
+static u16 iseries_readw_be(const volatile void __iomem *addr)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	*(volatile unsigned char __force *)addr = v;
+	return iSeries_Read_Word(addr);
 }
-EXPORT_SYMBOL(__raw_writeb);
 
-extern void __raw_writew(unsigned short v, volatile void __iomem *addr)
+static u32 iseries_readl_be(const volatile void __iomem *addr)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	*(volatile unsigned short __force *)addr = v;
+	return iSeries_Read_Long(addr);
 }
-EXPORT_SYMBOL(__raw_writew);
 
-extern void __raw_writel(unsigned int v, volatile void __iomem *addr)
+static void iseries_writeb(u8 data, volatile void __iomem *addr)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	*(volatile unsigned int __force *)addr = v;
+	iSeries_Write_Byte(data, addr);
 }
-EXPORT_SYMBOL(__raw_writel);
 
-extern void __raw_writeq(unsigned long v, volatile void __iomem *addr)
+static void iseries_writew(u16 data, volatile void __iomem *addr)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	*(volatile unsigned long __force *)addr = v;
+	iSeries_Write_Word(cpu_to_le16(data), addr);
 }
-EXPORT_SYMBOL(__raw_writeq);
 
-int in_8(const volatile unsigned char __iomem *addr)
+static void iseries_writel(u32 data, volatile void __iomem *addr)
 {
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return iSeries_Read_Byte(addr);
-	return __in_8(addr);
+	iSeries_Write_Long(cpu_to_le32(data), addr);
 }
-EXPORT_SYMBOL(in_8);
 
-void out_8(volatile unsigned char __iomem *addr, int val)
+static void iseries_writew_be(u16 data, volatile void __iomem *addr)
 {
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		iSeries_Write_Byte(val, addr);
-	else
-		__out_8(addr, val);
+	iSeries_Write_Word(data, addr);
 }
-EXPORT_SYMBOL(out_8);
 
-int in_le16(const volatile unsigned short __iomem *addr)
+static void iseries_writel_be(u32 data, volatile void __iomem *addr)
 {
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return iSeries_Read_Word(addr);
-	return __in_le16(addr);
+	iSeries_Write_Long(data, addr);
 }
-EXPORT_SYMBOL(in_le16);
 
-int in_be16(const volatile unsigned short __iomem *addr)
+static void iseries_readsb(const volatile void __iomem *addr, void *buf,
+			   unsigned long count)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	return __in_be16(addr);
+	u8 *dst = buf;
+	while(count-- > 0)
+		*(dst++) = iSeries_Read_Byte(addr);
 }
-EXPORT_SYMBOL(in_be16);
 
-void out_le16(volatile unsigned short __iomem *addr, int val)
+static void iseries_readsw(const volatile void __iomem *addr, void *buf,
+			   unsigned long count)
 {
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		iSeries_Write_Word(val, addr);
-	else
-		__out_le16(addr, val);
+	u16 *dst = buf;
+	while(count-- > 0)
+		*(dst++) = iSeries_Read_Word(addr);
 }
-EXPORT_SYMBOL(out_le16);
 
-void out_be16(volatile unsigned short __iomem *addr, int val)
+static void iseries_readsl(const volatile void __iomem *addr, void *buf,
+			   unsigned long count)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	__out_be16(addr, val);
+	u32 *dst = buf;
+	while(count-- > 0)
+		*(dst++) = iSeries_Read_Long(addr);
 }
-EXPORT_SYMBOL(out_be16);
 
-unsigned in_le32(const volatile unsigned __iomem *addr)
+static void iseries_writesb(volatile void __iomem *addr, const void *buf,
+			    unsigned long count)
 {
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return iSeries_Read_Long(addr);
-	return __in_le32(addr);
+	const u8 *src = buf;
+	while(count-- > 0)
+		iSeries_Write_Byte(*(src++), addr);
 }
-EXPORT_SYMBOL(in_le32);
 
-unsigned in_be32(const volatile unsigned __iomem *addr)
+static void iseries_writesw(volatile void __iomem *addr, const void *buf,
+			    unsigned long count)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
-	return __in_be32(addr);
+	const u16 *src = buf;
+	while(count-- > 0)
+		iSeries_Write_Word(*(src++), addr);
 }
-EXPORT_SYMBOL(in_be32);
 
-void out_le32(volatile unsigned __iomem *addr, int val)
+static void iseries_writesl(volatile void __iomem *addr, const void *buf,
+			    unsigned long count)
 {
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		iSeries_Write_Long(val, addr);
-	else
-		__out_le32(addr, val);
+	const u32 *src = buf;
+	while(count-- > 0)
+		iSeries_Write_Long(*(src++), addr);
 }
-EXPORT_SYMBOL(out_le32);
 
-void out_be32(volatile unsigned __iomem *addr, int val)
+static void iseries_memset_io(volatile void __iomem *addr, int c,
+			      unsigned long n)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+	volatile char __iomem *d = addr;
 
-	__out_be32(addr, val);
+	while (n-- > 0)
+		iSeries_Write_Byte(c, d++);
 }
-EXPORT_SYMBOL(out_be32);
 
-unsigned long in_le64(const volatile unsigned long __iomem *addr)
+static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
+				  unsigned long n)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+	char *d = dest;
+	const volatile char __iomem *s = src;
 
-	return __in_le64(addr);
+	while (n-- > 0)
+		*d++ = iSeries_Read_Byte(s++);
 }
-EXPORT_SYMBOL(in_le64);
 
-unsigned long in_be64(const volatile unsigned long __iomem *addr)
+static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
+				unsigned long n)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+	const char *s = src;
+	volatile char __iomem *d = dest;
 
-	return __in_be64(addr);
+	while (n-- > 0)
+		iSeries_Write_Byte(*s++, d++);
 }
-EXPORT_SYMBOL(in_be64);
-
-void out_le64(volatile unsigned long __iomem *addr, unsigned long val)
-{
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
 
-	__out_le64(addr, val);
-}
-EXPORT_SYMBOL(out_le64);
+/* We only set MMIO ops. The default PIO ops will be default
+ * to the MMIO ops + pci_io_base which is 0 on iSeries as
+ * expected so both should work.
+ *
+ * Note that we don't implement the readq/writeq versions as
+ * I don't know of an HV call for doing so. Thus, the default
+ * operation will be used instead, which will fault a the value
+ * return by iSeries for MMIO addresses always hits a non mapped
+ * area. This is as good as the BUG() we used to have there.
+ */
+static struct ppc_pci_io __initdata iseries_pci_io = {
+	.readb = iseries_readb;
+	.readw = iseries_readw;
+	.readl = iseries_readl;
+	.readw_be = iseries_readw_be;
+	.readl_be = iseries_readl_be;
+	.writeb = iseries_writeb;
+	.writew = iseries_writew;
+	.writel = iseries_writel;
+	.writew_be = iseries_writew_be;
+	.writel_be = iseries_writel_be;
+	.readsb = iseries_readsb;
+	.readsw = iseries_readsw;
+	.readsl = iseries_readsl;
+	.writesb = iseries_writesb;
+	.writesw = iseries_writesw;
+	.writesl = iseries_writesl;
+	.memset_io = iseries_memset_io;
+	.memcpy_fromio = iseries_memcpy_fromio;
+	.memcpy_toio = iseries_memcpy_toio;
+};
 
-void out_be64(volatile unsigned long __iomem *addr, unsigned long val)
+/*
+ * iSeries_pcibios_init
+ *
+ * Description:
+ *   This function checks for all possible system PCI host bridges that connect
+ *   PCI buses.  The system hypervisor is queried as to the guest partition
+ *   ownership status.  A pci_controller is built for any bus which is partially
+ *   owned or fully owned by this guest partition.
+ */
+void __init iSeries_pcibios_init(void)
 {
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+	struct pci_controller *phb;
+	struct device_node *root = of_find_node_by_path("/");
+	struct device_node *node = NULL;
 
-	__out_be64(addr, val);
-}
-EXPORT_SYMBOL(out_be64);
+	/* Install IO hooks */
+	ppc_pci_io = iseries_pci_io;
 
-void memset_io(volatile void __iomem *addr, int c, unsigned long n)
-{
-	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-		volatile char __iomem *d = addr;
+	if (root == NULL) {
+		printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
+				"of device tree\n");
+		return;
+	}
+	while ((node = of_get_next_child(root, node)) != NULL) {
+		HvBusNumber bus;
+		const u32 *busp;
 
-		while (n-- > 0) {
-			iSeries_Write_Byte(c, d++);
-		}
-	} else
-		eeh_memset_io(addr, c, n);
-}
-EXPORT_SYMBOL(memset_io);
+		if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
+			continue;
 
-void memcpy_fromio(void *dest, const volatile void __iomem *src,
-                                 unsigned long n)
-{
-	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-		char *d = dest;
-		const volatile char __iomem *s = src;
+		busp = get_property(node, "bus-range", NULL);
+		if (busp == NULL)
+			continue;
+		bus = *busp;
+		printk("bus %d appears to exist\n", bus);
+		phb = pcibios_alloc_controller(node);
+		if (phb == NULL)
+			continue;
 
-		while (n-- > 0) {
-			*d++ = iSeries_Read_Byte(s++);
-		}
-	} else
-		eeh_memcpy_fromio(dest, src, n);
-}
-EXPORT_SYMBOL(memcpy_fromio);
+		phb->pci_mem_offset = phb->local_number = bus;
+		phb->first_busno = bus;
+		phb->last_busno = bus;
+		phb->ops = &iSeries_pci_ops;
+	}
 
-void memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n)
-{
-	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-		const char *s = src;
-		volatile char __iomem *d = dest;
+	of_node_put(root);
 
-		while (n-- > 0) {
-			iSeries_Write_Byte(*s++, d++);
-		}
-	} else
-		eeh_memcpy_toio(dest, src, n);
+	pci_devs_phb_init();
 }
-EXPORT_SYMBOL(memcpy_toio);
+
Index: linux-cell/include/asm-powerpc/eeh.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/eeh.h	2006-10-06 13:48:23.000000000 +1000
+++ linux-cell/include/asm-powerpc/eeh.h	2006-11-10 16:41:13.000000000 +1100
@@ -120,10 +120,6 @@ static inline u8 eeh_readb(const volatil
 		return eeh_check_failure(addr, val);
 	return val;
 }
-static inline void eeh_writeb(u8 val, volatile void __iomem *addr)
-{
-	out_8(addr, val);
-}
 
 static inline u16 eeh_readw(const volatile void __iomem *addr)
 {
@@ -132,21 +128,6 @@ static inline u16 eeh_readw(const volati
 		return eeh_check_failure(addr, val);
 	return val;
 }
-static inline void eeh_writew(u16 val, volatile void __iomem *addr)
-{
-	out_le16(addr, val);
-}
-static inline u16 eeh_raw_readw(const volatile void __iomem *addr)
-{
-	u16 val = in_be16(addr);
-	if (EEH_POSSIBLE_ERROR(val, u16))
-		return eeh_check_failure(addr, val);
-	return val;
-}
-static inline void eeh_raw_writew(u16 val, volatile void __iomem *addr) {
-	volatile u16 __iomem *vaddr = (volatile u16 __iomem *) addr;
-	out_be16(vaddr, val);
-}
 
 static inline u32 eeh_readl(const volatile void __iomem *addr)
 {
@@ -155,44 +136,38 @@ static inline u32 eeh_readl(const volati
 		return eeh_check_failure(addr, val);
 	return val;
 }
-static inline void eeh_writel(u32 val, volatile void __iomem *addr)
-{
-	out_le32(addr, val);
-}
-static inline u32 eeh_raw_readl(const volatile void __iomem *addr)
+
+static inline u64 eeh_readq(const volatile void __iomem *addr)
 {
-	u32 val = in_be32(addr);
-	if (EEH_POSSIBLE_ERROR(val, u32))
+	u64 val = in_le64(addr);
+	if (EEH_POSSIBLE_ERROR(val, u64))
 		return eeh_check_failure(addr, val);
 	return val;
 }
-static inline void eeh_raw_writel(u32 val, volatile void __iomem *addr)
-{
-	out_be32(addr, val);
-}
 
-static inline u64 eeh_readq(const volatile void __iomem *addr)
+static inline u16 eeh_readw_be(const volatile void __iomem *addr)
 {
-	u64 val = in_le64(addr);
-	if (EEH_POSSIBLE_ERROR(val, u64))
+	u16 val = in_be16(addr);
+	if (EEH_POSSIBLE_ERROR(val, u16))
 		return eeh_check_failure(addr, val);
 	return val;
 }
-static inline void eeh_writeq(u64 val, volatile void __iomem *addr)
+
+static inline u32 eeh_readl_be(const volatile void __iomem *addr)
 {
-	out_le64(addr, val);
+	u32 val = in_be32(addr);
+	if (EEH_POSSIBLE_ERROR(val, u32))
+		return eeh_check_failure(addr, val);
+	return val;
 }
-static inline u64 eeh_raw_readq(const volatile void __iomem *addr)
+
+static inline u64 eeh_readq_be(const volatile void __iomem *addr)
 {
 	u64 val = in_be64(addr);
 	if (EEH_POSSIBLE_ERROR(val, u64))
 		return eeh_check_failure(addr, val);
 	return val;
 }
-static inline void eeh_raw_writeq(u64 val, volatile void __iomem *addr)
-{
-	out_be64(addr, val);
-}
 
 #define EEH_CHECK_ALIGN(v,a) \
 	((((unsigned long)(v)) & ((a) - 1)) == 0)
@@ -292,68 +267,29 @@ static inline void eeh_memcpy_toio(volat
 
 #undef EEH_CHECK_ALIGN
 
-static inline u8 eeh_inb(unsigned long port)
-{
-	u8 val;
-	val = in_8((u8 __iomem *)(port+pci_io_base));
-	if (EEH_POSSIBLE_ERROR(val, u8))
-		return eeh_check_failure((void __iomem *)(port), val);
-	return val;
-}
-
-static inline void eeh_outb(u8 val, unsigned long port)
-{
-	out_8((u8 __iomem *)(port+pci_io_base), val);
-}
-
-static inline u16 eeh_inw(unsigned long port)
-{
-	u16 val;
-	val = in_le16((u16 __iomem *)(port+pci_io_base));
-	if (EEH_POSSIBLE_ERROR(val, u16))
-		return eeh_check_failure((void __iomem *)(port), val);
-	return val;
-}
-
-static inline void eeh_outw(u16 val, unsigned long port)
-{
-	out_le16((u16 __iomem *)(port+pci_io_base), val);
-}
-
-static inline u32 eeh_inl(unsigned long port)
-{
-	u32 val;
-	val = in_le32((u32 __iomem *)(port+pci_io_base));
-	if (EEH_POSSIBLE_ERROR(val, u32))
-		return eeh_check_failure((void __iomem *)(port), val);
-	return val;
-}
-
-static inline void eeh_outl(u32 val, unsigned long port)
-{
-	out_le32((u32 __iomem *)(port+pci_io_base), val);
-}
-
 /* in-string eeh macros */
-static inline void eeh_insb(unsigned long port, void * buf, int ns)
+static inline void eeh_readsb(const volatile void __iomem *addr, void * buf,
+			      int ns)
 {
-	_insb((u8 __iomem *)(port+pci_io_base), buf, ns);
+	_insb(addr, buf, ns);
 	if (EEH_POSSIBLE_ERROR((*(((u8*)buf)+ns-1)), u8))
-		eeh_check_failure((void __iomem *)(port), *(u8*)buf);
+		eeh_check_failure(addr, *(u8*)buf);
 }
 
-static inline void eeh_insw_ns(unsigned long port, void * buf, int ns)
+static inline void eeh_readsw(const volatile void __iomem *addr, void * buf,
+			      int ns)
 {
-	_insw_ns((u16 __iomem *)(port+pci_io_base), buf, ns);
+	_insw(addr, buf, ns);
 	if (EEH_POSSIBLE_ERROR((*(((u16*)buf)+ns-1)), u16))
-		eeh_check_failure((void __iomem *)(port), *(u16*)buf);
+		eeh_check_failure(addr, *(u16*)buf);
 }
 
-static inline void eeh_insl_ns(unsigned long port, void * buf, int nl)
+static inline void eeh_readsl(const volatile void __iomem *addr, void * buf,
+			      int nl)
 {
-	_insl_ns((u32 __iomem *)(port+pci_io_base), buf, nl);
+	_insl(addr, buf, nl);
 	if (EEH_POSSIBLE_ERROR((*(((u32*)buf)+nl-1)), u32))
-		eeh_check_failure((void __iomem *)(port), *(u32*)buf);
+		eeh_check_failure(addr, *(u32*)buf);
 }
 
 #endif /* __KERNEL__ */
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile	2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/Makefile	2006-11-10 16:41:13.000000000 +1100
@@ -63,7 +63,7 @@ obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_s
 module-$(CONFIG_PPC64)		+= module_64.o
 obj-$(CONFIG_MODULES)		+= $(module-y)
 
-pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o iomap.o
+pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o
 pci32-$(CONFIG_PPC32)		:= pci_32.o
 obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32-y)
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
@@ -72,6 +72,10 @@ obj-$(CONFIG_KEXEC)		+= machine_kexec.o 
 obj-$(CONFIG_AUDIT)		+= audit.o
 obj64-$(CONFIG_AUDIT)		+= compat_audit.o
 
+ifneq ($(CONFIG_PPC_INDIRECT_IO),y)
+pci64-$(CONFIG_PPC64)		+= iomap.o
+endif
+
 ifeq ($(CONFIG_PPC_ISERIES),y)
 $(obj)/head_64.o: $(obj)/lparmap.s
 AFLAGS_head_64.o += -I$(obj)
Index: linux-cell/arch/powerpc/mm/pgtable_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_64.c	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/mm/pgtable_64.c	2006-11-10 16:41:13.000000000 +1100
@@ -129,22 +129,12 @@ static void __iomem * __ioremap_com(unsi
 	return (void __iomem *) (ea + (addr & ~PAGE_MASK));
 }
 
-
-void __iomem *
-ioremap(unsigned long addr, unsigned long size)
-{
-	return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED);
-}
-
 void __iomem * __ioremap(unsigned long addr, unsigned long size,
 			 unsigned long flags)
 {
 	unsigned long pa, ea;
 	void __iomem *ret;
 
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return (void __iomem *)addr;
-
 	/*
 	 * Choose an address to map it to.
 	 * Once the imalloc system is running, we use it.
@@ -178,6 +168,25 @@ void __iomem * __ioremap(unsigned long a
 	return ret;
 }
 
+
+void __iomem * ioremap(unsigned long addr, unsigned long size)
+{
+	unsigned long flags = _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+	if (ppc_md.ioremap)
+		return ppc_md.ioremap(addr, size, flags);
+	return __ioremap(addr, size, flags);
+}
+
+void __iomem * ioremap_flags(unsigned long addr, unsigned long size,
+			     unsigned long flags)
+{
+	if (ppc_md.ioremap)
+		return ppc_md.ioremap(addr, size, flags);
+	return __ioremap(addr, size, flags);
+}
+
+
 #define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
 
 int __ioremap_explicit(unsigned long pa, unsigned long ea,
@@ -235,13 +244,10 @@ int __ioremap_explicit(unsigned long pa,
  *
  * XXX	what about calls before mem_init_done (ie python_countermeasures())
  */
-void iounmap(volatile void __iomem *token)
+void __iounmap(void __iomem *token)
 {
 	void *addr;
 
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return;
-
 	if (!mem_init_done)
 		return;
 	
@@ -250,6 +256,14 @@ void iounmap(volatile void __iomem *toke
 	im_free(addr);
 }
 
+void iounmap(void __iomem *token)
+{
+	if (ppc_md.iounmap)
+		ppc_md.iounmap(token);
+	else
+		__iounmap(token);
+}
+
 static int iounmap_subset_regions(unsigned long addr, unsigned long size)
 {
 	struct vm_struct *area;
@@ -268,7 +282,7 @@ static int iounmap_subset_regions(unsign
 	return 0;
 }
 
-int iounmap_explicit(volatile void __iomem *start, unsigned long size)
+int __iounmap_explicit(void __iomem *start, unsigned long size)
 {
 	struct vm_struct *area;
 	unsigned long addr;
@@ -303,8 +317,10 @@ int iounmap_explicit(volatile void __iom
 }
 
 EXPORT_SYMBOL(ioremap);
+EXPORT_SYMBOL(ioremap_flags);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(__iounmap);
 
 void __iomem * reserve_phb_iospace(unsigned long size)
 {
Index: linux-cell/arch/powerpc/platforms/iseries/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/setup.c	2006-10-27 15:39:09.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/iseries/setup.c	2006-11-10 16:41:13.000000000 +1100
@@ -649,6 +649,16 @@ static void iseries_dedicated_idle(void)
 void __init iSeries_init_IRQ(void) { }
 #endif
 
+static void __iomem *iseries_ioremap(unsigned long address, unsigned long size,
+				     unsigned long flags)
+{
+	return (void __iomem *)address;
+}
+
+static void iseries_iounmap(void __iomem *token)
+{
+}
+
 /*
  * iSeries has no legacy IO, anything calling this function has to
  * fail or bad things will happen
@@ -687,6 +697,8 @@ define_machine(iseries) {
 	.progress	= iSeries_progress,
 	.probe		= iseries_probe,
 	.check_legacy_ioport	= iseries_check_legacy_ioport,
+	.ioremap	= iseries_ioremap,
+	.iounmap	= iseries_iounmap,
 	/* XXX Implement enable_pmcs for iSeries */
 };
 
Index: linux-cell/include/asm-powerpc/io-defs.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/include/asm-powerpc/io-defs.h	2006-11-10 16:41:13.000000000 +1100
@@ -0,0 +1,56 @@
+/* This file is meant to be include multiple times by other headers */
+
+DEF_PCI_AC_RET(readb, u8, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_RET(readw, u16, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_RET(readl, u32, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_RET(readw_be, u16, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_RET(readl_be, u32, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_NORET(writeb, (u8 val, PCI_IO_ADDR addr), (val, addr))
+DEF_PCI_AC_NORET(writew, (u16 val, PCI_IO_ADDR addr), (val, addr))
+DEF_PCI_AC_NORET(writel, (u32 val, PCI_IO_ADDR addr), (val, addr))
+DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr))
+DEF_PCI_AC_NORET(writew_be, (u16 val, PCI_IO_ADDR addr), (val, addr))
+DEF_PCI_AC_NORET(writel_be, (u32 val, PCI_IO_ADDR addr), (val, addr))
+DEF_PCI_AC_NORET(writeq_be, (u64 val, PCI_IO_ADDR addr), (val, addr))
+
+DEF_PCI_AC_RET(inb, u8, (unsigned long port), (port))
+DEF_PCI_AC_RET(inw, u16, (unsigned long port), (port))
+DEF_PCI_AC_RET(inl, u32, (unsigned long port), (port))
+DEF_PCI_AC_NORET(outb, (u8 val, unsigned long port), (val, port))
+DEF_PCI_AC_NORET(outw, (u16 val, unsigned long port), (val, port))
+DEF_PCI_AC_NORET(outl, (u32 val, unsigned long port), (val, port))
+
+DEF_PCI_AC_NORET(readsb, (const PCI_IO_ADDR a, void *b, unsigned long c), \
+		 (a, b, c))
+DEF_PCI_AC_NORET(readsw, (const PCI_IO_ADDR a, void *b, unsigned long c), \
+		 (a, b, c))
+DEF_PCI_AC_NORET(readsl, (const PCI_IO_ADDR a, void *b, unsigned long c), \
+		 (a, b, c))
+DEF_PCI_AC_NORET(writesb, (PCI_IO_ADDR a, const void *b, unsigned long c), \
+		 (a, b, c))
+DEF_PCI_AC_NORET(writesw, (PCI_IO_ADDR a, const void *b, unsigned long c), \
+		 (a, b, c))
+DEF_PCI_AC_NORET(writesl, (PCI_IO_ADDR a, const void *b, unsigned long c), \
+		 (a, b, c))
+
+DEF_PCI_AC_NORET(insb, (unsigned long p, void *b, unsigned long c), \
+		 (p, b, c))
+DEF_PCI_AC_NORET(insw, (unsigned long p, void *b, unsigned long c), \
+		 (p, b, c))
+DEF_PCI_AC_NORET(insl, (unsigned long p, void *b, unsigned long c), \
+		 (p, b, c))
+DEF_PCI_AC_NORET(outsb, (unsigned long p, const void *b, unsigned long c), \
+		 (p, b, c))
+DEF_PCI_AC_NORET(outsw, (unsigned long p, const void *b, unsigned long c), \
+		 (p, b, c))
+DEF_PCI_AC_NORET(outsl, (unsigned long p, const void *b, unsigned long c), \
+		 (p, b, c))
+
+DEF_PCI_AC_NORET(memset_io, (PCI_IO_ADDR a, int c, unsigned long n),	   \
+		 (a, c, n))
+DEF_PCI_AC_NORET(memcpy_fromio,(void *d,const PCI_IO_ADDR s,unsigned long n), \
+		 (d, s, n))
+DEF_PCI_AC_NORET(memcpy_toio,(PCI_IO_ADDR d,const void *s,unsigned long n),   \
+		 (d, s, n))
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h	2006-11-10 16:40:53.000000000 +1100
+++ linux-cell/include/asm-powerpc/machdep.h	2006-11-10 16:41:13.000000000 +1100
@@ -87,6 +87,10 @@ struct machdep_calls {
 	void		(*tce_flush)(struct iommu_table *tbl);
 	void		(*pci_dma_dev_setup)(struct pci_dev *dev);
 	void		(*pci_dma_bus_setup)(struct pci_bus *bus);
+
+	void __iomem *	(*ioremap)(unsigned long addr, unsigned long size,
+				   unsigned long flags);
+	void		(*iounmap)(void __iomem *token);
 #endif /* CONFIG_PPC64 */
 
 	int		(*probe)(void);
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c	2006-11-10 16:40:53.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_64.c	2006-11-10 16:41:13.000000000 +1100
@@ -1145,7 +1145,7 @@ int unmap_bus_range(struct pci_bus *bus)
 	
 	if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
 		return 1;
-	if (iounmap_explicit((void __iomem *) start_virt, size))
+	if (__iounmap_explicit((void __iomem *) start_virt, size))
 		return 1;
 
 	return 0;
Index: linux-cell/arch/powerpc/kernel/io.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/io.c	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/io.c	2006-11-10 16:41:13.000000000 +1100
@@ -25,13 +25,11 @@
 #include <asm/firmware.h>
 #include <asm/bug.h>
 
-void _insb(volatile u8 __iomem *port, void *buf, long count)
+void _insb(const volatile u8 __iomem *port, void *buf, long count)
 {
 	u8 *tbuf = buf;
 	u8 tmp;
 
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
 	if (unlikely(count <= 0))
 		return;
 	asm volatile("sync");
@@ -48,8 +46,6 @@ void _outsb(volatile u8 __iomem *port, c
 {
 	const u8 *tbuf = buf;
 
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
 	if (unlikely(count <= 0))
 		return;
 	asm volatile("sync");
@@ -60,13 +56,11 @@ void _outsb(volatile u8 __iomem *port, c
 }
 EXPORT_SYMBOL(_outsb);
 
-void _insw_ns(volatile u16 __iomem *port, void *buf, long count)
+void _insw_ns(const volatile u16 __iomem *port, void *buf, long count)
 {
 	u16 *tbuf = buf;
 	u16 tmp;
 
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
 	if (unlikely(count <= 0))
 		return;
 	asm volatile("sync");
@@ -83,8 +77,6 @@ void _outsw_ns(volatile u16 __iomem *por
 {
 	const u16 *tbuf = buf;
 
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
 	if (unlikely(count <= 0))
 		return;
 	asm volatile("sync");
@@ -95,13 +87,11 @@ void _outsw_ns(volatile u16 __iomem *por
 }
 EXPORT_SYMBOL(_outsw_ns);
 
-void _insl_ns(volatile u32 __iomem *port, void *buf, long count)
+void _insl_ns(const volatile u32 __iomem *port, void *buf, long count)
 {
 	u32 *tbuf = buf;
 	u32 tmp;
 
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
 	if (unlikely(count <= 0))
 		return;
 	asm volatile("sync");
@@ -118,8 +108,6 @@ void _outsl_ns(volatile u32 __iomem *por
 {
 	const u32 *tbuf = buf;
 
-	BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
-
 	if (unlikely(count <= 0))
 		return;
 	asm volatile("sync");
Index: linux-cell/include/asm-powerpc/ide.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ide.h	2006-10-06 13:48:23.000000000 +1000
+++ linux-cell/include/asm-powerpc/ide.h	2006-11-10 16:41:13.000000000 +1100
@@ -22,10 +22,17 @@
 #endif
 #endif
 
+#ifdef __powerpc64__
+#define __ide_mm_insw(p, a, c)	readsw((void __iomem *)(p), (a), (c))
+#define __ide_mm_insl(p, a, c)	readsl((void __iomem *)(p), (a), (c))
+#define __ide_mm_outsw(p, a, c)	writesw((void __iomem *)(p), (a), (c))
+#define __ide_mm_outsl(p, a, c)	writesl((void __iomem *)(p), (a), (c))
+#else
 #define __ide_mm_insw(p, a, c)	_insw_ns((volatile u16 __iomem *)(p), (a), (c))
 #define __ide_mm_insl(p, a, c)	_insl_ns((volatile u32 __iomem *)(p), (a), (c))
 #define __ide_mm_outsw(p, a, c)	_outsw_ns((volatile u16 __iomem *)(p), (a), (c))
 #define __ide_mm_outsl(p, a, c)	_outsl_ns((volatile u32 __iomem *)(p), (a), (c))
+#endif
 
 #ifndef  __powerpc64__
 #include <linux/hdreg.h>
Index: linux-cell/include/asm-ppc/io.h
===================================================================
--- linux-cell.orig/include/asm-ppc/io.h	2006-10-13 17:23:49.000000000 +1000
+++ linux-cell/include/asm-ppc/io.h	2006-11-10 16:41:13.000000000 +1100
@@ -327,12 +327,12 @@ __do_out_asm(outl, "stwbrx")
 #define inl_p(port)		inl((port))
 #define outl_p(val, port)	outl((val), (port))
 
-extern void _insb(volatile u8 __iomem *port, void *buf, long count);
-extern void _outsb(volatile u8 __iomem *port, const void *buf, long count);
-extern void _insw_ns(volatile u16 __iomem *port, void *buf, long count);
-extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count);
-extern void _insl_ns(volatile u32 __iomem *port, void *buf, long count);
-extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count);
+extern void _insb(const volatile u8 __iomem *addr, void *buf, long count);
+extern void _outsb(volatile u8 __iomem *addr,const void *buf,long count);
+extern void _insw_ns(const volatile u16 __iomem *addr, void *buf, long count);
+extern void _outsw_ns(volatile u16 __iomem *addr, const void *buf, long count);
+extern void _insl_ns(const volatile u32 __iomem *addr, void *buf, long count);
+extern void _outsl_ns(volatile u32 __iomem *addr, const void *buf, long count);
 
 
 #define IO_SPACE_LIMIT ~0

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

* [PATCH 24/32] powerpc: Cell "Spider" MMIO workarounds
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (22 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 23/32] powerpc: Allow hooking of PCI MMIO & PIO accessors on 64 bits Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 26/32] powerpc: Add an optional offset to direct DMA on 64 bits Benjamin Herrenschmidt
                   ` (7 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

This is totally untested, I just put it together quickly, but gives an
example of how the hooks can be used which is why I introduced it in
this serie. Hopefully, I'll test & fix it up properly this week.

This patch implements a workaround for a Spider PCI host bridge bug
where it doesn't enforce some of the PCI ordering rules unless some
manual manipulation of a special register is done. In order to be
fully compliant with the PCI spec, I do this on every MMIO read
operation.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/Kconfig                         |    1 
 arch/powerpc/platforms/cell/Makefile         |    3 
 arch/powerpc/platforms/cell/io-workarounds.c |  346 +++++++++++++++++++++++++++
 3 files changed, 349 insertions(+), 1 deletion(-)

Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig	2006-11-08 15:18:10.000000000 +1100
+++ linux-cell/arch/powerpc/Kconfig	2006-11-09 17:29:40.000000000 +1100
@@ -468,6 +468,7 @@ config PPC_CELL_NATIVE
 	select PPC_CELL
 	select PPC_DCR_MMIO
 	select PPC_OF_PLATFORM_PCI
+	select PPC_INDIRECT_IO
 	select MPIC
 	default n
 
Index: linux-cell/arch/powerpc/platforms/cell/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/Makefile	2006-11-08 15:18:10.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/Makefile	2006-11-08 15:21:34.000000000 +1100
@@ -1,5 +1,6 @@
 obj-$(CONFIG_PPC_CELL_NATIVE)		+= interrupt.o iommu.o setup.o \
-					   cbe_regs.o spider-pic.o pervasive.o
+					   cbe_regs.o spider-pic.o \
+					   pervasive.o io-workarounds.o
 obj-$(CONFIG_CBE_RAS)			+= ras.o
 
 ifeq ($(CONFIG_SMP),y)
Index: linux-cell/arch/powerpc/platforms/cell/io-workarounds.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/platforms/cell/io-workarounds.c	2006-11-09 17:30:11.000000000 +1100
@@ -0,0 +1,346 @@
+/*
+ *  Copyright (C) 2006 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+
+#define SPIDER_PCI_REG_BASE		0xd000
+#define SPIDER_PCI_VCI_CNTL_STAT	0x0110
+#define SPIDER_PCI_DUMMY_READ		0x0810
+#define SPIDER_PCI_DUMMY_READ_BASE	0x0814
+
+/* Undefine that to re-enable bogus prefetch
+ *
+ * Without that workaround, the chip will do bogus prefetch past
+ * page boundary from system memory. This setting will disable that,
+ * though the documentation is unclear as to the consequences of doing
+ * so, either purely performances, or possible misbehaviour... It's not
+ * clear wether the chip can handle unaligned accesses at all without
+ * prefetching enabled.
+ *
+ * For now, things appear to be behaving properly with that prefetching
+ * disabled and IDE, possibly because IDE isn't doing any unaligned
+ * access.
+ */
+#define SPIDER_DISABLE_PREFETCH
+
+#define MAX_SPIDERS	2
+
+static struct spider_pci_bus {
+	void __iomem	*regs;
+	unsigned long	mmio_start;
+	unsigned long	mmio_end;
+	unsigned long	pio_vstart;
+	unsigned long	pio_vend;
+} spider_pci_busses[MAX_SPIDERS];
+static int spider_pci_count;
+
+static struct spider_pci_bus *spider_pci_find(unsigned long vaddr,
+					      unsigned long paddr)
+{
+	int i;
+
+	for (i = 0; i < spider_pci_count; i++) {
+		struct spider_pci_bus *bus = &spider_pci_busses[i];
+		if (paddr && paddr >= bus->mmio_start && paddr < bus->mmio_end)
+			return bus;
+		if (vaddr && vaddr >= bus->pio_vstart && vaddr < bus->pio_vend)
+			return bus;
+	}
+	return NULL;
+}
+
+static void spider_io_flush(const volatile void __iomem *addr)
+{
+	struct spider_pci_bus *bus;
+	int token;
+
+	/* Get platform token (set by ioremap) from address */
+	token = PCI_GET_ADDR_TOKEN(addr);
+
+	/* Fast path if we have a non-0 token, it indicates which bus we
+	 * are on.
+	 *
+	 * If the token is 0, that means either the the ioremap was done
+	 * before we initialized this layer, or it's a PIO operation. We
+	 * fallback to a low path in this case. Hopefully, internal devices
+	 * which are ioremap'ed early should use in_XX/out_XX functions
+	 * instead of the PCI ones and thus not suffer from the slowdown.
+	 *
+	 * Also note that currently, the workaround will not work for areas
+	 * that are not mapped with PTEs (bolted in the hash table). This
+	 * is the case for ioremaps done very early at boot (before
+	 * mem_init_done) and includes the mapping of the ISA IO space.
+	 *
+	 * Fortunately, none of the affected devices is expected to do DMA
+	 * and thus there should be no problem in practice.
+	 *
+	 * In order to improve performances, we only do the PTE search for
+	 * addresses falling in the PHB IO space area. That means it will
+	 * not work for hotplug'ed PHBs but those don't exist with Spider.
+	 */
+	if (token && token <= spider_pci_count)
+		bus = &spider_pci_busses[token - 1];
+	else {
+		unsigned long vaddr, paddr;
+		pte_t *ptep;
+
+		/* Fixup physical address */
+		vaddr = (unsigned long)PCI_FIX_ADDR(addr);
+
+		/* Check if it's in allowed range for  PIO */
+		if (vaddr < PHBS_IO_BASE || vaddr >= IMALLOC_BASE)
+			return;
+
+		/* Try to find a PTE. If not, clear the paddr, we'll do
+		 * a vaddr only lookup (PIO only)
+		 */
+		ptep = find_linux_pte(init_mm.pgd, vaddr);
+		if (ptep == NULL)
+			paddr = 0;
+		else
+			paddr = pte_pfn(*ptep) << PAGE_SHIFT;
+
+		bus = spider_pci_find(vaddr, paddr);
+		if (bus == NULL)
+			return;
+	}
+
+	/* Now do the workaround
+	 */
+	(void)in_be32(bus->regs + SPIDER_PCI_DUMMY_READ);
+}
+
+static u8 spider_readb(const volatile void __iomem *addr)
+{
+	u8 val = __do_readb(addr);
+	spider_io_flush(addr);
+	return val;
+}
+
+static u16 spider_readw(const volatile void __iomem *addr)
+{
+	u16 val = __do_readw(addr);
+	spider_io_flush(addr);
+	return val;
+}
+
+static u32 spider_readl(const volatile void __iomem *addr)
+{
+	u32 val = __do_readl(addr);
+	spider_io_flush(addr);
+	return val;
+}
+
+static u64 spider_readq(const volatile void __iomem *addr)
+{
+	u64 val = __do_readq(addr);
+	spider_io_flush(addr);
+	return val;
+}
+
+static u16 spider_readw_be(const volatile void __iomem *addr)
+{
+	u16 val = __do_readw_be(addr);
+	spider_io_flush(addr);
+	return val;
+}
+
+static u32 spider_readl_be(const volatile void __iomem *addr)
+{
+	u32 val = __do_readl_be(addr);
+	spider_io_flush(addr);
+	return val;
+}
+
+static u64 spider_readq_be(const volatile void __iomem *addr)
+{
+	u64 val = __do_readq_be(addr);
+	spider_io_flush(addr);
+	return val;
+}
+
+static void spider_readsb(const volatile void __iomem *addr, void *buf,
+			  unsigned long count)
+{
+	__do_readsb(addr, buf, count);
+	spider_io_flush(addr);
+}
+
+static void spider_readsw(const volatile void __iomem *addr, void *buf,
+			  unsigned long count)
+{
+	__do_readsw(addr, buf, count);
+	spider_io_flush(addr);
+}
+
+static void spider_readsl(const volatile void __iomem *addr, void *buf,
+			  unsigned long count)
+{
+	__do_readsl(addr, buf, count);
+	spider_io_flush(addr);
+}
+
+static void spider_memcpy_fromio(void *dest, const volatile void __iomem *src,
+				 unsigned long n)
+{
+	__do_memcpy_fromio(dest, src, n);
+	spider_io_flush(src);
+}
+
+
+static void __iomem * spider_ioremap(unsigned long addr, unsigned long size,
+				     unsigned long flags)
+{
+	struct spider_pci_bus *bus;
+	void __iomem *res = __ioremap(addr, size, flags);
+	int busno;
+
+	pr_debug("spider_ioremap(0x%lx, 0x%lx, 0x%lx) -> 0x%p\n",
+		 addr, size, flags, res);
+
+	bus = spider_pci_find(0, addr);
+	if (bus != NULL) {
+		busno = bus - spider_pci_busses;
+		pr_debug(" found bus %d, setting token\n", busno);
+		PCI_SET_ADDR_TOKEN(res, busno + 1);
+	}
+	pr_debug(" result=0x%p\n", res);
+
+	return res;
+}
+
+static void __init spider_pci_setup_chip(struct spider_pci_bus *bus)
+{
+#ifdef SPIDER_DISABLE_PREFETCH
+	u32 val = in_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT);
+	pr_debug(" PVCI_Control_Status was 0x%08x\n", val);
+	out_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);
+#endif
+
+	/* Configure the dummy address for the workaround */
+	out_be32(bus->regs + SPIDER_PCI_DUMMY_READ_BASE, 0x80000000);
+}
+
+static void __init spider_pci_add_one(struct pci_controller *phb)
+{
+	struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count];
+	struct device_node *np = phb->arch_data;
+	struct resource rsrc;
+	void __iomem *regs;
+
+	if (spider_pci_count >= MAX_SPIDERS) {
+		printk(KERN_ERR "Too many spider bridges, workarounds"
+		       " disabled for %s\n", np->full_name);
+		return;
+	}
+
+	/* Get the registers for the beast */
+	if (of_address_to_resource(np, 0, &rsrc)) {
+		printk(KERN_ERR "Failed to get registers for spider %s"
+		       " workarounds disabled\n", np->full_name);
+		return;
+	}
+
+	/* Mask out some useless bits in there to get to the base of the
+	 * spider chip
+	 */
+	rsrc.start &= ~0xfffffffful;
+
+	/* Map them */
+	regs = ioremap(rsrc.start + SPIDER_PCI_REG_BASE, 0x1000);
+	if (regs == NULL) {
+		printk(KERN_ERR "Failed to map registers for spider %s"
+		       " workarounds disabled\n", np->full_name);
+		return;
+	}
+
+	spider_pci_count++;
+
+	/* We assume spiders only have one MMIO resource */
+	bus->mmio_start = phb->mem_resources[0].start;
+	bus->mmio_end = phb->mem_resources[0].end + 1;
+
+	bus->pio_vstart = (unsigned long)phb->io_base_virt;
+	bus->pio_vend = bus->pio_vstart + phb->pci_io_size;
+
+	bus->regs = regs;
+
+	printk(KERN_INFO "PCI: Spider MMIO workaround for %s\n",np->full_name);
+
+	pr_debug(" mmio (P) = 0x%016lx..0x%016lx\n",
+		 bus->mmio_start, bus->mmio_end);
+	pr_debug("  pio (V) = 0x%016lx..0x%016lx\n",
+		 bus->pio_vstart, bus->pio_vend);
+	pr_debug(" regs (P) = 0x%016lx (V) = 0x%p\n",
+		 rsrc.start + SPIDER_PCI_REG_BASE, bus->regs);
+
+	spider_pci_setup_chip(bus);
+}
+
+static struct ppc_pci_io __initdata spider_pci_io = {
+	.readb = spider_readb,
+	.readw = spider_readw,
+	.readl = spider_readl,
+	.readq = spider_readq,
+	.readw_be = spider_readw_be,
+	.readl_be = spider_readl_be,
+	.readq_be = spider_readq_be,
+	.readsb = spider_readsb,
+	.readsw = spider_readsw,
+	.readsl = spider_readsl,
+	.memcpy_fromio = spider_memcpy_fromio,
+};
+
+static int __init spider_pci_workaround_init(void)
+{
+	struct pci_controller *phb;
+
+	if (!machine_is(cell))
+		return 0;
+
+	/* Find spider bridges. We assume they have been all probed
+	 * in setup_arch(). If that was to change, we would need to
+	 * update this code to cope with dynamically added busses
+	 */
+	list_for_each_entry(phb, &hose_list, list_node) {
+		struct device_node *np = phb->arch_data;
+		const char *model = get_property(np, "model", NULL);
+
+		/* If no model property or name isn't exactly "pci", skip */
+		if (model == NULL || strcmp(np->name, "pci"))
+			continue;
+		/* If model is not "Spider", skip */
+		if (strcmp(model, "Spider"))
+			continue;
+		spider_pci_add_one(phb);
+	}
+
+	/* No Spider PCI found, exit */
+	if (spider_pci_count == 0)
+		return 0;
+
+	/* Setup IO callbacks. We only setup MMIO reads. PIO reads will
+	 * fallback to MMIO reads (though without a token, thus slower)
+	 */
+	ppc_pci_io = spider_pci_io;
+
+	/* Setup ioremap callback */
+	ppc_md.ioremap = spider_ioremap;
+
+	return 0;
+}
+arch_initcall(spider_pci_workaround_init);

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

* [PATCH 25/32] powerpc: spider uses low level BE MMIO accessors
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (24 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 26/32] powerpc: Add an optional offset to direct DMA on 64 bits Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 27/32] powerpc: Make direct DMA use node local allocations Benjamin Herrenschmidt
                   ` (5 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

We use the powerpc specific low level MMIO accessor variants instead
of readl() or readl_be() because we know spidernet is not a real PCI
device and we can thus avoid the performance hit caused by the PCI
workarounds.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 drivers/net/spider_net.c |   18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

Index: linux-cell/drivers/net/spider_net.c
===================================================================
--- linux-cell.orig/drivers/net/spider_net.c	2006-11-07 15:10:08.000000000 +1100
+++ linux-cell/drivers/net/spider_net.c	2006-11-07 15:11:26.000000000 +1100
@@ -88,12 +88,11 @@ MODULE_DEVICE_TABLE(pci, spider_net_pci_
 static inline u32
 spider_net_read_reg(struct spider_net_card *card, u32 reg)
 {
-	u32 value;
-
-	value = readl(card->regs + reg);
-	value = le32_to_cpu(value);
-
-	return value;
+	/* We use the powerpc specific variants instead of readl_be() because
+	 * we know spidernet is not a real PCI device and we can thus avoid the
+	 * performance hit caused by the PCI workarounds.
+	 */
+	return in_be32(card->regs + reg);
 }
 
 /**
@@ -105,8 +104,11 @@ spider_net_read_reg(struct spider_net_ca
 static inline void
 spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
 {
-	value = cpu_to_le32(value);
-	writel(value, card->regs + reg);
+	/* We use the powerpc specific variants instead of writel_be() because
+	 * we know spidernet is not a real PCI device and we can thus avoid the
+	 * performance hit caused by the PCI workarounds.
+	 */
+	out_be32(card->regs + reg, value);
 }
 
 /** spider_net_write_phy - write to phy register

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

* [PATCH 26/32] powerpc: Add an optional offset to direct DMA on 64 bits
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (23 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 24/32] powerpc: Cell "Spider" MMIO workarounds Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 25/32] powerpc: spider uses low level BE MMIO accessors Benjamin Herrenschmidt
                   ` (6 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

This patch adds an optional global offset that can be added to DMA addresses
when using the direct DMA operations.

That brings it a step closer to the 32 bits direct DMA operations, and makes
it useable on Cell when the MMU is disabled and we are using a spider
southbridge.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/dma_64.c      |   11 ++++++++---
 include/asm-powerpc/dma-mapping.h |    2 ++
 2 files changed, 10 insertions(+), 3 deletions(-)

Index: linux-cell/arch/powerpc/kernel/dma_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/dma_64.c	2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/dma_64.c	2006-11-10 16:45:21.000000000 +1100
@@ -111,7 +111,11 @@ EXPORT_SYMBOL(dma_iommu_ops);
 
 /*
  * Generic direct DMA implementation
+ *
+ * This implementation supports a global offset that can be applied if
+ * the address at which memory is visible to devices is not 0.
  */
+unsigned long dma_direct_offset;
 
 static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 				       dma_addr_t *dma_handle, gfp_t flag)
@@ -122,7 +126,7 @@ static void *dma_direct_alloc_coherent(s
 	ret = (void *)__get_free_pages(flag, get_order(size));
 	if (ret != NULL) {
 		memset(ret, 0, size);
-		*dma_handle = virt_to_abs(ret);
+		*dma_handle = virt_to_abs(ret) | dma_direct_offset;
 	}
 	return ret;
 }
@@ -137,7 +141,7 @@ static dma_addr_t dma_direct_map_single(
 					size_t size,
 					enum dma_data_direction direction)
 {
-	return virt_to_abs(ptr);
+	return virt_to_abs(ptr) | dma_direct_offset;
 }
 
 static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr,
@@ -152,7 +156,8 @@ static int dma_direct_map_sg(struct devi
 	int i;
 
 	for (i = 0; i < nents; i++, sg++) {
-		sg->dma_address = page_to_phys(sg->page) + sg->offset;
+		sg->dma_address = (page_to_phys(sg->page) + sg->offset) |
+			dma_direct_offset;
 		sg->dma_length = sg->length;
 	}
 
Index: linux-cell/include/asm-powerpc/dma-mapping.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/dma-mapping.h	2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/include/asm-powerpc/dma-mapping.h	2006-11-10 16:45:21.000000000 +1100
@@ -187,6 +187,8 @@ static inline void dma_unmap_sg(struct d
 extern struct dma_mapping_ops dma_iommu_ops;
 extern struct dma_mapping_ops dma_direct_ops;
 
+extern unsigned long dma_direct_offset;
+
 #else /* CONFIG_PPC64 */
 
 #define dma_supported(dev, mask)	(1)

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

* [PATCH 27/32] powerpc: Make direct DMA use node local allocations
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (25 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 25/32] powerpc: spider uses low level BE MMIO accessors Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 28/32] powerpc: Make cell use direct DMA ops Benjamin Herrenschmidt
                   ` (4 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

This patch makes dma_alloc_coherent() use node local allocation when
using the direct DMA ops. The node is obtained from the new device
extension. If no such extension is present, the current node is used.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/dma_64.c |   14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

Index: linux-cell/arch/powerpc/kernel/dma_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/dma_64.c	2006-11-10 16:53:23.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/dma_64.c	2006-11-10 16:53:56.000000000 +1100
@@ -120,14 +120,18 @@ unsigned long dma_direct_offset;
 static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 				       dma_addr_t *dma_handle, gfp_t flag)
 {
+	struct page *page;
 	void *ret;
+	int node = dev->sysdata.numa_node;
 
 	/* TODO: Maybe use the numa node here too ? */
-	ret = (void *)__get_free_pages(flag, get_order(size));
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_abs(ret) | dma_direct_offset;
-	}
+	page = alloc_pages_node(node, flag, get_order(size));
+	if (page == NULL)
+		return NULL;
+	ret = page_address(page);
+	memset(ret, 0, size);
+	*dma_handle = virt_to_abs(ret) | dma_direct_offset;
+
 	return ret;
 }
 

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

* [PATCH 28/32] powerpc: Make cell use direct DMA ops
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (26 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 27/32] powerpc: Make direct DMA use node local allocations Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 29/32] powerpc: Cell iommu support Benjamin Herrenschmidt
                   ` (3 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

Now that the direct DMA ops supports an offset, we use that instead
of defining our own.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>


 arch/powerpc/platforms/cell/iommu.c |   79 ++----------------------------------
 1 file changed, 6 insertions(+), 73 deletions(-)

Index: linux-cell/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.c	2006-11-07 16:45:08.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/iommu.c	2006-11-07 16:48:00.000000000 +1100
@@ -46,8 +46,6 @@
 
 #include "iommu.h"
 
-static dma_addr_t cell_dma_valid = SPIDER_DMA_VALID;
-
 static inline unsigned long 
 get_iopt_entry(unsigned long real_address, unsigned long ioid,
 			 unsigned long prot)
@@ -417,83 +415,18 @@ static int cell_map_iommu(void)
 	return 1;
 }
 
-static void *cell_alloc_coherent(struct device *hwdev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag)
-{
-	void *ret;
-
-	ret = (void *)__get_free_pages(flag, get_order(size));
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_abs(ret) | cell_dma_valid;
-	}
-	return ret;
-}
-
-static void cell_free_coherent(struct device *hwdev, size_t size,
-				 void *vaddr, dma_addr_t dma_handle)
-{
-	free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static dma_addr_t cell_map_single(struct device *hwdev, void *ptr,
-		size_t size, enum dma_data_direction direction)
-{
-	return virt_to_abs(ptr) | cell_dma_valid;
-}
-
-static void cell_unmap_single(struct device *hwdev, dma_addr_t dma_addr,
-		size_t size, enum dma_data_direction direction)
-{
-}
-
-static int cell_map_sg(struct device *hwdev, struct scatterlist *sg,
-		int nents, enum dma_data_direction direction)
-{
-	int i;
-
-	for (i = 0; i < nents; i++, sg++) {
-		sg->dma_address = (page_to_phys(sg->page) + sg->offset)
-					| cell_dma_valid;
-		sg->dma_length = sg->length;
-	}
-
-	return nents;
-}
-
-static void cell_unmap_sg(struct device *hwdev, struct scatterlist *sg,
-		int nents, enum dma_data_direction direction)
-{
-}
-
-static int cell_dma_supported(struct device *dev, u64 mask)
-{
-	return mask < 0x100000000ull;
-}
-
-static struct dma_mapping_ops cell_iommu_ops = {
-	.alloc_coherent = cell_alloc_coherent,
-	.free_coherent = cell_free_coherent,
-	.map_single = cell_map_single,
-	.unmap_single = cell_unmap_single,
-	.map_sg = cell_map_sg,
-	.unmap_sg = cell_unmap_sg,
-	.dma_supported = cell_dma_supported,
-};
-
 void cell_init_iommu(void)
 {
 	int setup_bus = 0;
 
-	/* If we have an Axon bridge, clear the DMA valid mask. This is fairly
-	 * hackish but will work well enough until we have proper iommu code.
-	 */
-	if (of_find_node_by_name(NULL, "axon"))
-		cell_dma_valid = 0;
-
 	if (of_find_node_by_path("/mambo")) {
 		pr_info("Not using iommu on systemsim\n");
 	} else {
+		/* If we don't have an Axon bridge, we assume we have a
+		 * spider which requires a DMA offset
+		 */
+		if (of_find_node_by_name(NULL, "axon") == NULL)
+			dma_direct_offset = SPIDER_DMA_VALID;
 
 		if (!(of_chosen &&
 		      get_property(of_chosen, "linux,iommu-off", NULL)))
@@ -509,5 +442,5 @@ void cell_init_iommu(void)
 		}
 	}
 
-	pci_dma_ops = &cell_iommu_ops;
+	pci_dma_ops = &dma_direct_ops;
 }

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

* [PATCH 29/32] powerpc: Cell iommu support
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (27 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 28/32] powerpc: Make cell use direct DMA ops Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 30/32] powerpc: remove ioremap64 and fixup_bigphys_addr Benjamin Herrenschmidt
                   ` (2 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

From: Jeremy Kerr <jk@ozlabs.org>

This patch adds full cell iommu support (and iommu diabled mode).

It implements mapping/unmapping of iommu pages on demand using the
standard powerpc iommu framework. It also supports running with
iommu disabled for machines with less than 2Gb of memory. (The
default is off in that case, though it can be forced on with the
kernel command line option iommu=force).

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/prom_init.c     |   14 
 arch/powerpc/kernel/setup_64.c      |    3 
 arch/powerpc/platforms/cell/iommu.c |  995 +++++++++++++++++++++++-------------
 arch/powerpc/platforms/cell/iommu.h |   67 --
 arch/powerpc/platforms/cell/setup.c |   43 -
 arch/powerpc/sysdev/dart_iommu.c    |    3 
 include/asm-powerpc/iommu.h         |    6 
 7 files changed, 660 insertions(+), 471 deletions(-)

Index: linux-cell/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.c	2006-11-10 16:54:09.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/iommu.c	2006-11-10 17:07:48.000000000 +1100
@@ -1,446 +1,747 @@
 /*
  * IOMMU implementation for Cell Broadband Processor Architecture
- * We just establish a linear mapping at boot by setting all the
- * IOPT cache entries in the CPU.
- * The mapping functions should be identical to pci_direct_iommu, 
- * except for the handling of the high order bit that is required
- * by the Spider bridge. These should be split into a separate
- * file at the point where we get a different bridge chip.
  *
- * Copyright (C) 2005 IBM Deutschland Entwicklung GmbH,
- *			 Arnd Bergmann <arndb@de.ibm.com>
+ * (C) Copyright IBM Corporation 2006
  *
- * Based on linear mapping
- * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ * Author: Jeremy Kerr <jk@ozlabs.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 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/compiler.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
 
-#include <asm/sections.h>
-#include <asm/iommu.h>
-#include <asm/io.h>
 #include <asm/prom.h>
-#include <asm/pci-bridge.h>
+#include <asm/iommu.h>
 #include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/abs_addr.h>
-#include <asm/system.h>
-#include <asm/ppc-pci.h>
+#include <asm/pci-bridge.h>
 #include <asm/udbg.h>
+#include <asm/of_platform.h>
+#include <asm/lmb.h>
 
-#include "iommu.h"
+#include "cbe_regs.h"
+#include "interrupt.h"
 
-static inline unsigned long 
-get_iopt_entry(unsigned long real_address, unsigned long ioid,
-			 unsigned long prot)
-{
-	return (prot & IOPT_PROT_MASK)
-	     | (IOPT_COHERENT)
-	     | (IOPT_ORDER_VC)
-	     | (real_address & IOPT_RPN_MASK)
-	     | (ioid & IOPT_IOID_MASK);
-}
-
-typedef struct {
-	unsigned long val;
-} ioste;
-
-static inline ioste
-mk_ioste(unsigned long val)
-{
-	ioste ioste = { .val = val, };
-	return ioste;
-}
-
-static inline ioste
-get_iost_entry(unsigned long iopt_base, unsigned long io_address, unsigned page_size)
-{
-	unsigned long ps;
-	unsigned long iostep;
-	unsigned long nnpt;
-	unsigned long shift;
-
-	switch (page_size) {
-	case 0x1000000:
-		ps = IOST_PS_16M;
-		nnpt = 0;  /* one page per segment */
-		shift = 5; /* segment has 16 iopt entries */
-		break;
-
-	case 0x100000:
-		ps = IOST_PS_1M;
-		nnpt = 0;  /* one page per segment */
-		shift = 1; /* segment has 256 iopt entries */
-		break;
-
-	case 0x10000:
-		ps = IOST_PS_64K;
-		nnpt = 0x07; /* 8 pages per io page table */
-		shift = 0;   /* all entries are used */
-		break;
-
-	case 0x1000:
-		ps = IOST_PS_4K;
-		nnpt = 0x7f; /* 128 pages per io page table */
-		shift = 0;   /* all entries are used */
-		break;
-
-	default: /* not a known compile time constant */
-		{
-			/* BUILD_BUG_ON() is not usable here */
-			extern void __get_iost_entry_bad_page_size(void);
-			__get_iost_entry_bad_page_size();
-		}
-		break;
-	}
+/* Define CELL_IOMMU_REAL_UNMAP to actually unmap non-used pages
+ * instead of leaving them mapped to some dummy page. This can be
+ * enabled once the appropriate workarounds for spider bugs have
+ * been enabled
+ */
+#define CELL_IOMMU_REAL_UNMAP
 
-	iostep = iopt_base +
-			 /* need 8 bytes per iopte */
-			(((io_address / page_size * 8)
-			 /* align io page tables on 4k page boundaries */
-				 << shift) 
-			 /* nnpt+1 pages go into each iopt */
-				 & ~(nnpt << 12));
+/* Define CELL_IOMMU_STRICT_PROTECTION to enforce protection of
+ * IO PTEs based on the transfer direction. That can be enabled
+ * once spider-net has been fixed to pass the correct direction
+ * to the DMA mapping functions
+ */
+#define CELL_IOMMU_STRICT_PROTECTION
 
-	nnpt++; /* this seems to work, but the documentation is not clear
-		   about wether we put nnpt or nnpt-1 into the ioste bits.
-		   In theory, this can't work for 4k pages. */
-	return mk_ioste(IOST_VALID_MASK
-			| (iostep & IOST_PT_BASE_MASK)
-			| ((nnpt << 5) & IOST_NNPT_MASK)
-			| (ps & IOST_PS_MASK));
-}
 
-/* compute the address of an io pte */
-static inline unsigned long
-get_ioptep(ioste iost_entry, unsigned long io_address)
-{
-	unsigned long iopt_base;
-	unsigned long page_size;
-	unsigned long page_number;
-	unsigned long iopt_offset;
+#define NR_IOMMUS			2
 
-	iopt_base = iost_entry.val & IOST_PT_BASE_MASK;
-	page_size = iost_entry.val & IOST_PS_MASK;
+/* IOC mmap registers */
+#define IOC_Reg_Size			0x2000
 
-	/* decode page size to compute page number */
-	page_number = (io_address & 0x0fffffff) >> (10 + 2 * page_size);
-	/* page number is an offset into the io page table */
-	iopt_offset = (page_number << 3) & 0x7fff8ul;
-	return iopt_base + iopt_offset;
-}
+#define IOC_IOPT_CacheInvd		0x908
+#define IOC_IOPT_CacheInvd_NE_Mask	0xffe0000000000000ul
+#define IOC_IOPT_CacheInvd_IOPTE_Mask	0x000003fffffffff8ul
+#define IOC_IOPT_CacheInvd_Busy		0x0000000000000001ul
+
+#define IOC_IOST_Origin			0x918
+#define IOC_IOST_Origin_E		0x8000000000000000ul
+#define IOC_IOST_Origin_HW		0x0000000000000800ul
+#define IOC_IOST_Origin_HL		0x0000000000000400ul
+
+#define IOC_IO_ExcpStat			0x920
+#define IOC_IO_ExcpStat_V		0x8000000000000000ul
+#define IOC_IO_ExcpStat_SPF_Mask	0x6000000000000000ul
+#define IOC_IO_ExcpStat_SPF_S		0x6000000000000000ul
+#define IOC_IO_ExcpStat_SPF_P		0x4000000000000000ul
+#define IOC_IO_ExcpStat_ADDR_Mask	0x00000007fffff000ul
+#define IOC_IO_ExcpStat_RW_Mask		0x0000000000000800ul
+#define IOC_IO_ExcpStat_IOID_Mask	0x00000000000007fful
+
+#define IOC_IO_ExcpMask			0x928
+#define IOC_IO_ExcpMask_SFE		0x4000000000000000ul
+#define IOC_IO_ExcpMask_PFE		0x2000000000000000ul
+
+#define IOC_IOCmd_Offset		0x1000
+
+#define IOC_IOCmd_Cfg			0xc00
+#define IOC_IOCmd_Cfg_TE		0x0000800000000000ul
+
+
+/* Segment table entries */
+#define IOSTE_V			0x8000000000000000ul /* valid */
+#define IOSTE_H			0x4000000000000000ul /* cache hint */
+#define IOSTE_PT_Base_RPN_Mask  0x3ffffffffffff000ul /* base RPN of IOPT */
+#define IOSTE_NPPT_Mask		0x0000000000000fe0ul /* no. pages in IOPT */
+#define IOSTE_PS_Mask		0x0000000000000007ul /* page size */
+#define IOSTE_PS_4K		0x0000000000000001ul /*   - 4kB  */
+#define IOSTE_PS_64K		0x0000000000000003ul /*   - 64kB */
+#define IOSTE_PS_1M		0x0000000000000005ul /*   - 1MB  */
+#define IOSTE_PS_16M		0x0000000000000007ul /*   - 16MB */
+
+/* Page table entries */
+#define IOPTE_PP_W		0x8000000000000000ul /* protection: write */
+#define IOPTE_PP_R		0x4000000000000000ul /* protection: read */
+#define IOPTE_M			0x2000000000000000ul /* coherency required */
+#define IOPTE_SO_R		0x1000000000000000ul /* ordering: writes */
+#define IOPTE_SO_RW             0x1800000000000000ul /* ordering: r & w */
+#define IOPTE_RPN_Mask		0x07fffffffffff000ul /* RPN */
+#define IOPTE_H			0x0000000000000800ul /* cache hint */
+#define IOPTE_IOID_Mask		0x00000000000007fful /* ioid */
+
+
+/* IOMMU sizing */
+#define IO_SEGMENT_SHIFT	28
+#define IO_PAGENO_BITS		(IO_SEGMENT_SHIFT - IOMMU_PAGE_SHIFT)
+
+/* The high bit needs to be set on every DMA address */
+#define SPIDER_DMA_OFFSET	0x80000000ul
+
+struct iommu_window {
+	struct list_head list;
+	struct cbe_iommu *iommu;
+	unsigned long offset;
+	unsigned long size;
+	unsigned long pte_offset;
+	unsigned int ioid;
+	struct iommu_table table;
+};
 
-/* compute the tag field of the iopt cache entry */
-static inline unsigned long
-get_ioc_tag(ioste iost_entry, unsigned long io_address)
-{
-	unsigned long iopte = get_ioptep(iost_entry, io_address);
+#define NAMESIZE 8
+struct cbe_iommu {
+	int nid;
+	char name[NAMESIZE];
+	void __iomem *xlate_regs;
+	void __iomem *cmd_regs;
+	unsigned long *stab;
+	unsigned long *ptab;
+	void *pad_page;
+	struct list_head windows;
+};
 
-	return IOPT_VALID_MASK
-	     | ((iopte & 0x00000000000000ff8ul) >> 3)
-	     | ((iopte & 0x0000003fffffc0000ul) >> 9);
-}
+/* Static array of iommus, one per node
+ *   each contains a list of windows, keyed from dma_window property
+ *   - on bus setup, look for a matching window, or create one
+ *   - on dev setup, assign iommu_table ptr
+ */
+static struct cbe_iommu iommus[NR_IOMMUS];
+static int cbe_nr_iommus;
 
-/* compute the hashed 6 bit index for the 4-way associative pte cache */
-static inline unsigned long
-get_ioc_hash(ioste iost_entry, unsigned long io_address)
+static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte,
+		long n_ptes)
 {
-	unsigned long iopte = get_ioptep(iost_entry, io_address);
+	unsigned long *reg, val;
+	long n;
+
+	reg = iommu->xlate_regs + IOC_IOPT_CacheInvd;
+
+	while (n_ptes > 0) {
+		/* we can invalidate up to 1 << 11 PTEs at once */
+		n = min(n_ptes, 1l << 11);
+		val = (((n /*- 1*/) << 53) & IOC_IOPT_CacheInvd_NE_Mask)
+			| (__pa(pte) & IOC_IOPT_CacheInvd_IOPTE_Mask)
+		        | IOC_IOPT_CacheInvd_Busy;
+
+		out_be64(reg, val);
+		while (in_be64(reg) & IOC_IOPT_CacheInvd_Busy)
+			;
 
-	return ((iopte & 0x000000000000001f8ul) >> 3)
-	     ^ ((iopte & 0x00000000000020000ul) >> 17)
-	     ^ ((iopte & 0x00000000000010000ul) >> 15)
-	     ^ ((iopte & 0x00000000000008000ul) >> 13)
-	     ^ ((iopte & 0x00000000000004000ul) >> 11)
-	     ^ ((iopte & 0x00000000000002000ul) >> 9)
-	     ^ ((iopte & 0x00000000000001000ul) >> 7);
+		n_ptes -= n;
+		pte += n;
+	}
 }
 
-/* same as above, but pretend that we have a simpler 1-way associative
-   pte cache with an 8 bit index */
-static inline unsigned long
-get_ioc_hash_1way(ioste iost_entry, unsigned long io_address)
+static void tce_build_cell(struct iommu_table *tbl, long index, long npages,
+		unsigned long uaddr, enum dma_data_direction direction)
 {
-	unsigned long iopte = get_ioptep(iost_entry, io_address);
+	int i;
+	unsigned long *io_pte, base_pte;
+	struct iommu_window *window =
+		container_of(tbl, struct iommu_window, table);
 
-	return ((iopte & 0x000000000000001f8ul) >> 3)
-	     ^ ((iopte & 0x00000000000020000ul) >> 17)
-	     ^ ((iopte & 0x00000000000010000ul) >> 15)
-	     ^ ((iopte & 0x00000000000008000ul) >> 13)
-	     ^ ((iopte & 0x00000000000004000ul) >> 11)
-	     ^ ((iopte & 0x00000000000002000ul) >> 9)
-	     ^ ((iopte & 0x00000000000001000ul) >> 7)
-	     ^ ((iopte & 0x0000000000000c000ul) >> 8);
-}
+	/* implementing proper protection causes problems with the spidernet
+	 * driver - check mapping directions later, but allow read & write by
+	 * default for now.*/
+#ifdef CELL_IOMMU_STRICT_PROTECTION
+	/* to avoid referencing a global, we use a trick here to setup the
+	 * protection bit. "prot" is setup to be 3 fields of 4 bits apprended
+	 * together for each of the 3 supported direction values. It is then
+	 * shifted left so that the fields matching the desired direction
+	 * lands on the appropriate bits, and other bits are masked out.
+	 */
+	const unsigned long prot = 0xc48;
+	base_pte =
+		((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R))
+		| IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask);
+#else
+	base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW |
+		(window->ioid & IOPTE_IOID_Mask);
+#endif
 
-static inline ioste
-get_iost_cache(void __iomem *base, unsigned long index)
-{
-	unsigned long __iomem *p = (base + IOC_ST_CACHE_DIR);
-	return mk_ioste(in_be64(&p[index]));
-}
+	io_pte = (unsigned long *)tbl->it_base + (index - window->pte_offset);
 
-static inline void
-set_iost_cache(void __iomem *base, unsigned long index, ioste ste)
-{
-	unsigned long __iomem *p = (base + IOC_ST_CACHE_DIR);
-	pr_debug("ioste %02lx was %016lx, store %016lx", index,
-			get_iost_cache(base, index).val, ste.val);
-	out_be64(&p[index], ste.val);
-	pr_debug(" now %016lx\n", get_iost_cache(base, index).val);
-}
+	for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
+		io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
 
-static inline unsigned long
-get_iopt_cache(void __iomem *base, unsigned long index, unsigned long *tag)
-{
-	unsigned long __iomem *tags = (void *)(base + IOC_PT_CACHE_DIR);
-	unsigned long __iomem *p = (void *)(base + IOC_PT_CACHE_REG);	
+	mb();
+
+	invalidate_tce_cache(window->iommu, io_pte, npages);
 
-	*tag = tags[index];
-	rmb();
-	return *p;
+	pr_debug("tce_build_cell(index=%lx,n=%lx,dir=%d,base_pte=%lx)\n",
+		 index, npages, direction, base_pte);
 }
 
-static inline void
-set_iopt_cache(void __iomem *base, unsigned long index,
-		 unsigned long tag, unsigned long val)
+static void tce_free_cell(struct iommu_table *tbl, long index, long npages)
 {
-	unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR;
-	unsigned long __iomem *p = base + IOC_PT_CACHE_REG;
 
-	out_be64(p, val);
-	out_be64(&tags[index], tag);
-}
+	int i;
+	unsigned long *io_pte, pte;
+	struct iommu_window *window =
+		container_of(tbl, struct iommu_window, table);
 
-static inline void
-set_iost_origin(void __iomem *base)
-{
-	unsigned long __iomem *p = base + IOC_ST_ORIGIN;
-	unsigned long origin = IOSTO_ENABLE | IOSTO_SW;
+	pr_debug("tce_free_cell(index=%lx,n=%lx)\n", index, npages);
 
-	pr_debug("iost_origin %016lx, now %016lx\n", in_be64(p), origin);
-	out_be64(p, origin);
-}
+#ifdef CELL_IOMMU_REAL_UNMAP
+	pte = 0;
+#else
+	/* spider bridge does PCI reads after freeing - insert a mapping
+	 * to a scratch page instead of an invalid entry */
+	pte = IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | __pa(window->iommu->pad_page)
+		| (window->ioid & IOPTE_IOID_Mask);
+#endif
 
-static inline void
-set_iocmd_config(void __iomem *base)
-{
-	unsigned long __iomem *p = base + 0xc00;
-	unsigned long conf;
+	io_pte = (unsigned long *)tbl->it_base + (index - window->pte_offset);
 
-	conf = in_be64(p);
-	pr_debug("iost_conf %016lx, now %016lx\n", conf, conf | IOCMD_CONF_TE);
-	out_be64(p, conf | IOCMD_CONF_TE);
+	for (i = 0; i < npages; i++)
+		io_pte[i] = pte;
+
+	mb();
+
+	invalidate_tce_cache(window->iommu, io_pte, npages);
 }
 
-static void enable_mapping(void __iomem *base, void __iomem *mmio_base)
+static irqreturn_t ioc_interrupt(int irq, void *data)
 {
-	set_iocmd_config(base);
-	set_iost_origin(mmio_base);
+	unsigned long stat;
+	struct cbe_iommu *iommu = data;
+
+	stat = in_be64(iommu->xlate_regs + IOC_IO_ExcpStat);
+
+	/* Might want to rate limit it */
+	printk(KERN_ERR "iommu: DMA exception 0x%016lx\n", stat);
+	printk(KERN_ERR "  V=%d, SPF=[%c%c], RW=%s, IOID=0x%04x\n",
+	       !!(stat & IOC_IO_ExcpStat_V),
+	       (stat & IOC_IO_ExcpStat_SPF_S) ? 'S' : ' ',
+	       (stat & IOC_IO_ExcpStat_SPF_P) ? 'P' : ' ',
+	       (stat & IOC_IO_ExcpStat_RW_Mask) ? "Read" : "Write",
+	       (unsigned int)(stat & IOC_IO_ExcpStat_IOID_Mask));
+	printk(KERN_ERR "  page=0x%016lx\n",
+	       stat & IOC_IO_ExcpStat_ADDR_Mask);
+
+	/* clear interrupt */
+	stat &= ~IOC_IO_ExcpStat_V;
+	out_be64(iommu->xlate_regs + IOC_IO_ExcpStat, stat);
+
+	return IRQ_HANDLED;
 }
 
-struct cell_iommu {
-	unsigned long base;
-	unsigned long mmio_base;
-	void __iomem *mapped_base;
-	void __iomem *mapped_mmio_base;
-};
+static int cell_iommu_find_ioc(int nid, unsigned long *base)
+{
+	struct device_node *np;
+	struct resource r;
 
-static struct cell_iommu cell_iommus[NR_CPUS];
+	*base = 0;
 
-/* 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_do_map_iommu(struct cell_iommu *iommu,
-			      unsigned int ioid,
-			      unsigned long map_start,
-			      unsigned long map_size)
-{
-	unsigned long io_address, real_address;
-	void __iomem *ioc_base, *ioc_mmio_base;
-	ioste ioste;
-	unsigned long index;
+	/* First look for new style /be nodes */
+	for_each_node_by_name(np, "ioc") {
+		if (of_node_to_nid(np) != nid)
+			continue;
+		if (of_address_to_resource(np, 0, &r)) {
+			printk(KERN_ERR "iommu: can't get address for %s\n",
+			       np->full_name);
+			continue;
+		}
+		*base = r.start;
+		of_node_put(np);
+		return 0;
+	}
 
-	/* 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 */
-
-	ioc_base = iommu->mapped_base;
-	ioc_mmio_base = iommu->mapped_mmio_base;
-
-	for (real_address = 0, io_address = map_start;
-	     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",
-					 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, ioid, IOPT_PROT_RW));
+	/* Ok, let's try the old way */
+	for_each_node_by_type(np, "cpu") {
+		const unsigned int *nidp;
+		const unsigned long *tmp;
+
+		nidp = get_property(np, "node-id", NULL);
+		if (nidp && *nidp == nid) {
+			tmp = get_property(np, "ioc-translation", NULL);
+			if (tmp) {
+				*base = *tmp;
+				of_node_put(np);
+				return 0;
+			}
+		}
 	}
+
+	return -ENODEV;
 }
 
-static void pci_dma_cell_bus_setup(struct pci_bus *b)
+static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long size)
 {
-	const unsigned int *ioid;
-	unsigned long map_start, map_size, token;
-	const unsigned long *dma_window;
-	struct cell_iommu *iommu;
-	struct device_node *d;
+	struct page *page;
+	int ret, i;
+	unsigned long reg, segments, pages_per_segment, ptab_size, n_pte_pages;
+	unsigned long xlate_base;
+	unsigned int virq;
+
+	if (cell_iommu_find_ioc(iommu->nid, &xlate_base))
+		panic("%s: missing IOC register mappings for node %d\n",
+		      __FUNCTION__, iommu->nid);
+
+	iommu->xlate_regs = ioremap(xlate_base, IOC_Reg_Size);
+	iommu->cmd_regs = iommu->xlate_regs + IOC_IOCmd_Offset;
+
+	segments = size >> IO_SEGMENT_SHIFT;
+	pages_per_segment = 1ull << IO_PAGENO_BITS;
+
+	pr_debug("%s: iommu[%d]: segments: %lu, pages per segment: %lu\n",
+			__FUNCTION__, iommu->nid, segments, pages_per_segment);
+
+	/* set up the segment table */
+	page = alloc_pages_node(iommu->nid, GFP_KERNEL, 0);
+	BUG_ON(!page);
+	iommu->stab = page_address(page);
+	clear_page(iommu->stab);
+
+	/* ... and the page tables. Since these are contiguous, we can treat
+	 * the page tables as one array of ptes, like pSeries does.
+	 */
+	ptab_size = segments * pages_per_segment * sizeof(unsigned long);
+	pr_debug("%s: iommu[%d]: ptab_size: %lu, order: %d\n", __FUNCTION__,
+			iommu->nid, ptab_size, get_order(ptab_size));
+	page = alloc_pages_node(iommu->nid, GFP_KERNEL, get_order(ptab_size));
+	BUG_ON(!page);
+
+	iommu->ptab = page_address(page);
+	memset(iommu->ptab, 0, ptab_size);
+
+	/* allocate a bogus page for the end of each mapping */
+	page = alloc_pages_node(iommu->nid, GFP_KERNEL, 0);
+	BUG_ON(!page);
+	iommu->pad_page = page_address(page);
+	clear_page(iommu->pad_page);
+
+	/* number of pages needed for a page table */
+	n_pte_pages = (pages_per_segment *
+		       sizeof(unsigned long)) >> IOMMU_PAGE_SHIFT;
+
+	pr_debug("%s: iommu[%d]: stab at %p, ptab at %p, n_pte_pages: %lu\n",
+			__FUNCTION__, iommu->nid, iommu->stab, iommu->ptab,
+			n_pte_pages);
+
+	/* initialise the STEs */
+	reg = IOSTE_V | ((n_pte_pages - 1) << 5);
+
+	if (IOMMU_PAGE_SIZE == 0x1000)
+		reg |= IOSTE_PS_4K;
+	else if (IOMMU_PAGE_SIZE == 0x10000)
+		reg |= IOSTE_PS_64K;
+	else {
+		extern void __unknown_page_size_error(void);
+		__unknown_page_size_error();
+	}
+
+	pr_debug("Setting up IOMMU stab:\n");
+	for (i = 0; i * (1ul << IO_SEGMENT_SHIFT) < size; i++) {
+		iommu->stab[i] = reg |
+			(__pa(iommu->ptab) + n_pte_pages * IOMMU_PAGE_SIZE * i);
+		pr_debug("\t[%d] 0x%016lx\n", i, iommu->stab[i]);
+	}
 
-	d = pci_bus_to_OF_node(b);
+	/* ensure that the STEs have updated */
+	mb();
 
-	ioid = get_property(d, "ioid", NULL);
-	if (!ioid)
-		pr_debug("No ioid entry found !\n");
+	/* setup interrupts for the iommu. */
+	reg = in_be64(iommu->xlate_regs + IOC_IO_ExcpStat);
+	out_be64(iommu->xlate_regs + IOC_IO_ExcpStat,
+			reg & ~IOC_IO_ExcpStat_V);
+	out_be64(iommu->xlate_regs + IOC_IO_ExcpMask,
+			IOC_IO_ExcpMask_PFE | IOC_IO_ExcpMask_SFE);
 
-	dma_window = get_property(d, "ibm,dma-window", NULL);
-	if (!dma_window)
-		pr_debug("No ibm,dma-window entry found !\n");
+	virq = irq_create_mapping(NULL,
+			IIC_IRQ_IOEX_ATI | (iommu->nid << IIC_IRQ_NODE_SHIFT));
+	BUG_ON(virq == NO_IRQ);
 
-	map_start = dma_window[1];
-	map_size = dma_window[2];
-	token = dma_window[0] >> 32;
+	ret = request_irq(virq, ioc_interrupt, IRQF_DISABLED,
+			iommu->name, iommu);
+	BUG_ON(ret);
 
-	iommu = &cell_iommus[token];
+	/* set the IOC segment table origin register (and turn on the iommu) */
+	reg = IOC_IOST_Origin_E | __pa(iommu->stab) | IOC_IOST_Origin_HW;
+	out_be64(iommu->xlate_regs + IOC_IOST_Origin, reg);
+	in_be64(iommu->xlate_regs + IOC_IOST_Origin);
 
-	cell_do_map_iommu(iommu, *ioid, map_start, map_size);
+	/* turn on IO translation */
+	reg = in_be64(iommu->cmd_regs + IOC_IOCmd_Cfg) | IOC_IOCmd_Cfg_TE;
+	out_be64(iommu->cmd_regs + IOC_IOCmd_Cfg, reg);
 }
 
+#if 0/* Unused for now */
+static struct iommu_window *find_window(struct cbe_iommu *iommu,
+		unsigned long offset, unsigned long size)
+{
+	struct iommu_window *window;
+
+	/* todo: check for overlapping (but not equal) windows) */
 
-static int cell_map_iommu_hardcoded(int num_nodes)
+	list_for_each_entry(window, &(iommu->windows), list) {
+		if (window->offset == offset && window->size == size)
+			return window;
+	}
+
+	return NULL;
+}
+#endif
+
+static struct iommu_window * __init
+cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
+			unsigned long offset, unsigned long size,
+			unsigned long pte_offset)
 {
-	struct cell_iommu *iommu = NULL;
+	struct iommu_window *window;
+	const unsigned int *ioid;
 
-	pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
+	ioid = get_property(np, "ioid", NULL);
+	if (ioid == NULL)
+		printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
+		       np->full_name);
+
+	window = kmalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid);
+	BUG_ON(window == NULL);
+
+	window->offset = offset;
+	window->size = size;
+	window->ioid = ioid ? *ioid : 0;
+	window->iommu = iommu;
+	window->pte_offset = pte_offset;
+
+	window->table.it_blocksize = 16;
+	window->table.it_base = (unsigned long)iommu->ptab;
+	window->table.it_index = iommu->nid;
+	window->table.it_offset = (offset >> IOMMU_PAGE_SHIFT) +
+		window->pte_offset;
+	window->table.it_size = size >> IOMMU_PAGE_SHIFT;
+
+	iommu_init_table(&window->table, iommu->nid);
+
+	pr_debug("\tioid      %d\n", window->ioid);
+	pr_debug("\tblocksize %ld\n", window->table.it_blocksize);
+	pr_debug("\tbase      0x%016lx\n", window->table.it_base);
+	pr_debug("\toffset    0x%lx\n", window->table.it_offset);
+	pr_debug("\tsize      %ld\n", window->table.it_size);
+
+	list_add(&window->list, &iommu->windows);
+
+	if (offset != 0)
+		return window;
+
+	/* We need to map and reserve the first IOMMU page since it's used
+	 * by the spider workaround. In theory, we only need to do that when
+	 * running on spider but it doesn't really matter.
+	 *
+	 * This code also assumes that we have a window that starts at 0,
+	 * which is the case on all spider based blades.
+	 */
+	__set_bit(0, window->table.it_map);
+	tce_build_cell(&window->table, window->table.it_offset, 1,
+		       (unsigned long)iommu->pad_page, DMA_TO_DEVICE);
+	window->table.it_hint = window->table.it_blocksize;
+
+	return window;
+}
+
+static struct cbe_iommu *cell_iommu_for_node(int nid)
+{
+	int i;
+
+	for (i = 0; i < cbe_nr_iommus; i++)
+		if (iommus[i].nid == nid)
+			return &iommus[i];
+	return NULL;
+}
+
+static void cell_dma_dev_setup(struct device *dev)
+{
+	struct iommu_window *window;
+	struct cbe_iommu *iommu;
+	struct dev_sysdata *sysdata = &dev->sysdata;
+
+	/* If we run without iommu, no need to do anything */
+	if (pci_dma_ops == &dma_direct_ops)
+		return;
+
+	/* Current implementation uses the first window available in that
+	 * node's iommu. We -might- do something smarter later though it may
+	 * never be necessary
+	 */
+	iommu = cell_iommu_for_node(sysdata->numa_node);
+	if (iommu == NULL || list_empty(&iommu->windows)) {
+		printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n",
+		       sysdata->of_node ? sysdata->of_node->full_name : "?",
+		       sysdata->numa_node);
+		return;
+	}
+	window = list_entry(iommu->windows.next, struct iommu_window, list);
 
-	/* node 0 */
-	iommu = &cell_iommus[0];
-	iommu->mapped_base = ioremap(0x20000511000ul, 0x1000);
-	iommu->mapped_mmio_base = ioremap(0x20000510000ul, 0x1000);
+	sysdata->dma_data = &window->table;
+}
 
-	enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+static void cell_pci_dma_dev_setup(struct pci_dev *dev)
+{
+	cell_dma_dev_setup(&dev->dev);
+}
 
-	cell_do_map_iommu(iommu, 0x048a,
-			  0x20000000ul,0x20000000ul);
+static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action,
+			      void *data)
+{
+	struct device *dev = data;
 
-	if (num_nodes < 2)
+	/* We are only intereted in device addition */
+	if (action != BUS_NOTIFY_ADD_DEVICE)
 		return 0;
 
-	/* node 1 */
-	iommu = &cell_iommus[1];
-	iommu->mapped_base = ioremap(0x30000511000ul, 0x1000);
-	iommu->mapped_mmio_base = ioremap(0x30000510000ul, 0x1000);
-
-	enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+	/* We use the PCI DMA ops */
+	dev->sysdata.dma_ops = pci_dma_ops;
 
-	cell_do_map_iommu(iommu, 0x048a,
-			  0x20000000,0x20000000ul);
+	cell_dma_dev_setup(dev);
 
 	return 0;
 }
 
+static struct notifier_block cell_of_bus_notifier = {
+	.notifier_call = cell_of_bus_notify
+};
 
-static int cell_map_iommu(void)
+static int __init cell_iommu_get_window(struct device_node *np,
+					 unsigned long *base,
+					 unsigned long *size)
 {
-	unsigned int num_nodes = 0;
-	const unsigned int *node_id;
-	const 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 = get_property(dn, "node-id", NULL);
+	const void *dma_window;
+	unsigned long index;
 
-		if (num_nodes < *node_id)
-			num_nodes = *node_id;
-		}
+	/* Use ibm,dma-window if available, else, hard code ! */
+	dma_window = get_property(np, "ibm,dma-window", NULL);
+	if (dma_window == NULL) {
+		*base = 0;
+		*size = 0x80000000u;
+		return -ENODEV;
+	}
 
-	num_nodes++;
-	pr_debug("%i found.\n", num_nodes);
+	of_parse_dma_window(np, dma_window, &index, base, size);
+	return 0;
+}
 
-	/* 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")) {
+static void __init cell_iommu_init_one(struct device_node *np, unsigned long offset)
+{
+	struct cbe_iommu *iommu;
+	unsigned long base, size;
+	int nid, i;
+
+	/* Get node ID */
+	nid = of_node_to_nid(np);
+	if (nid < 0) {
+		printk(KERN_ERR "iommu: failed to get node for %s\n",
+		       np->full_name);
+		return;
+	}
+	pr_debug("iommu: setting up iommu for node %d (%s)\n",
+		 nid, np->full_name);
 
-		node_id = get_property(dn, "node-id", NULL);
-		base = get_property(dn, "ioc-cache", NULL);
-		mmio_base = get_property(dn, "ioc-translation", NULL);
+	/* XXX todo: If we can have multiple windows on the same IOMMU, which
+	 * isn't the case today, we probably want here to check wether the
+	 * iommu for that node is already setup.
+	 * However, there might be issue with getting the size right so let's
+	 * ignore that for now. We might want to completely get rid of the
+	 * multiple window support since the cell iommu supports per-page ioids
+	 */
+
+	if (cbe_nr_iommus >= NR_IOMMUS) {
+		printk(KERN_ERR "iommu: too many IOMMUs detected ! (%s)\n",
+		       np->full_name);
+		return;
+	}
 
-		if (!base || !mmio_base || !node_id)
-			return cell_map_iommu_hardcoded(num_nodes);
+	/* Init base fields */
+	i = cbe_nr_iommus++;
+	iommu = &iommus[i];
+	iommu->stab = 0;
+	iommu->nid = nid;
+	snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i);
+	INIT_LIST_HEAD(&iommu->windows);
+
+	/* Obtain a window for it */
+	cell_iommu_get_window(np, &base, &size);
+
+	pr_debug("\ttranslating window 0x%lx...0x%lx\n",
+		 base, base + size - 1);
+
+	/* Initialize the hardware */
+	cell_iommu_setup_hardware(iommu, size);
+
+	/* Setup the iommu_table */
+	cell_iommu_setup_window(iommu, np, base, size,
+				offset >> IOMMU_PAGE_SHIFT);
+}
+
+static void __init cell_disable_iommus(void)
+{
+	int node;
+	unsigned long base, val;
+	void __iomem *xregs, *cregs;
+
+	/* Make sure IOC translation is disabled on all nodes */
+	for_each_online_node(node) {
+		if (cell_iommu_find_ioc(node, &base))
+			continue;
+		xregs = ioremap(base, IOC_Reg_Size);
+		if (xregs == NULL)
+			continue;
+		cregs = xregs + IOC_IOCmd_Offset;
+
+		pr_debug("iommu: cleaning up iommu on node %d\n", node);
+
+		out_be64(xregs + IOC_IOST_Origin, 0);
+		(void)in_be64(xregs + IOC_IOST_Origin);
+		val = in_be64(cregs + IOC_IOCmd_Cfg);
+		val &= ~IOC_IOCmd_Cfg_TE;
+		out_be64(cregs + IOC_IOCmd_Cfg, val);
+		(void)in_be64(cregs + IOC_IOCmd_Cfg);
 
-		iommu = &cell_iommus[*node_id];
-		iommu->base = *base;
-		iommu->mmio_base = *mmio_base;
+		iounmap(xregs);
+	}
+}
 
-		iommu->mapped_base = ioremap(*base, 0x1000);
-		iommu->mapped_mmio_base = ioremap(*mmio_base, 0x1000);
+static int __init cell_iommu_init_disabled(void)
+{
+	struct device_node *np = NULL;
+	unsigned long base = 0, size;
 
-		enable_mapping(iommu->mapped_base,
-			       iommu->mapped_mmio_base);
+	/* When no iommu is present, we use direct DMA ops */
+	pci_dma_ops = &dma_direct_ops;
+
+	/* First make sure all IOC translation is turned off */
+	cell_disable_iommus();
+
+	/* If we have no Axon, we set up the spider DMA magic offset */
+	if (of_find_node_by_name(NULL, "axon") == NULL)
+		dma_direct_offset = SPIDER_DMA_OFFSET;
+
+	/* Now we need to check to see where the memory is mapped
+	 * in PCI space. We assume that all busses use the same dma
+	 * window which is always the case so far on Cell, thus we
+	 * pick up the first pci-internal node we can find and check
+	 * the DMA window from there.
+	 */
+	for_each_node_by_name(np, "axon") {
+		if (np->parent == NULL || np->parent->parent != NULL)
+			continue;
+		if (cell_iommu_get_window(np, &base, &size) == 0)
+			break;
+	}
+	if (np == NULL) {
+		for_each_node_by_name(np, "pci-internal") {
+			if (np->parent == NULL || np->parent->parent != NULL)
+				continue;
+			if (cell_iommu_get_window(np, &base, &size) == 0)
+				break;
+		}
+	}
+	of_node_put(np);
 
-		/* everything else will be done in iommu_bus_setup */
+	/* If we found a DMA window, we check if it's big enough to enclose
+	 * all of physical memory. If not, we force enable IOMMU
+	 */
+	if (np && size < lmb_end_of_DRAM()) {
+		printk(KERN_WARNING "iommu: force-enabled, dma window"
+		       " (%ldMB) smaller than total memory (%ldMB)\n",
+		       size >> 20, lmb_end_of_DRAM() >> 20);
+		return -ENODEV;
 	}
 
-	return 1;
+	dma_direct_offset += base;
+
+	printk("iommu: disabled, direct DMA offset is 0x%lx\n",
+	       dma_direct_offset);
+
+	return 0;
 }
 
-void cell_init_iommu(void)
+static int __init cell_iommu_init(void)
 {
-	int setup_bus = 0;
+	struct device_node *np;
 
-	if (of_find_node_by_path("/mambo")) {
-		pr_info("Not using iommu on systemsim\n");
-	} else {
-		/* If we don't have an Axon bridge, we assume we have a
-		 * spider which requires a DMA offset
-		 */
-		if (of_find_node_by_name(NULL, "axon") == NULL)
-			dma_direct_offset = SPIDER_DMA_VALID;
+	if (!machine_is(cell))
+		return -ENODEV;
 
-		if (!(of_chosen &&
-		      get_property(of_chosen, "linux,iommu-off", NULL)))
-			setup_bus = cell_map_iommu();
+	/* If IOMMU is disabled or we have little enough RAM to not need
+	 * to enable it, we setup a direct mapping.
+	 *
+	 * Note: should we make sure we have the IOMMU actually disabled ?
+	 */
+	if (iommu_is_off ||
+	    (!iommu_force_on && lmb_end_of_DRAM() <= 0x80000000ull))
+		if (cell_iommu_init_disabled() == 0)
+			goto bail;
+
+	/* Setup various ppc_md. callbacks */
+	ppc_md.pci_dma_dev_setup = cell_pci_dma_dev_setup;
+	ppc_md.tce_build = tce_build_cell;
+	ppc_md.tce_free = tce_free_cell;
+
+	/* Create an iommu for each /axon node.  */
+	for_each_node_by_name(np, "axon") {
+		if (np->parent == NULL || np->parent->parent != NULL)
+			continue;
+		cell_iommu_init_one(np, 0);
+	}
 
-		if (setup_bus) {
-			pr_debug("%s: IOMMU mapping activated\n", __FUNCTION__);
-			ppc_md.pci_dma_bus_setup = pci_dma_cell_bus_setup;
-		} else {
-			pr_debug("%s: IOMMU mapping activated, "
-				 "no device action necessary\n", __FUNCTION__);
-			/* Direct I/O, IOMMU off */
-		}
+	/* Create an iommu for each toplevel /pci-internal node for
+	 * old hardware/firmware
+	 */
+	for_each_node_by_name(np, "pci-internal") {
+		if (np->parent == NULL || np->parent->parent != NULL)
+			continue;
+		cell_iommu_init_one(np, SPIDER_DMA_OFFSET);
 	}
 
-	pci_dma_ops = &dma_direct_ops;
+	/* Setup default PCI iommu ops */
+	pci_dma_ops = &dma_iommu_ops;
+
+ bail:
+	/* Register callbacks on OF platform device addition/removal
+	 * to handle linking them to the right DMA operations
+	 */
+	register_bus_notifier(&of_platform_bus_type, &cell_of_bus_notifier);
+
+	return 0;
 }
+arch_initcall(cell_iommu_init);
+
Index: linux-cell/arch/powerpc/platforms/cell/iommu.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.h	2006-11-10 16:53:06.000000000 +1100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,67 +0,0 @@
-#ifndef CELL_IOMMU_H
-#define CELL_IOMMU_H
-
-/* some constants */
-enum {
-	/* segment table entries */
-	IOST_VALID_MASK	  = 0x8000000000000000ul,
-	IOST_TAG_MASK     = 0x3000000000000000ul,
-	IOST_PT_BASE_MASK = 0x000003fffffff000ul,
-	IOST_NNPT_MASK	  = 0x0000000000000fe0ul,
-	IOST_PS_MASK	  = 0x000000000000000ful,
-
-	IOST_PS_4K	  = 0x1,
-	IOST_PS_64K	  = 0x3,
-	IOST_PS_1M	  = 0x5,
-	IOST_PS_16M	  = 0x7,
-
-	/* iopt tag register */
-	IOPT_VALID_MASK   = 0x0000000200000000ul,
-	IOPT_TAG_MASK	  = 0x00000001fffffffful,
-
-	/* iopt cache register */
-	IOPT_PROT_MASK	  = 0xc000000000000000ul,
-	IOPT_PROT_NONE	  = 0x0000000000000000ul,
-	IOPT_PROT_READ	  = 0x4000000000000000ul,
-	IOPT_PROT_WRITE	  = 0x8000000000000000ul,
-	IOPT_PROT_RW	  = 0xc000000000000000ul,
-	IOPT_COHERENT	  = 0x2000000000000000ul,
-	
-	IOPT_ORDER_MASK	  = 0x1800000000000000ul,
-	/* order access to same IOID/VC on same address */
-	IOPT_ORDER_ADDR	  = 0x0800000000000000ul,
-	/* similar, but only after a write access */
-	IOPT_ORDER_WRITES = 0x1000000000000000ul,
-	/* Order all accesses to same IOID/VC */
-	IOPT_ORDER_VC	  = 0x1800000000000000ul,
-	
-	IOPT_RPN_MASK	  = 0x000003fffffff000ul,
-	IOPT_HINT_MASK	  = 0x0000000000000800ul,
-	IOPT_IOID_MASK	  = 0x00000000000007fful,
-
-	IOSTO_ENABLE	  = 0x8000000000000000ul,
-	IOSTO_ORIGIN	  = 0x000003fffffff000ul,
-	IOSTO_HW	  = 0x0000000000000800ul,
-	IOSTO_SW	  = 0x0000000000000400ul,
-
-	IOCMD_CONF_TE	  = 0x0000800000000000ul,
-
-	/* memory mapped registers */
-	IOC_PT_CACHE_DIR  = 0x000,
-	IOC_ST_CACHE_DIR  = 0x800,
-	IOC_PT_CACHE_REG  = 0x910,
-	IOC_ST_ORIGIN     = 0x918,
-	IOC_CONF	  = 0x930,
-
-	/* The high bit needs to be set on every DMA address when using
-	 * a spider bridge and only 2GB are addressable with the current
-	 * iommu code.
-	 */
-	SPIDER_DMA_VALID  = 0x80000000,
-	CELL_DMA_MASK	  = 0x7fffffff,
-};
-
-
-void cell_init_iommu(void);
-
-#endif
Index: linux-cell/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/setup.c	2006-11-10 16:53:06.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/setup.c	2006-11-10 16:54:10.000000000 +1100
@@ -30,7 +30,6 @@
 #include <linux/console.h>
 #include <linux/mutex.h>
 #include <linux/memory_hotplug.h>
-#include <linux/notifier.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -55,7 +54,6 @@
 #include <asm/of_platform.h>
 
 #include "interrupt.h"
-#include "iommu.h"
 #include "cbe_regs.h"
 #include "pervasive.h"
 #include "ras.h"
@@ -83,38 +81,11 @@ static void cell_progress(char *s, unsig
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
-static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action,
-			      void *data)
-{
-	struct device *dev = data;
-
-	if (action != BUS_NOTIFY_ADD_DEVICE)
-		return 0;
-
-	/* For now, we just use the PCI DMA ops for everything, though
-	 * we'll need something better when we have a real iommu
-	 * implementation.
-	 */
-	dev->sysdata.dma_ops = pci_dma_ops;
-
-	return 0;
-}
-
-static struct notifier_block cell_of_bus_notifier = {
-	.notifier_call = cell_of_bus_notify
-};
-
-
 static int __init cell_publish_devices(void)
 {
 	if (!machine_is(cell))
 		return 0;
 
-	/* Register callbacks on OF platform device addition/removal
-	 * to handle linking them to the right DMA operations
-	 */
-	register_bus_notifier(&of_platform_bus_type, &cell_of_bus_notifier);
-
 	/* Publish OF platform devices for southbridge IOs */
 	of_platform_bus_probe(NULL, NULL, NULL);
 
@@ -205,19 +176,6 @@ static void __init cell_setup_arch(void)
 	mmio_nvram_init();
 }
 
-/*
- * Early initialization.  Relocation is on but do not reference unbolted pages
- */
-static void __init cell_init_early(void)
-{
-	DBG(" -> cell_init_early()\n");
-
-	cell_init_iommu();
-
-	DBG(" <- cell_init_early()\n");
-}
-
-
 static int __init cell_probe(void)
 {
 	unsigned long root = of_get_flat_dt_root();
@@ -244,7 +202,6 @@ define_machine(cell) {
 	.name			= "Cell",
 	.probe			= cell_probe,
 	.setup_arch		= cell_setup_arch,
-	.init_early		= cell_init_early,
 	.show_cpuinfo		= cell_show_cpuinfo,
 	.restart		= rtas_restart,
 	.power_off		= rtas_power_off,
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c	2006-11-10 16:53:06.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/setup_64.c	2006-11-10 16:54:10.000000000 +1100
@@ -393,7 +393,8 @@ void __init setup_system(void)
 	 * setting up the hash table pointers. It also sets up some interrupt-mapping
 	 * related options that will be used by finish_device_tree()
 	 */
-	ppc_md.init_early();
+	if (ppc_md.init_early)
+		ppc_md.init_early();
 
  	/*
 	 * We can discover serial ports now since the above did setup the
Index: linux-cell/arch/powerpc/kernel/prom_init.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/prom_init.c	2006-11-10 16:53:06.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/prom_init.c	2006-11-10 16:54:10.000000000 +1100
@@ -173,8 +173,8 @@ static unsigned long __initdata dt_strin
 static unsigned long __initdata prom_initrd_start, prom_initrd_end;
 
 #ifdef CONFIG_PPC64
-static int __initdata iommu_force_on;
-static int __initdata ppc64_iommu_off;
+static int __initdata prom_iommu_force_on;
+static int __initdata prom_iommu_off;
 static unsigned long __initdata prom_tce_alloc_start;
 static unsigned long __initdata prom_tce_alloc_end;
 #endif
@@ -582,9 +582,9 @@ static void __init early_cmdline_parse(v
 		while (*opt && *opt == ' ')
 			opt++;
 		if (!strncmp(opt, RELOC("off"), 3))
-			RELOC(ppc64_iommu_off) = 1;
+			RELOC(prom_iommu_off) = 1;
 		else if (!strncmp(opt, RELOC("force"), 5))
-			RELOC(iommu_force_on) = 1;
+			RELOC(prom_iommu_force_on) = 1;
 	}
 #endif
 }
@@ -1167,7 +1167,7 @@ static void __init prom_initialize_tce_t
 	u64 local_alloc_top, local_alloc_bottom;
 	u64 i;
 
-	if (RELOC(ppc64_iommu_off))
+	if (RELOC(prom_iommu_off))
 		return;
 
 	prom_debug("starting prom_initialize_tce_table\n");
@@ -2283,11 +2283,11 @@ unsigned long __init prom_init(unsigned 
 	 * Fill in some infos for use by the kernel later on
 	 */
 #ifdef CONFIG_PPC64
-	if (RELOC(ppc64_iommu_off))
+	if (RELOC(prom_iommu_off))
 		prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
 			     NULL, 0);
 
-	if (RELOC(iommu_force_on))
+	if (RELOC(prom_iommu_force_on))
 		prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
 			     NULL, 0);
 
Index: linux-cell/arch/powerpc/sysdev/dart_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/dart_iommu.c	2006-11-10 16:53:06.000000000 +1100
+++ linux-cell/arch/powerpc/sysdev/dart_iommu.c	2006-11-10 16:54:10.000000000 +1100
@@ -48,9 +48,6 @@
 
 #include "dart.h"
 
-extern int iommu_is_off;
-extern int iommu_force_on;
-
 /* Physical base address and size of the DART table */
 unsigned long dart_tablebase; /* exported to htab_initialize */
 static unsigned long dart_tablesize;
Index: linux-cell/include/asm-powerpc/iommu.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/iommu.h	2006-11-10 16:53:06.000000000 +1100
+++ linux-cell/include/asm-powerpc/iommu.h	2006-11-10 16:54:10.000000000 +1100
@@ -34,7 +34,9 @@
 #define IOMMU_PAGE_MASK       (~((1 << IOMMU_PAGE_SHIFT) - 1))
 #define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
 
-#ifndef __ASSEMBLY__
+/* Boot time flags */
+extern int iommu_is_off;
+extern int iommu_force_on;
 
 /* Pure 2^n version of get_order */
 static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
@@ -42,8 +44,6 @@ static __inline__ __attribute_const__ in
 	return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1;
 }
 
-#endif   /* __ASSEMBLY__ */
-
 
 /*
  * IOMAP_MAX_ORDER defines the largest contiguous block

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

* [PATCH 30/32] powerpc: remove ioremap64 and fixup_bigphys_addr
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (28 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 29/32] powerpc: Cell iommu support Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 31/32] powerpc: Merge 32 and 64 bits asm-powerpc/io.h Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 32/32] powerpc: Fix a typo in new style SPE mapping code Benjamin Herrenschmidt
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

In order to suppose platforms with devices above 4Gb on 32 bits platforms
with a >32 bits physical address space, we used to have a special ioremap64
along with a fixup routine fixup_bigphys_addr.

This shouldn't be necessary anymore as struct resource now supports 64 bits
addresses even on 32 bits archs. This patch enables that option when
CONFIG_PHYS_64BIT is set and removes ioremap64 and fixup_bigphys_addr.

This is a preliminary work for the upcoming merge of 32 and 64 bits io.h

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/Kconfig               |    1 +
 arch/powerpc/mm/pgtable_32.c       |   17 -----------------
 arch/powerpc/platforms/85xx/misc.c |    8 --------
 3 files changed, 1 insertion(+), 25 deletions(-)

Index: linux-cell/arch/powerpc/mm/pgtable_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_32.c	2006-11-06 15:18:35.000000000 +1100
+++ linux-cell/arch/powerpc/mm/pgtable_32.c	2006-11-06 15:55:37.000000000 +1100
@@ -141,28 +141,11 @@ void pte_free(struct page *ptepage)
 	__free_page(ptepage);
 }
 
-#ifndef CONFIG_PHYS_64BIT
 void __iomem *
 ioremap(phys_addr_t addr, unsigned long size)
 {
 	return __ioremap(addr, size, _PAGE_NO_CACHE);
 }
-#else /* CONFIG_PHYS_64BIT */
-void __iomem *
-ioremap64(unsigned long long addr, unsigned long size)
-{
-	return __ioremap(addr, size, _PAGE_NO_CACHE);
-}
-EXPORT_SYMBOL(ioremap64);
-
-void __iomem *
-ioremap(phys_addr_t addr, unsigned long size)
-{
-	phys_addr_t addr64 = fixup_bigphys_addr(addr, size);
-
-	return ioremap64(addr64, size);
-}
-#endif /* CONFIG_PHYS_64BIT */
 EXPORT_SYMBOL(ioremap);
 
 void __iomem *
Index: linux-cell/arch/powerpc/platforms/85xx/misc.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/85xx/misc.c	2006-11-06 15:18:35.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/85xx/misc.c	2006-11-06 15:55:37.000000000 +1100
@@ -21,11 +21,3 @@ void mpc85xx_restart(char *cmd)
 	local_irq_disable();
 	abort();
 }
-
-/* For now this is a pass through */
-phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size)
-{
-	return addr;
-};
-
-EXPORT_SYMBOL(fixup_bigphys_addr);
Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig	2006-11-06 15:55:34.000000000 +1100
+++ linux-cell/arch/powerpc/Kconfig	2006-11-06 15:55:37.000000000 +1100
@@ -247,6 +247,7 @@ config PTE_64BIT
 config PHYS_64BIT
 	bool 'Large physical address support' if E500
 	depends on 44x || E500
+	select RESOURCES_64BIT
 	default y if 44x
 	---help---
 	  This option enables kernel support for larger than 32-bit physical

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

* [PATCH 31/32] powerpc: Merge 32 and 64 bits asm-powerpc/io.h
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (29 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 30/32] powerpc: remove ioremap64 and fixup_bigphys_addr Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  2006-11-10  7:45 ` [PATCH 32/32] powerpc: Fix a typo in new style SPE mapping code Benjamin Herrenschmidt
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

The rework on io.h done for the new hookable accessors made it easier,
so I just finished the work and merged 32 and 64 bits io.h for arch/powerpc.

arch/ppc still uses the old version in asm-ppc, there is just too much gunk
in there that I really can't be bothered trying to cleanup.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/Makefile            |    2 
 arch/powerpc/kernel/io.c                |   87 +++++++++
 arch/powerpc/kernel/iomap.c             |    2 
 arch/powerpc/kernel/pci_32.c            |   34 ---
 arch/powerpc/kernel/rtas_pci.c          |    1 
 arch/powerpc/kernel/traps.c             |    8 
 arch/powerpc/mm/pgtable_32.c            |   22 --
 arch/powerpc/mm/pgtable_64.c            |   16 -
 arch/powerpc/platforms/chrp/setup.c     |    1 
 arch/powerpc/platforms/iseries/setup.c  |    4 
 arch/powerpc/platforms/powermac/setup.c |    2 
 include/asm-powerpc/eeh.h               |   95 ----------
 include/asm-powerpc/ide.h               |    7 
 include/asm-powerpc/io-defs.h           |    9 -
 include/asm-powerpc/io.h                |  284 +++++++++++++++++++++++++++-----
 include/asm-powerpc/machdep.h           |    4 
 16 files changed, 366 insertions(+), 212 deletions(-)

Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/Makefile	2006-11-07 17:40:29.000000000 +1100
@@ -73,7 +73,7 @@ obj-$(CONFIG_AUDIT)		+= audit.o
 obj64-$(CONFIG_AUDIT)		+= compat_audit.o
 
 ifneq ($(CONFIG_PPC_INDIRECT_IO),y)
-pci64-$(CONFIG_PPC64)		+= iomap.o
+obj-y				+= iomap.o
 endif
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
Index: linux-cell/arch/powerpc/kernel/io.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/io.c	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/io.c	2006-11-07 17:40:29.000000000 +1100
@@ -117,3 +117,90 @@ void _outsl_ns(volatile u32 __iomem *por
 	asm volatile("sync");
 }
 EXPORT_SYMBOL(_outsl_ns);
+
+#define IO_CHECK_ALIGN(v,a) ((((unsigned long)(v)) & ((a) - 1)) == 0)
+
+void _memset_io(volatile void __iomem *addr, int c, unsigned long n)
+{
+	void *p = (void __force *)addr;
+	u32 lc = c;
+	lc |= lc << 8;
+	lc |= lc << 16;
+
+	__asm__ __volatile__ ("sync" : : : "memory");
+	while(n && !IO_CHECK_ALIGN(p, 4)) {
+		*((volatile u8 *)p) = c;
+		p++;
+		n--;
+	}
+	while(n >= 4) {
+		*((volatile u32 *)p) = lc;
+		p += 4;
+		n -= 4;
+	}
+	while(n) {
+		*((volatile u8 *)p) = c;
+		p++;
+		n--;
+	}
+	__asm__ __volatile__ ("sync" : : : "memory");
+}
+EXPORT_SYMBOL(_memset_io);
+
+void _memcpy_fromio(void *dest, const volatile void __iomem *src,
+		    unsigned long n)
+{
+	void *vsrc = (void __force *) src;
+
+	__asm__ __volatile__ ("sync" : : : "memory");
+	while(n && (!IO_CHECK_ALIGN(vsrc, 4) || !IO_CHECK_ALIGN(dest, 4))) {
+		*((u8 *)dest) = *((volatile u8 *)vsrc);
+		__asm__ __volatile__ ("eieio" : : : "memory");
+		vsrc++;
+		dest++;
+		n--;
+	}
+	while(n > 4) {
+		*((u32 *)dest) = *((volatile u32 *)vsrc);
+		__asm__ __volatile__ ("eieio" : : : "memory");
+		vsrc += 4;
+		dest += 4;
+		n -= 4;
+	}
+	while(n) {
+		*((u8 *)dest) = *((volatile u8 *)vsrc);
+		__asm__ __volatile__ ("eieio" : : : "memory");
+		vsrc++;
+		dest++;
+		n--;
+	}
+	__asm__ __volatile__ ("sync" : : : "memory");
+}
+EXPORT_SYMBOL(_memcpy_fromio);
+
+void _memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n)
+{
+	void *vdest = (void __force *) dest;
+
+	__asm__ __volatile__ ("sync" : : : "memory");
+	while(n && (!IO_CHECK_ALIGN(vdest, 4) || !IO_CHECK_ALIGN(src, 4))) {
+		*((volatile u8 *)vdest) = *((u8 *)src);
+		src++;
+		vdest++;
+		n--;
+	}
+	while(n > 4) {
+		*((volatile u32 *)vdest) = *((volatile u32 *)src);
+		src += 4;
+		vdest += 4;
+		n-=4;
+	}
+	while(n) {
+		*((volatile u8 *)vdest) = *((u8 *)src);
+		src++;
+		vdest++;
+		n--;
+	}
+	__asm__ __volatile__ ("sync" : : : "memory");
+}
+EXPORT_SYMBOL(_memcpy_toio);
Index: linux-cell/include/asm-powerpc/eeh.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/eeh.h	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/eeh.h	2006-11-07 17:40:29.000000000 +1100
@@ -169,104 +169,19 @@ static inline u64 eeh_readq_be(const vol
 	return val;
 }
 
-#define EEH_CHECK_ALIGN(v,a) \
-	((((unsigned long)(v)) & ((a) - 1)) == 0)
-
-static inline void eeh_memset_io(volatile void __iomem *addr, int c,
-				 unsigned long n)
-{
-	void *p = (void __force *)addr;
-	u32 lc = c;
-	lc |= lc << 8;
-	lc |= lc << 16;
-
-	__asm__ __volatile__ ("sync" : : : "memory");
-	while(n && !EEH_CHECK_ALIGN(p, 4)) {
-		*((volatile u8 *)p) = c;
-		p++;
-		n--;
-	}
-	while(n >= 4) {
-		*((volatile u32 *)p) = lc;
-		p += 4;
-		n -= 4;
-	}
-	while(n) {
-		*((volatile u8 *)p) = c;
-		p++;
-		n--;
-	}
-	__asm__ __volatile__ ("sync" : : : "memory");
-}
-static inline void eeh_memcpy_fromio(void *dest, const volatile void __iomem *src,
+static inline void eeh_memcpy_fromio(void *dest, const
+				     volatile void __iomem *src,
 				     unsigned long n)
 {
-	void *vsrc = (void __force *) src;
-	void *destsave = dest;
-	unsigned long nsave = n;
-
-	__asm__ __volatile__ ("sync" : : : "memory");
-	while(n && (!EEH_CHECK_ALIGN(vsrc, 4) || !EEH_CHECK_ALIGN(dest, 4))) {
-		*((u8 *)dest) = *((volatile u8 *)vsrc);
-		__asm__ __volatile__ ("eieio" : : : "memory");
-		vsrc++;
-		dest++;
-		n--;
-	}
-	while(n > 4) {
-		*((u32 *)dest) = *((volatile u32 *)vsrc);
-		__asm__ __volatile__ ("eieio" : : : "memory");
-		vsrc += 4;
-		dest += 4;
-		n -= 4;
-	}
-	while(n) {
-		*((u8 *)dest) = *((volatile u8 *)vsrc);
-		__asm__ __volatile__ ("eieio" : : : "memory");
-		vsrc++;
-		dest++;
-		n--;
-	}
-	__asm__ __volatile__ ("sync" : : : "memory");
+	_memcpy_fromio(dest, src, n);
 
 	/* Look for ffff's here at dest[n].  Assume that at least 4 bytes
 	 * were copied. Check all four bytes.
 	 */
-	if ((nsave >= 4) &&
-		(EEH_POSSIBLE_ERROR((*((u32 *) destsave+nsave-4)), u32))) {
-		eeh_check_failure(src, (*((u32 *) destsave+nsave-4)));
-	}
-}
-
-static inline void eeh_memcpy_toio(volatile void __iomem *dest, const void *src,
-				   unsigned long n)
-{
-	void *vdest = (void __force *) dest;
-
-	__asm__ __volatile__ ("sync" : : : "memory");
-	while(n && (!EEH_CHECK_ALIGN(vdest, 4) || !EEH_CHECK_ALIGN(src, 4))) {
-		*((volatile u8 *)vdest) = *((u8 *)src);
-		src++;
-		vdest++;
-		n--;
-	}
-	while(n > 4) {
-		*((volatile u32 *)vdest) = *((volatile u32 *)src);
-		src += 4;
-		vdest += 4;
-		n-=4;
-	}
-	while(n) {
-		*((volatile u8 *)vdest) = *((u8 *)src);
-		src++;
-		vdest++;
-		n--;
-	}
-	__asm__ __volatile__ ("sync" : : : "memory");
+	if (n >= 4 && EEH_POSSIBLE_ERROR(*((u32 *)(dest + n - 4)), u32))
+		eeh_check_failure(src, *((u32 *)(dest + n - 4)));
 }
 
-#undef EEH_CHECK_ALIGN
-
 /* in-string eeh macros */
 static inline void eeh_readsb(const volatile void __iomem *addr, void * buf,
 			      int ns)
Index: linux-cell/include/asm-powerpc/io-defs.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/io-defs.h	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/io-defs.h	2006-11-07 17:40:29.000000000 +1100
@@ -3,17 +3,20 @@
 DEF_PCI_AC_RET(readb, u8, (const PCI_IO_ADDR addr), (addr))
 DEF_PCI_AC_RET(readw, u16, (const PCI_IO_ADDR addr), (addr))
 DEF_PCI_AC_RET(readl, u32, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr))
 DEF_PCI_AC_RET(readw_be, u16, (const PCI_IO_ADDR addr), (addr))
 DEF_PCI_AC_RET(readl_be, u32, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr))
 DEF_PCI_AC_NORET(writeb, (u8 val, PCI_IO_ADDR addr), (val, addr))
 DEF_PCI_AC_NORET(writew, (u16 val, PCI_IO_ADDR addr), (val, addr))
 DEF_PCI_AC_NORET(writel, (u32 val, PCI_IO_ADDR addr), (val, addr))
-DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr))
 DEF_PCI_AC_NORET(writew_be, (u16 val, PCI_IO_ADDR addr), (val, addr))
 DEF_PCI_AC_NORET(writel_be, (u32 val, PCI_IO_ADDR addr), (val, addr))
+
+#ifdef __powerpc64__
+DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr))
 DEF_PCI_AC_NORET(writeq_be, (u64 val, PCI_IO_ADDR addr), (val, addr))
+#endif /* __powerpc64__ */
 
 DEF_PCI_AC_RET(inb, u8, (unsigned long port), (port))
 DEF_PCI_AC_RET(inw, u16, (unsigned long port), (port))
Index: linux-cell/include/asm-powerpc/io.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/io.h	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/io.h	2006-11-07 17:40:29.000000000 +1100
@@ -13,24 +13,51 @@
 extern int check_legacy_ioport(unsigned long base_port);
 #define PNPBIOS_BASE	0xf000	/* only relevant for PReP */
 
-#ifndef CONFIG_PPC64
-#include <asm-ppc/io.h>
-#else
-
 #include <linux/compiler.h>
 #include <asm/page.h>
 #include <asm/byteorder.h>
-#include <asm/paca.h>
 #include <asm/synch.h>
 #include <asm/delay.h>
+#include <asm/mmu.h>
 
 #include <asm-generic/iomap.h>
 
+#ifdef CONFIG_PPC64
+#include <asm/paca.h>
+#endif
+
 #define SIO_CONFIG_RA	0x398
 #define SIO_CONFIG_RD	0x399
 
 #define SLOW_DOWN_IO
 
+/* 32 bits uses slightly different variables for the various IO
+ * bases. Most of this file only uses _IO_BASE though which we
+ * define properly based on the platform
+ */
+#ifdef CONFIG_PCI
+#define _IO_BASE	0
+#define _ISA_MEM_BASE	0
+#define PCI_DRAM_OFFSET 0
+#elif defined(CONFIG_PPC32)
+#define _IO_BASE	isa_io_base
+#define _ISA_MEM_BASE	isa_mem_base
+#define PCI_DRAM_OFFSET	pci_dram_offset
+#else
+#define _IO_BASE	pci_io_base
+#define _ISA_MEM_BASE	0
+#define PCI_DRAM_OFFSET	0
+#endif
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_io_base;
+extern unsigned long pci_dram_offset;
+
+#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_INDIRECT_IO)
+#error CONFIG_PPC_INDIRECT_IO is not yet support on 32 bits
+#endif
+
 /*
  *
  * Low level MMIO accessors
@@ -53,7 +80,11 @@ extern int check_legacy_ioport(unsigned 
  *
  */
 
+#ifdef CONFIG_PPC64
 #define IO_SET_SYNC_FLAG()	do { get_paca()->io_sync = 1; } while(0)
+#else
+#define IO_SET_SYNC_FLAG()
+#endif
 
 #define DEF_MMIO_IN(name, type, insn)					\
 static inline type name(const volatile type __iomem *addr)		\
@@ -86,17 +117,19 @@ static inline void name(volatile type __
 DEF_MMIO_IN_BE(in_8,     8, lbz);
 DEF_MMIO_IN_BE(in_be16, 16, lhz);
 DEF_MMIO_IN_BE(in_be32, 32, lwz);
-DEF_MMIO_IN_BE(in_be64, 64, ld);
 DEF_MMIO_IN_LE(in_le16, 16, lhbrx);
 DEF_MMIO_IN_LE(in_le32, 32, lwbrx);
 
 DEF_MMIO_OUT_BE(out_8,     8, stb);
 DEF_MMIO_OUT_BE(out_be16, 16, sth);
 DEF_MMIO_OUT_BE(out_be32, 32, stw);
-DEF_MMIO_OUT_BE(out_be64, 64, std);
 DEF_MMIO_OUT_LE(out_le16, 16, sthbrx);
 DEF_MMIO_OUT_LE(out_le32, 32, stwbrx);
 
+#ifdef __powerpc64__
+DEF_MMIO_OUT_BE(out_be64, 64, std);
+DEF_MMIO_IN_BE(in_be64, 64, ld);
+
 /* There is no asm instructions for 64 bits reverse loads and stores */
 static inline u64 in_le64(const volatile u64 __iomem *addr)
 {
@@ -107,6 +140,7 @@ static inline void out_le64(volatile u64
 {
 	out_be64(addr, cpu_to_le64(val));
 }
+#endif /* __powerpc64__ */
 
 /*
  * Low level IO stream instructions are defined out of line for now
@@ -126,6 +160,17 @@ extern void _outsl_ns(volatile u32 __iom
 #define _outsw	_outsw_ns
 #define _outsl	_outsl_ns
 
+
+/*
+ * memset_io, memcpy_toio, memcpy_fromio base implementations are out of line
+ */
+
+extern void _memset_io(volatile void __iomem *addr, int c, unsigned long n);
+extern void _memcpy_fromio(void *dest, const volatile void __iomem *src,
+			   unsigned long n);
+extern void _memcpy_toio(volatile void __iomem *dest, const void *src,
+			 unsigned long n);
+
 /*
  *
  * PCI and standard ISA accessors
@@ -140,9 +185,6 @@ extern void _outsl_ns(volatile u32 __iom
  * of the accessors.
  */
 
-extern unsigned long isa_io_base;
-extern unsigned long pci_io_base;
-
 
 /*
  * Non ordered and non-swapping "raw" accessors
@@ -160,10 +202,6 @@ static inline unsigned int __raw_readl(c
 {
 	return *(volatile unsigned int __force *)addr;
 }
-static inline unsigned long __raw_readq(const volatile void __iomem *addr)
-{
-	return *(volatile unsigned long __force *)addr;
-}
 static inline void __raw_writeb(unsigned char v, volatile void __iomem *addr)
 {
 	*(volatile unsigned char __force *)addr = v;
@@ -176,11 +214,17 @@ static inline void __raw_writel(unsigned
 {
 	*(volatile unsigned int __force *)addr = v;
 }
+
+#ifdef __powerpc64__
+static inline unsigned long __raw_readq(const volatile void __iomem *addr)
+{
+	return *(volatile unsigned long __force *)addr;
+}
 static inline void __raw_writeq(unsigned long v, volatile void __iomem *addr)
 {
 	*(volatile unsigned long __force *)addr = v;
 }
-
+#endif /* __powerpc64__ */
 
 /*
  *
@@ -188,7 +232,13 @@ static inline void __raw_writeq(unsigned
  *
  */
 
+/*
+ * Include the EEH definitions when EEH is enabled only so they don't get
+ * in the way when building for 32 bits
+ */
+#ifdef CONFIG_EEH
 #include <asm/eeh.h>
+#endif
 
 /* Shortcut to the MMIO argument pointer */
 #define PCI_IO_ADDR	volatile void __iomem *
@@ -196,7 +246,7 @@ static inline void __raw_writeq(unsigned
 /* Indirect IO address tokens:
  *
  * When CONFIG_PPC_INDIRECT_IO is set, the platform can provide hooks
- * on all IOs.
+ * on all IOs. (Note that this is all 64 bits only for now)
  *
  * To help platforms who may need to differenciate MMIO addresses in
  * their hooks, a bitfield is reserved for use by the platform near the
@@ -241,6 +291,70 @@ do {									\
 #define PCI_FIX_ADDR(addr) (addr)
 #endif
 
+/*
+ * On 32 bits, PIO operations have a recovery mechanism in case they trigger
+ * machine checks (which they occasionally do when probing non existing
+ * IO ports on some platforms, like PowerMac and 8xx).
+ * I always found it to be of dubious reliability and I am tempted to get
+ * rid of it one of these days. So if you think it's important to keep it,
+ * please voice up asap. We never had it for 64 bits and I do not intend
+ * to port it over
+ */
+
+#ifdef CONFIG_PPC32
+
+#define __do_in_asm(name, op)				\
+extern __inline__ unsigned int name(unsigned int port)	\
+{							\
+	unsigned int x;					\
+	__asm__ __volatile__(				\
+		"sync\n"				\
+		"0:"	op "	%0,0,%1\n"		\
+		"1:	twi	0,%0,0\n"		\
+		"2:	isync\n"			\
+		"3:	nop\n"				\
+		"4:\n"					\
+		".section .fixup,\"ax\"\n"		\
+		"5:	li	%0,-1\n"		\
+		"	b	4b\n"			\
+		".previous\n"				\
+		".section __ex_table,\"a\"\n"		\
+		"	.align	2\n"			\
+		"	.long	0b,5b\n"		\
+		"	.long	1b,5b\n"		\
+		"	.long	2b,5b\n"		\
+		"	.long	3b,5b\n"		\
+		".previous"				\
+		: "=&r" (x)				\
+		: "r" (port + _IO_BASE));		\
+	return x;					\
+}
+
+#define __do_out_asm(name, op)				\
+extern __inline__ void name(unsigned int val, unsigned int port) \
+{							\
+	__asm__ __volatile__(				\
+		"sync\n"				\
+		"0:" op " %0,0,%1\n"			\
+		"1:	sync\n"				\
+		"2:\n"					\
+		".section __ex_table,\"a\"\n"		\
+		"	.align	2\n"			\
+		"	.long	0b,2b\n"		\
+		"	.long	1b,2b\n"		\
+		".previous"				\
+		: : "r" (val), "r" (port + _IO_BASE));	\
+}
+
+__do_in_asm(_rec_inb, "lbzx")
+__do_in_asm(_rec_inw, "lhbrx")
+__do_in_asm(_rec_inl, "lwbrx")
+__do_out_asm(_rec_outb, "stbx")
+__do_out_asm(_rec_outw, "sthbrx")
+__do_out_asm(_rec_outl, "stwbrx")
+
+#endif /* CONFIG_PPC32 */
+
 /* The "__do_*" operations below provide the actual "base" implementation
  * for each of the defined acccessor. Some of them use the out_* functions
  * directly, some of them still use EEH, though we might change that in the
@@ -263,6 +377,8 @@ do {									\
 #define __do_writew_be(val, addr) out_be16(PCI_FIX_ADDR(addr), val)
 #define __do_writel_be(val, addr) out_be32(PCI_FIX_ADDR(addr), val)
 #define __do_writeq_be(val, addr) out_be64(PCI_FIX_ADDR(addr), val)
+
+#ifdef CONFIG_EEH
 #define __do_readb(addr)	eeh_readb(PCI_FIX_ADDR(addr))
 #define __do_readw(addr)	eeh_readw(PCI_FIX_ADDR(addr))
 #define __do_readl(addr)	eeh_readl(PCI_FIX_ADDR(addr))
@@ -270,33 +386,64 @@ do {									\
 #define __do_readw_be(addr)	eeh_readw_be(PCI_FIX_ADDR(addr))
 #define __do_readl_be(addr)	eeh_readl_be(PCI_FIX_ADDR(addr))
 #define __do_readq_be(addr)	eeh_readq_be(PCI_FIX_ADDR(addr))
+#else /* CONFIG_EEH */
+#define __do_readb(addr)	in_8(PCI_FIX_ADDR(addr))
+#define __do_readw(addr)	in_le16(PCI_FIX_ADDR(addr))
+#define __do_readl(addr)	in_le32(PCI_FIX_ADDR(addr))
+#define __do_readq(addr)	in_le64(PCI_FIX_ADDR(addr))
+#define __do_readw_be(addr)	in_be16(PCI_FIX_ADDR(addr))
+#define __do_readl_be(addr)	in_be32(PCI_FIX_ADDR(addr))
+#define __do_readq_be(addr)	in_be64(PCI_FIX_ADDR(addr))
+#endif /* !defined(CONFIG_EEH) */
+
+#ifdef CONFIG_PPC32
+#define __do_outb(val, port)	_rec_outb(val, port)
+#define __do_outw(val, port)	_rec_outw(val, port)
+#define __do_outl(val, port)	_rec_outl(val, port)
+#define __do_inb(port)		_rec_inb(port)
+#define __do_inw(port)		_rec_inw(port)
+#define __do_inl(port)		_rec_inl(port)
+#else /* CONFIG_PPC32 */
+#define __do_outb(val, port)	writeb(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_outw(val, port)	writew(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_outl(val, port)	writel(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_inb(port)		readb((PCI_IO_ADDR)_IO_BASE + port);
+#define __do_inw(port)		readw((PCI_IO_ADDR)_IO_BASE + port);
+#define __do_inl(port)		readl((PCI_IO_ADDR)_IO_BASE + port);
+#endif /* !CONFIG_PPC32 */
 
-#define __do_outb(val, port)	writeb(val,(PCI_IO_ADDR)pci_io_base+port);
-#define __do_outw(val, port)	writew(val,(PCI_IO_ADDR)pci_io_base+port);
-#define __do_outl(val, port)	writel(val,(PCI_IO_ADDR)pci_io_base+port);
-#define __do_inb(port)		readb((PCI_IO_ADDR)pci_io_base + port);
-#define __do_inw(port)		readw((PCI_IO_ADDR)pci_io_base + port);
-#define __do_inl(port)		readl((PCI_IO_ADDR)pci_io_base + port);
-
+#ifdef CONFIG_EEH
 #define __do_readsb(a, b, n)	eeh_readsb(PCI_FIX_ADDR(a), (b), (n))
 #define __do_readsw(a, b, n)	eeh_readsw(PCI_FIX_ADDR(a), (b), (n))
 #define __do_readsl(a, b, n)	eeh_readsl(PCI_FIX_ADDR(a), (b), (n))
+#else /* CONFIG_EEH */
+#define __do_readsb(a, b, n)	_insb(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsw(a, b, n)	_insw(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsl(a, b, n)	_insl(PCI_FIX_ADDR(a), (b), (n))
+#endif /* !CONFIG_EEH */
 #define __do_writesb(a, b, n)	_outsb(PCI_FIX_ADDR(a),(b),(n))
 #define __do_writesw(a, b, n)	_outsw(PCI_FIX_ADDR(a),(b),(n))
 #define __do_writesl(a, b, n)	_outsl(PCI_FIX_ADDR(a),(b),(n))
 
-#define __do_insb(p, b, n)	readsb((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
-#define __do_insw(p, b, n)	readsw((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
-#define __do_insl(p, b, n)	readsl((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
-#define __do_outsb(p, b, n)	writesb((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
-#define __do_outsw(p, b, n)	writesw((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
-#define __do_outsl(p, b, n)	writesl((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
-
-#define __do_memset_io(addr, c, n)	eeh_memset_io(PCI_FIX_ADDR(addr), c, n)
-#define __do_memcpy_fromio(dst, src, n)	eeh_memcpy_fromio(dst, \
-						PCI_FIX_ADDR(src), n)
-#define __do_memcpy_toio(dst, src, n)	eeh_memcpy_toio(PCI_FIX_ADDR(dst), \
-						src, n)
+#define __do_insb(p, b, n)	readsb((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_insw(p, b, n)	readsw((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_insl(p, b, n)	readsl((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_outsb(p, b, n)	writesb((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+#define __do_outsw(p, b, n)	writesw((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+#define __do_outsl(p, b, n)	writesl((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+
+#define __do_memset_io(addr, c, n)	\
+				_memset_io(PCI_FIX_ADDR(addr), c, n)
+#define __do_memcpy_toio(dst, src, n)	\
+				_memcpy_toio(PCI_FIX_ADDR(dst), src, n)
+
+#ifdef CONFIG_EEH
+#define __do_memcpy_fromio(dst, src, n)	\
+				eeh_memcpy_fromio(dst, PCI_FIX_ADDR(src), n)
+#else /* CONFIG_EEH */
+#define __do_memcpy_fromio(dst, src, n)	\
+				_memcpy_fromio(dst,PCI_FIX_ADDR(src),n)
+#endif /* !CONFIG_EEH */
 
 #ifdef CONFIG_PPC_INDIRECT_IO
 #define DEF_PCI_HOOK(x)		x
@@ -343,15 +490,27 @@ static inline void name at					\
 /* Some drivers check for the presence of readq & writeq with
  * a #ifdef, so we make them happy here.
  */
+#ifdef __powerpc64__
 #define readq	readq
 #define writeq	writeq
+#endif
 
-/* Nothing to do for cache stuff x*/
+#ifdef CONFIG_NOT_COHERENT_CACHE
+
+#define dma_cache_inv(_start,_size) \
+	invalidate_dcache_range(_start, (_start + _size))
+#define dma_cache_wback(_start,_size) \
+	clean_dcache_range(_start, (_start + _size))
+#define dma_cache_wback_inv(_start,_size) \
+	flush_dcache_range(_start, (_start + _size))
+
+#else /* CONFIG_NOT_COHERENT_CACHE */
 
 #define dma_cache_inv(_start,_size)		do { } while (0)
 #define dma_cache_wback(_start,_size)		do { } while (0)
 #define dma_cache_wback_inv(_start,_size)	do { } while (0)
 
+#endif /* !CONFIG_NOT_COHERENT_CACHE */
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
@@ -372,6 +531,9 @@ static inline void name at					\
 #define readl_relaxed(addr) readl(addr)
 #define readq_relaxed(addr) readq(addr)
 
+#ifdef CONFIG_PPC32
+#define mmiowb()
+#else
 /*
  * Enforce synchronisation of stores vs. spin_unlock
  * (this does it explicitely, though our implementation of spin_unlock
@@ -385,6 +547,7 @@ static inline void mmiowb(void)
 	: "=&r" (tmp) : "i" (offsetof(struct paca_struct, io_sync))
 	: "memory");
 }
+#endif /* !CONFIG_PPC32 */
 
 static inline void iosync(void)
 {
@@ -453,22 +616,29 @@ static inline void iosync(void)
  *   be hooked (but can be used by a hook on iounmap)
  *
  */
-extern void __iomem *ioremap(unsigned long address, unsigned long size);
-extern void __iomem *ioremap_flags(unsigned long address, unsigned long size,
+extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
+extern void __iomem *ioremap_flags(phys_addr_t address, unsigned long size,
 				   unsigned long flags);
 #define ioremap_nocache(addr, size)	ioremap((addr), (size))
-extern void iounmap(void __iomem *addr);
+extern void iounmap(volatile void __iomem *addr);
 
-extern void __iomem *__ioremap(unsigned long address, unsigned long size,
+extern void __iomem *__ioremap(phys_addr_t, unsigned long size,
 			       unsigned long flags);
-extern void __iounmap(void __iomem *addr);
+extern void __iounmap(volatile void __iomem *addr);
 
-extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr,
+extern int __ioremap_explicit(phys_addr_t p_addr, unsigned long v_addr,
 		     	      unsigned long size, unsigned long flags);
-extern int __iounmap_explicit(void __iomem *start, unsigned long size);
+extern int __iounmap_explicit(volatile void __iomem *start,
+			      unsigned long size);
 
 extern void __iomem * reserve_phb_iospace(unsigned long size);
 
+/* Those are more 32 bits only functions */
+extern unsigned long iopa(unsigned long addr);
+extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
+extern void io_block_mapping(unsigned long virt, phys_addr_t phys,
+			     unsigned int size, int flags);
+
 
 /*
  * When CONFIG_PPC_INDIRECT_IO is set, we use the generic iomap implementation
@@ -538,7 +708,33 @@ static inline void * phys_to_virt(unsign
  */
 #define BIO_VMERGE_BOUNDARY	0
 
+/*
+ * 32 bits still uses virt_to_bus() for it's implementation of DMA
+ * mappings se we have to keep it defined here. We also have some old
+ * drivers (shame shame shame) that use bus_to_virt() and haven't been
+ * fixed yet so I need to define it here.
+ */
+#ifdef CONFIG_PPC32
+
+static inline unsigned long virt_to_bus(volatile void * address)
+{
+        if (address == NULL)
+		return 0;
+        return __pa(address) + PCI_DRAM_OFFSET;
+}
+
+static inline void * bus_to_virt(unsigned long address)
+{
+        if (address == 0)
+		return NULL;
+        return __va(address - PCI_DRAM_OFFSET);
+}
+
+#define page_to_bus(page)	(page_to_phys(page) + PCI_DRAM_OFFSET)
+
+#endif /* CONFIG_PPC32 */
+
+
 #endif /* __KERNEL__ */
 
-#endif /* CONFIG_PPC64 */
 #endif /* _ASM_POWERPC_IO_H */
Index: linux-cell/arch/powerpc/kernel/traps.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/traps.c	2006-11-07 15:04:29.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/traps.c	2006-11-07 17:40:29.000000000 +1100
@@ -53,10 +53,6 @@
 #endif
 #include <asm/kexec.h>
 
-#ifdef CONFIG_PPC64	/* XXX */
-#define _IO_BASE	pci_io_base
-#endif
-
 #ifdef CONFIG_DEBUGGER
 int (*__debugger)(struct pt_regs *regs);
 int (*__debugger_ipi)(struct pt_regs *regs);
@@ -241,7 +237,7 @@ void system_reset_exception(struct pt_re
  */
 static inline int check_io_access(struct pt_regs *regs)
 {
-#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
+#ifdef CONFIG_PPC32
 	unsigned long msr = regs->msr;
 	const struct exception_table_entry *entry;
 	unsigned int *nip = (unsigned int *)regs->nip;
@@ -274,7 +270,7 @@ static inline int check_io_access(struct
 			return 1;
 		}
 	}
-#endif /* CONFIG_PPC_PMAC && CONFIG_PPC32 */
+#endif /* CONFIG_PPC32 */
 	return 0;
 }
 
Index: linux-cell/arch/powerpc/kernel/rtas_pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/rtas_pci.c	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/rtas_pci.c	2006-11-07 17:40:29.000000000 +1100
@@ -38,6 +38,7 @@
 #include <asm/rtas.h>
 #include <asm/mpic.h>
 #include <asm/ppc-pci.h>
+#include <asm/eeh.h>
 
 /* RTAS tokens */
 static int read_pci_config;
Index: linux-cell/arch/powerpc/platforms/chrp/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/chrp/setup.c	2006-11-07 15:04:29.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/chrp/setup.c	2006-11-07 17:40:29.000000000 +1100
@@ -588,7 +588,6 @@ static int __init chrp_probe(void)
 	ISA_DMA_THRESHOLD = ~0L;
 	DMA_MODE_READ = 0x44;
 	DMA_MODE_WRITE = 0x48;
-	isa_io_base = CHRP_ISA_IO_BASE;		/* default value */
 
 	return 1;
 }
Index: linux-cell/arch/powerpc/platforms/powermac/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/setup.c	2006-11-07 15:04:29.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/powermac/setup.c	2006-11-07 17:40:29.000000000 +1100
@@ -677,8 +677,6 @@ static int __init pmac_probe(void)
 
 #ifdef CONFIG_PPC32
 	/* isa_io_base gets set in pmac_pci_init */
-	isa_mem_base = PMAC_ISA_MEM_BASE;
-	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
 	ISA_DMA_THRESHOLD = ~0L;
 	DMA_MODE_READ = 1;
 	DMA_MODE_WRITE = 2;
Index: linux-cell/arch/powerpc/mm/pgtable_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_32.c	2006-11-07 17:40:28.000000000 +1100
+++ linux-cell/arch/powerpc/mm/pgtable_32.c	2006-11-07 17:40:29.000000000 +1100
@@ -149,6 +149,13 @@ ioremap(phys_addr_t addr, unsigned long 
 EXPORT_SYMBOL(ioremap);
 
 void __iomem *
+ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags)
+{
+	return __ioremap(addr, size, flags);
+}
+EXPORT_SYMBOL(ioremap_flags);
+
+void __iomem *
 __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
 {
 	unsigned long v, i;
@@ -247,20 +254,7 @@ void iounmap(volatile void __iomem *addr
 }
 EXPORT_SYMBOL(iounmap);
 
-void __iomem *ioport_map(unsigned long port, unsigned int len)
-{
-	return (void __iomem *) (port + _IO_BASE);
-}
-
-void ioport_unmap(void __iomem *addr)
-{
-	/* Nothing to do */
-}
-EXPORT_SYMBOL(ioport_map);
-EXPORT_SYMBOL(ioport_unmap);
-
-int
-map_page(unsigned long va, phys_addr_t pa, int flags)
+int map_page(unsigned long va, phys_addr_t pa, int flags)
 {
 	pmd_t *pd;
 	pte_t *pg;
Index: linux-cell/arch/powerpc/mm/pgtable_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_64.c	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/mm/pgtable_64.c	2006-11-07 17:40:29.000000000 +1100
@@ -113,7 +113,7 @@ static int map_io_page(unsigned long ea,
 }
 
 
-static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa,
+static void __iomem * __ioremap_com(phys_addr_t addr, unsigned long pa,
 			    unsigned long ea, unsigned long size,
 			    unsigned long flags)
 {
@@ -129,7 +129,7 @@ static void __iomem * __ioremap_com(unsi
 	return (void __iomem *) (ea + (addr & ~PAGE_MASK));
 }
 
-void __iomem * __ioremap(unsigned long addr, unsigned long size,
+void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
 			 unsigned long flags)
 {
 	unsigned long pa, ea;
@@ -169,7 +169,7 @@ void __iomem * __ioremap(unsigned long a
 }
 
 
-void __iomem * ioremap(unsigned long addr, unsigned long size)
+void __iomem * ioremap(phys_addr_t addr, unsigned long size)
 {
 	unsigned long flags = _PAGE_NO_CACHE | _PAGE_GUARDED;
 
@@ -178,7 +178,7 @@ void __iomem * ioremap(unsigned long add
 	return __ioremap(addr, size, flags);
 }
 
-void __iomem * ioremap_flags(unsigned long addr, unsigned long size,
+void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size,
 			     unsigned long flags)
 {
 	if (ppc_md.ioremap)
@@ -189,7 +189,7 @@ void __iomem * ioremap_flags(unsigned lo
 
 #define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
 
-int __ioremap_explicit(unsigned long pa, unsigned long ea,
+int __ioremap_explicit(phys_addr_t pa, unsigned long ea,
 		       unsigned long size, unsigned long flags)
 {
 	struct vm_struct *area;
@@ -244,7 +244,7 @@ int __ioremap_explicit(unsigned long pa,
  *
  * XXX	what about calls before mem_init_done (ie python_countermeasures())
  */
-void __iounmap(void __iomem *token)
+void __iounmap(volatile void __iomem *token)
 {
 	void *addr;
 
@@ -256,7 +256,7 @@ void __iounmap(void __iomem *token)
 	im_free(addr);
 }
 
-void iounmap(void __iomem *token)
+void iounmap(volatile void __iomem *token)
 {
 	if (ppc_md.iounmap)
 		ppc_md.iounmap(token);
@@ -282,7 +282,7 @@ static int iounmap_subset_regions(unsign
 	return 0;
 }
 
-int __iounmap_explicit(void __iomem *start, unsigned long size)
+int __iounmap_explicit(volatile void __iomem *start, unsigned long size)
 {
 	struct vm_struct *area;
 	unsigned long addr;
Index: linux-cell/arch/powerpc/platforms/iseries/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/setup.c	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/iseries/setup.c	2006-11-07 17:40:29.000000000 +1100
@@ -649,13 +649,13 @@ static void iseries_dedicated_idle(void)
 void __init iSeries_init_IRQ(void) { }
 #endif
 
-static void __iomem *iseries_ioremap(unsigned long address, unsigned long size,
+static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size,
 				     unsigned long flags)
 {
 	return (void __iomem *)address;
 }
 
-static void iseries_iounmap(void __iomem *token)
+static void iseries_iounmap(volatile void __iomem *token)
 {
 }
 
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/machdep.h	2006-11-07 17:40:29.000000000 +1100
@@ -88,9 +88,9 @@ struct machdep_calls {
 	void		(*pci_dma_dev_setup)(struct pci_dev *dev);
 	void		(*pci_dma_bus_setup)(struct pci_bus *bus);
 
-	void __iomem *	(*ioremap)(unsigned long addr, unsigned long size,
+	void __iomem *	(*ioremap)(phys_addr_t addr, unsigned long size,
 				   unsigned long flags);
-	void		(*iounmap)(void __iomem *token);
+	void		(*iounmap)(volatile void __iomem *token);
 #endif /* CONFIG_PPC64 */
 
 	int		(*probe)(void);
Index: linux-cell/arch/powerpc/kernel/pci_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_32.c	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_32.c	2006-11-07 17:40:29.000000000 +1100
@@ -1561,7 +1561,7 @@ static struct resource *__pci_mmap_make_
 		*offset += hose->pci_mem_offset;
 		res_bit = IORESOURCE_MEM;
 	} else {
-		io_offset = hose->io_base_virt - ___IO_BASE;
+		io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE;
 		*offset += io_offset;
 		res_bit = IORESOURCE_IO;
 	}
@@ -1816,7 +1816,8 @@ void pci_resource_to_user(const struct p
 		return;
 
 	if (rsrc->flags & IORESOURCE_IO)
-		offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+		offset = (void __iomem *)_IO_BASE - hose->io_base_virt
+			+ hose->io_base_phys;
 
 	*start = rsrc->start + offset;
 	*end = rsrc->end + offset;
@@ -1835,35 +1836,6 @@ pci_init_resource(struct resource *res, 
 	res->child = NULL;
 }
 
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
-{
-	unsigned long start = pci_resource_start(dev, bar);
-	unsigned long len = pci_resource_len(dev, bar);
-	unsigned long flags = pci_resource_flags(dev, bar);
-
-	if (!len)
-		return NULL;
-	if (max && len > max)
-		len = max;
-	if (flags & IORESOURCE_IO)
-		return ioport_map(start, len);
-	if (flags & IORESOURCE_MEM)
-		/* Not checking IORESOURCE_CACHEABLE because PPC does
-		 * not currently distinguish between ioremap and
-		 * ioremap_nocache.
-		 */
-		return ioremap(start, len);
-	/* What? */
-	return NULL;
-}
-
-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
-{
-	/* Nothing to do */
-}
-EXPORT_SYMBOL(pci_iomap);
-EXPORT_SYMBOL(pci_iounmap);
-
 unsigned long pci_address_to_pio(phys_addr_t address)
 {
 	struct pci_controller* hose = hose_head;
Index: linux-cell/arch/powerpc/kernel/iomap.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/iomap.c	2006-11-07 15:04:29.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/iomap.c	2006-11-07 17:40:29.000000000 +1100
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(iowrite32_rep);
 
 void __iomem *ioport_map(unsigned long port, unsigned int len)
 {
-	return (void __iomem *) (port+pci_io_base);
+	return (void __iomem *) (port + _IO_BASE);
 }
 
 void ioport_unmap(void __iomem *addr)
Index: linux-cell/include/asm-powerpc/ide.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ide.h	2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/ide.h	2006-11-07 17:40:29.000000000 +1100
@@ -22,17 +22,10 @@
 #endif
 #endif
 
-#ifdef __powerpc64__
 #define __ide_mm_insw(p, a, c)	readsw((void __iomem *)(p), (a), (c))
 #define __ide_mm_insl(p, a, c)	readsl((void __iomem *)(p), (a), (c))
 #define __ide_mm_outsw(p, a, c)	writesw((void __iomem *)(p), (a), (c))
 #define __ide_mm_outsl(p, a, c)	writesl((void __iomem *)(p), (a), (c))
-#else
-#define __ide_mm_insw(p, a, c)	_insw_ns((volatile u16 __iomem *)(p), (a), (c))
-#define __ide_mm_insl(p, a, c)	_insl_ns((volatile u32 __iomem *)(p), (a), (c))
-#define __ide_mm_outsw(p, a, c)	_outsw_ns((volatile u16 __iomem *)(p), (a), (c))
-#define __ide_mm_outsl(p, a, c)	_outsl_ns((volatile u32 __iomem *)(p), (a), (c))
-#endif
 
 #ifndef  __powerpc64__
 #include <linux/hdreg.h>

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

* [PATCH 32/32] powerpc: Fix a typo in new style SPE mapping code
  2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
                   ` (30 preceding siblings ...)
  2006-11-10  7:45 ` [PATCH 31/32] powerpc: Merge 32 and 64 bits asm-powerpc/io.h Benjamin Herrenschmidt
@ 2006-11-10  7:45 ` Benjamin Herrenschmidt
  31 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-10  7:45 UTC (permalink / raw)
  To: linuxppc-dev

This patch fixes a typo in the "new style" code for mapping SPE
resources, which causes it to try to map 4 times the same resource.

It also adds some pr_debug's that are useful to track down issues with
the firmware when bringinh up new machines.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

The bug is in 2.6.19 so we should merge that asap.

 arch/powerpc/platforms/cell/spu_base.c |   41 ++++++++++++++++++++++++++-------
 1 file changed, 33 insertions(+), 8 deletions(-)

Index: linux-cell/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spu_base.c	2006-10-23 14:41:37.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spu_base.c	2006-11-10 16:54:20.000000000 +1100
@@ -655,14 +655,19 @@ static int __init spu_map_interrupts(str
 
 	for (i=0; i < 3; i++) {
 		ret = of_irq_map_one(np, i, &oirq);
-		if (ret)
+		if (ret) {
+			pr_debug("spu_new: failed to get irq %d\n", i);
 			goto err;
-
+		}
 		ret = -EINVAL;
+		pr_debug("  irq %d no 0x%x on %s\n", i, oirq.specifier[0],
+			 oirq.controller->full_name);
 		spu->irqs[i] = irq_create_of_mapping(oirq.controller,
 					oirq.specifier, oirq.size);
-		if (spu->irqs[i] == NO_IRQ)
+		if (spu->irqs[i] == NO_IRQ) {
+			pr_debug("spu_new: failed to map it !\n");
 			goto err;
+		}
 	}
 	return 0;
 
@@ -681,7 +686,7 @@ static int spu_map_resource(struct devic
 	struct resource resource = { };
 	int ret;
 
-	ret = of_address_to_resource(node, 0, &resource);
+	ret = of_address_to_resource(node, nr, &resource);
 	if (ret)
 		goto out;
 
@@ -704,22 +709,42 @@ static int __init spu_map_device(struct 
 
 	ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store,
 					&spu->local_store_phys);
-	if (ret)
+	if (ret) {
+		pr_debug("spu_new: failed to map %s resource 0\n",
+			 node->full_name);
 		goto out;
+	}
 	ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
 					&spu->problem_phys);
-	if (ret)
+	if (ret) {
+		pr_debug("spu_new: failed to map %s resource 1\n",
+			 node->full_name);
 		goto out_unmap;
+	}
 	ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
 					NULL);
-	if (ret)
+	if (ret) {
+		pr_debug("spu_new: failed to map %s resource 2\n",
+			 node->full_name);
 		goto out_unmap;
+	}
 
 	if (!firmware_has_feature(FW_FEATURE_LPAR))
 		ret = spu_map_resource(node, 3, (void __iomem**)&spu->priv1,
 					NULL);
-	if (ret)
+	if (ret) {
+		pr_debug("spu_new: failed to map %s resource 3\n",
+			 node->full_name);
 		goto out_unmap;
+	}
+	pr_debug("spu_new: %s maps:\n", node->full_name);
+	pr_debug("  local store   : 0x%016lx -> 0x%p\n",
+		 spu->local_store_phys, spu->local_store);
+	pr_debug("  problem state : 0x%016lx -> 0x%p\n",
+		 spu->problem_phys, spu->problem);
+	pr_debug("  priv2         :                       0x%p\n", spu->priv2);
+	pr_debug("  priv1         :                       0x%p\n", spu->priv1);
+
 	return 0;
 
 out_unmap:

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

* [PATCH 26/32] powerpc: Add an optional offset to direct DMA on 64 bits
  2006-11-11  6:24 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
@ 2006-11-11  6:25 ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-11  6:25 UTC (permalink / raw)
  To: linuxppc-dev

This patch adds an optional global offset that can be added to DMA addresses
when using the direct DMA operations.

That brings it a step closer to the 32 bits direct DMA operations, and makes
it useable on Cell when the MMU is disabled and we are using a spider
southbridge.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/kernel/dma_64.c      |   11 ++++++++---
 include/asm-powerpc/dma-mapping.h |    2 ++
 2 files changed, 10 insertions(+), 3 deletions(-)

Index: linux-cell/arch/powerpc/kernel/dma_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/dma_64.c	2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/dma_64.c	2006-11-10 16:45:21.000000000 +1100
@@ -111,7 +111,11 @@ EXPORT_SYMBOL(dma_iommu_ops);
 
 /*
  * Generic direct DMA implementation
+ *
+ * This implementation supports a global offset that can be applied if
+ * the address at which memory is visible to devices is not 0.
  */
+unsigned long dma_direct_offset;
 
 static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 				       dma_addr_t *dma_handle, gfp_t flag)
@@ -122,7 +126,7 @@ static void *dma_direct_alloc_coherent(s
 	ret = (void *)__get_free_pages(flag, get_order(size));
 	if (ret != NULL) {
 		memset(ret, 0, size);
-		*dma_handle = virt_to_abs(ret);
+		*dma_handle = virt_to_abs(ret) | dma_direct_offset;
 	}
 	return ret;
 }
@@ -137,7 +141,7 @@ static dma_addr_t dma_direct_map_single(
 					size_t size,
 					enum dma_data_direction direction)
 {
-	return virt_to_abs(ptr);
+	return virt_to_abs(ptr) | dma_direct_offset;
 }
 
 static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr,
@@ -152,7 +156,8 @@ static int dma_direct_map_sg(struct devi
 	int i;
 
 	for (i = 0; i < nents; i++, sg++) {
-		sg->dma_address = page_to_phys(sg->page) + sg->offset;
+		sg->dma_address = (page_to_phys(sg->page) + sg->offset) |
+			dma_direct_offset;
 		sg->dma_length = sg->length;
 	}
 
Index: linux-cell/include/asm-powerpc/dma-mapping.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/dma-mapping.h	2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/include/asm-powerpc/dma-mapping.h	2006-11-10 16:45:21.000000000 +1100
@@ -187,6 +187,8 @@ static inline void dma_unmap_sg(struct d
 extern struct dma_mapping_ops dma_iommu_ops;
 extern struct dma_mapping_ops dma_direct_ops;
 
+extern unsigned long dma_direct_offset;
+
 #else /* CONFIG_PPC64 */
 
 #define dma_supported(dev, mask)	(1)

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

* Re: [PATCH 7/32] powerpc: Make pci_read_irq_line the default
  2006-11-10  7:44 ` [PATCH 7/32] powerpc: Make pci_read_irq_line the default Benjamin Herrenschmidt
@ 2006-11-14  5:47   ` Zang Roy-r61911
  2006-11-14  5:48     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 36+ messages in thread
From: Zang Roy-r61911 @ 2006-11-14  5:47 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list

On Fri, 2006-11-10 at 15:44, Benjamin Herrenschmidt wrote:

> I also haven't updated the old-style fixup code from 85xx_cds.c
> because it's actually buggy :) It assigns pci_dev->irq hard coded
> numbers which is no good with the new IRQ mapping code. It should
> at least use irq_create_mapping(NULL, hard_coded_number); and possibly
> also set_irq_type() to set them as level low.
> 
85xx cds is a little more complex. There are hardware revises.
Hope to fix it soon :-).
Roy 

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

* Re: [PATCH 7/32] powerpc: Make pci_read_irq_line the default
  2006-11-14  5:47   ` Zang Roy-r61911
@ 2006-11-14  5:48     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 36+ messages in thread
From: Benjamin Herrenschmidt @ 2006-11-14  5:48 UTC (permalink / raw)
  To: Zang Roy-r61911; +Cc: linuxppc-dev list

On Tue, 2006-11-14 at 13:47 +0800, Zang Roy-r61911 wrote:
> On Fri, 2006-11-10 at 15:44, Benjamin Herrenschmidt wrote:
> 
> > I also haven't updated the old-style fixup code from 85xx_cds.c
> > because it's actually buggy :) It assigns pci_dev->irq hard coded
> > numbers which is no good with the new IRQ mapping code. It should
> > at least use irq_create_mapping(NULL, hard_coded_number); and possibly
> > also set_irq_type() to set them as level low.
> > 
> 85xx cds is a little more complex. There are hardware revises.

In fact, my comment is partially wrong I noticed... That is, some of
those seem to have a 8259. In this case, the 8259 interrupts are always
down at 1...15 and can perfectly be hard coded in fixups as there is
always a 1:1 mapping between virq and hwirq for 8259 (that's what the
HOST_LEGACY choice is, specifically for 8259).

Ben.

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

end of thread, other threads:[~2006-11-14  5:49 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-10  7:44 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 2/32] Call platform_notify_remove later Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 1/32] ibmveth: Remove ibmveth "liobn" field Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 4/32] arch provides generic iomap missing accessors Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 3/32] Driver core: add notification of bus events Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 5/32] Add arch specific dev_sysdata to struct device Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 6/32] Change ACPI to use dev_sysdata instead of firmware_data Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 7/32] powerpc: Make pci_read_irq_line the default Benjamin Herrenschmidt
2006-11-14  5:47   ` Zang Roy-r61911
2006-11-14  5:48     ` Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 8/32] powerpc: Remove ppc_md.pci_map_irq & ppc_swizzle for ARCH=powerpc Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 9/32] powerpc: Generic DCR infrastructure Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 10/32] powerpc: Make EMAC use generic DCR access methods Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 11/32] powerpc: Support for DCR based MPIC Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 12/32] powerpc: Improve MPIC driver auto-configuration from DT Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 13/32] powerpc: Native cell support for MPIC in southbridge Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 14/32] powerpc: Souped-up of_platform_device support Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 16/32] powerpc: Refactor 64 bits DMA operations Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 15/32] powerpc: Hook of_platform_bus_probe with cell Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 17/32] powerpc: Add DMA ops support for of_plaform_device to Cell Benjamin Herrenschmidt
2006-11-10  7:44 ` [PATCH 18/32] powerpc: Resolve the parent address of a PCI bus range Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 19/32] powerpc: Resolve the BUID fir RTAS PCI config space accesses Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 20/32] powerpc: Add "parent" struct device for PCI host bridges Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 21/32] powerpc: Generic OF platform driver " Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 22/32] powerpc: Cell fixup DMA offset for new southbridge Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 23/32] powerpc: Allow hooking of PCI MMIO & PIO accessors on 64 bits Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 24/32] powerpc: Cell "Spider" MMIO workarounds Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 26/32] powerpc: Add an optional offset to direct DMA on 64 bits Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 25/32] powerpc: spider uses low level BE MMIO accessors Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 27/32] powerpc: Make direct DMA use node local allocations Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 28/32] powerpc: Make cell use direct DMA ops Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 29/32] powerpc: Cell iommu support Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 30/32] powerpc: remove ioremap64 and fixup_bigphys_addr Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 31/32] powerpc: Merge 32 and 64 bits asm-powerpc/io.h Benjamin Herrenschmidt
2006-11-10  7:45 ` [PATCH 32/32] powerpc: Fix a typo in new style SPE mapping code Benjamin Herrenschmidt
  -- strict thread matches above, loose matches on Subject: below --
2006-11-11  6:24 [PATCH 0/32] My current serie of patches for 2.6.20 for review Benjamin Herrenschmidt
2006-11-11  6:25 ` [PATCH 26/32] powerpc: Add an optional offset to direct DMA on 64 bits Benjamin Herrenschmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).