obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PCI)       += pci.o pci_common.o \
+obj-$(CONFIG_PCI)       += pci.o pci_common.o psycho_common.o \
                            pci_psycho.o pci_sabre.o pci_schizo.o \
                            pci_sun4v.o pci_sun4v_asm.o pci_fire.o
 obj-$(CONFIG_PCI_MSI)  += pci_msi.o
 
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
 #define DRIVER_NAME    "psycho"
 #define PFX            DRIVER_NAME ": "
        psycho_register_error_handlers(pbm);
 }
 
-static int psycho_iommu_init(struct pci_pbm_info *pbm)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long i;
-       u64 control;
-       int err;
-
-       /* Register addresses. */
-       iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
-       iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
-       iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
-       iommu->iommu_tags     = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-
-       /* PSYCHO's IOMMU lacks ctx flushing. */
-       iommu->iommu_ctxflush = 0;
-
-       /* We use the main control register of PSYCHO as the write
-        * completion register.
-        */
-       iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
-
-       /*
-        * Invalidate TLB Entries.
-        */
-       control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
-       control |= PSYCHO_IOMMU_CTRL_DENAB;
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-       for (i = 0; i < 16; i++) {
-               psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-               psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
-       }
-
-       /* Leave diag mode enabled for full-flushing done
-        * in pci_iommu.c
-        */
-       err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff,
-                              pbm->numa_node);
-       if (err) {
-               printk(KERN_ERR PFX "iommu_table_init() fails\n");
-               return err;
-       }
-
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
-                    __pa(iommu->page_table));
-
-       control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
-       control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
-       control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-
-       /* If necessary, hook us up for starfire IRQ translations. */
-       if (this_is_starfire)
-               starfire_hookup(pbm->portid);
-
-       return 0;
-}
-
 #define PSYCHO_IRQ_RETRY       0x1a00UL
 #define PSYCHO_PCIA_DIAG       0x2020UL
 #define PSYCHO_PCIB_DIAG       0x4020UL
 
        psycho_controller_hwinit(pbm);
        if (!pbm->sibling) {
-               err = psycho_iommu_init(pbm);
+               err = psycho_iommu_init(pbm, 128, 0xc0000000,
+                                       0xffffffff, PSYCHO_CONTROL);
                if (err)
                        goto out_free_iommu;
+
+               /* If necessary, hook us up for starfire IRQ translations. */
+               if (this_is_starfire)
+                       starfire_hookup(pbm->portid);
        }
 
        psycho_pbm_init(pbm, op, is_pbm_a);
 
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
 #define DRIVER_NAME    "sabre"
 #define PFX            DRIVER_NAME ": "
        sabre_register_error_handlers(pbm);
 }
 
-static int sabre_iommu_init(struct pci_pbm_info *pbm,
-                           int tsbsize, unsigned long dvma_offset,
-                           u32 dma_mask)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long i;
-       u64 control;
-       int err;
-
-       /* Register addresses. */
-       iommu->iommu_control  = pbm->controller_regs + SABRE_IOMMU_CONTROL;
-       iommu->iommu_tsbbase  = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
-       iommu->iommu_flush    = pbm->controller_regs + SABRE_IOMMU_FLUSH;
-       iommu->iommu_tags     = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-       iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
-       /* Sabre's IOMMU lacks ctx flushing. */
-       iommu->iommu_ctxflush = 0;
-                                        
-       /* Invalidate TLB Entries. */
-       control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
-       control |= SABRE_IOMMUCTRL_DENAB;
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
-       for(i = 0; i < 16; i++) {
-               sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
-               sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
-       }
-
-       /* Leave diag mode enabled for full-flushing done
-        * in pci_iommu.c
-        */
-       err = iommu_table_init(iommu, tsbsize * 1024 * 8,
-                              dvma_offset, dma_mask, pbm->numa_node);
-       if (err) {
-               printk(KERN_ERR PFX "iommu_table_init() failed\n");
-               return err;
-       }
-
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
-                   __pa(iommu->page_table));
-
-       control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
-       control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
-       control |= SABRE_IOMMUCTRL_ENAB;
-       switch(tsbsize) {
-       case 64:
-               control |= SABRE_IOMMU_TSBSZ_64K;
-               break;
-       case 128:
-               control |= SABRE_IOMMU_TSBSZ_128K;
-               break;
-       default:
-               printk(KERN_ERR PFX "Illegal TSB size %d\n", tsbsize);
-               return -EINVAL;
-       }
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
-       return 0;
-}
-
 static void __init sabre_pbm_init(struct pci_pbm_info *pbm,
                                  struct of_device *op)
 {
                        goto out_free_iommu;
        }
 
-       err = sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask);
+       err = psycho_iommu_init(pbm, tsbsize, vdma[0], dma_mask, SABRE_WRSYNC);
        if (err)
                goto out_free_iommu;
 
 
--- /dev/null
+/* psycho_common.c: Code common to PSYCHO and derivative PCI controllers.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+
+#include <asm/upa.h>
+
+#include "pci_impl.h"
+#include "psycho_common.h"
+
+#define PSYCHO_IOMMU_TAG               0xa580UL
+#define PSYCHO_IOMMU_DATA              0xa600UL
+
+static void psycho_iommu_flush(struct pci_pbm_info *pbm)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               unsigned long off = i * 8;
+
+               upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_TAG + off);
+               upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_DATA + off);
+       }
+}
+
+#define PSYCHO_IOMMU_CONTROL           0x0200UL
+#define  PSYCHO_IOMMU_CTRL_TSBSZ       0x0000000000070000UL
+#define  PSYCHO_IOMMU_TSBSZ_1K         0x0000000000000000UL
+#define  PSYCHO_IOMMU_TSBSZ_2K         0x0000000000010000UL
+#define  PSYCHO_IOMMU_TSBSZ_4K         0x0000000000020000UL
+#define  PSYCHO_IOMMU_TSBSZ_8K         0x0000000000030000UL
+#define  PSYCHO_IOMMU_TSBSZ_16K        0x0000000000040000UL
+#define  PSYCHO_IOMMU_TSBSZ_32K        0x0000000000050000UL
+#define  PSYCHO_IOMMU_TSBSZ_64K        0x0000000000060000UL
+#define  PSYCHO_IOMMU_TSBSZ_128K       0x0000000000070000UL
+#define  PSYCHO_IOMMU_CTRL_TBWSZ       0x0000000000000004UL
+#define  PSYCHO_IOMMU_CTRL_DENAB       0x0000000000000002UL
+#define  PSYCHO_IOMMU_CTRL_ENAB        0x0000000000000001UL
+#define PSYCHO_IOMMU_FLUSH             0x0210UL
+#define PSYCHO_IOMMU_TSBBASE           0x0208UL
+
+int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+                     u32 dvma_offset, u32 dma_mask,
+                     unsigned long write_complete_offset)
+{
+       struct iommu *iommu = pbm->iommu;
+       u64 control;
+       int err;
+
+       iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
+       iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
+       iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
+       iommu->iommu_tags     = pbm->controller_regs + PSYCHO_IOMMU_TAG;
+       iommu->write_complete_reg = (pbm->controller_regs +
+                                    write_complete_offset);
+
+       iommu->iommu_ctxflush = 0;
+
+       control = upa_readq(iommu->iommu_control);
+       control |= PSYCHO_IOMMU_CTRL_DENAB;
+       upa_writeq(control, iommu->iommu_control);
+
+       psycho_iommu_flush(pbm);
+
+       /* Leave diag mode enabled for full-flushing done in pci_iommu.c */
+       err = iommu_table_init(iommu, tsbsize * 1024 * 8,
+                              dvma_offset, dma_mask, pbm->numa_node);
+       if (err)
+               return err;
+
+       upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
+
+       control = upa_readq(iommu->iommu_control);
+       control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
+       control |= PSYCHO_IOMMU_CTRL_ENAB;
+
+       switch (tsbsize) {
+       case 64:
+               control |= PSYCHO_IOMMU_TSBSZ_64K;
+               break;
+       case 128:
+               control |= PSYCHO_IOMMU_TSBSZ_128K;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       upa_writeq(control, iommu->iommu_control);
+
+       return 0;
+
+}
 
--- /dev/null
+#ifndef _PSYCHO_COMMON_H
+#define _PSYCHO_COMMON_H
+
+extern int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+                            u32 dvma_offset, u32 dma_mask,
+                            unsigned long write_complete_offset);
+
+#endif /* _PSYCHO_COMMON_H */