]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/sparc64/kernel/pci_schizo.c
regression: disable timer peek-ahead for 2.6.28
[linux-2.6-omap-h63xx.git] / arch / sparc64 / kernel / pci_schizo.c
index 9248c6737f0e90b83f0d5aca16240236b3ea4a9f..45d9dba1ba117a9d652727f9968dc13ee690b7cd 100644 (file)
@@ -1,6 +1,6 @@
 /* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
  *
- * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2002, 2003, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/upa.h>
 #include <asm/pstate.h>
 #include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
 
-/* All SCHIZO registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define schizo_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define schizo_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
+#define DRIVER_NAME    "schizo"
+#define PFX            DRIVER_NAME ": "
 
 /* This is a convention that at least Excalibur and Merlin
  * follow.  I suppose the SCHIZO used in Starcat and friends
@@ -163,25 +146,25 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
         * invalidating it before it has a chance to reach
         * main memory.
         */
-       control = schizo_read(strbuf->strbuf_control);
-       schizo_write(strbuf->strbuf_control,
-                    (control | SCHIZO_STRBUF_CTRL_DENAB));
+       control = upa_readq(strbuf->strbuf_control);
+       upa_writeq((control | SCHIZO_STRBUF_CTRL_DENAB),
+                  strbuf->strbuf_control);
        for (i = 0; i < 128; i++) {
                unsigned long val;
 
-               val = schizo_read(err_base + (i * 8UL));
-               schizo_write(err_base + (i * 8UL), 0UL);
+               val = upa_readq(err_base + (i * 8UL));
+               upa_writeq(0UL, err_base + (i * 8UL));
                stc_error_buf[i] = val;
        }
        for (i = 0; i < 16; i++) {
-               stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL));
-               stc_line_buf[i] = schizo_read(line_base + (i * 8UL));
-               schizo_write(tag_base + (i * 8UL), 0UL);
-               schizo_write(line_base + (i * 8UL), 0UL);
+               stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+               stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+               upa_writeq(0UL, tag_base + (i * 8UL));
+               upa_writeq(0UL, line_base + (i * 8UL));
        }
 
        /* OK, state is logged, exit diagnostic mode. */
-       schizo_write(strbuf->strbuf_control, control);
+       upa_writeq(control, strbuf->strbuf_control);
 
        for (i = 0; i < 16; i++) {
                int j, saw_error, first, last;
@@ -258,14 +241,14 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
        int i;
 
        spin_lock_irqsave(&iommu->lock, flags);
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        if (control & SCHIZO_IOMMU_CTRL_XLTEERR) {
                unsigned long base;
                char *type_string;
 
                /* Clear the error encountered bit. */
                control &= ~SCHIZO_IOMMU_CTRL_XLTEERR;
-               schizo_write(iommu->iommu_control, control);
+               upa_writeq(control, iommu->iommu_control);
 
                switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
                case 0:
@@ -295,24 +278,24 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
                 * get as much diagnostic information to the
                 * console as we can.
                 */
-               schizo_write(iommu->iommu_control,
-                            control | SCHIZO_IOMMU_CTRL_DENAB);
+               upa_writeq(control | SCHIZO_IOMMU_CTRL_DENAB,
+                          iommu->iommu_control);
 
                base = pbm->pbm_regs;
 
                for (i = 0; i < 16; i++) {
                        iommu_tag[i] =
-                               schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL));
+                               upa_readq(base + SCHIZO_IOMMU_TAG + (i * 8UL));
                        iommu_data[i] =
-                               schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL));
+                               upa_readq(base + SCHIZO_IOMMU_DATA + (i * 8UL));
 
                        /* Now clear out the entry. */
-                       schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0);
-                       schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0);
+                       upa_writeq(0, base + SCHIZO_IOMMU_TAG + (i * 8UL));
+                       upa_writeq(0, base + SCHIZO_IOMMU_DATA + (i * 8UL));
                }
 
                /* Leave diagnostic mode. */
-               schizo_write(iommu->iommu_control, control);
+               upa_writeq(control, iommu->iommu_control);
 
                for (i = 0; i < 16; i++) {
                        unsigned long tag, data;
@@ -357,11 +340,12 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static void schizo_check_iommu_error(struct pci_controller_info *p,
+static void schizo_check_iommu_error(struct pci_pbm_info *pbm,
                                     enum schizo_error_type type)
 {
-       schizo_check_iommu_error_pbm(&p->pbm_A, type);
-       schizo_check_iommu_error_pbm(&p->pbm_B, type);
+       schizo_check_iommu_error_pbm(pbm, type);
+       if (pbm->sibling)
+               schizo_check_iommu_error_pbm(pbm->sibling, type);
 }
 
 /* Uncorrectable ECC error status gathering. */
@@ -386,14 +370,13 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
 static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
        unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported, limit;
 
        /* Latch uncorrectable error status. */
-       afar = schizo_read(afar_reg);
+       afar = upa_readq(afar_reg);
 
        /* If either of the error pending bits are set in the
         * AFSR, the error status is being actively updated by
@@ -401,7 +384,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
         */
        limit = 1000;
        do {
-               afsr = schizo_read(afsr_reg);
+               afsr = upa_readq(afsr_reg);
        } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
 
        /* Clear the primary/secondary error status bits. */
@@ -410,7 +393,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
                 SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
        if (!error_bits)
                return IRQ_NONE;
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -449,7 +432,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
        printk("]\n");
 
        /* Interrogate IOMMU for error status. */
-       schizo_check_iommu_error(p, UE_ERR);
+       schizo_check_iommu_error(pbm, UE_ERR);
 
        return IRQ_HANDLED;
 }
@@ -481,7 +464,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
        int reported, limit;
 
        /* Latch error status. */
-       afar = schizo_read(afar_reg);
+       afar = upa_readq(afar_reg);
 
        /* If either of the error pending bits are set in the
         * AFSR, the error status is being actively updated by
@@ -489,7 +472,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
         */
        limit = 1000;
        do {
-               afsr = schizo_read(afsr_reg);
+               afsr = upa_readq(afsr_reg);
        } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
 
        /* Clear primary/secondary error status bits. */
@@ -498,7 +481,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
                 SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
        if (!error_bits)
                return IRQ_NONE;
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Correctable Error, primary error type[%s]\n",
@@ -600,7 +583,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
        u16 stat;
 
        csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL;
-       csr = schizo_read(csr_reg);
+       csr = upa_readq(csr_reg);
        csr_error_bits =
                csr & (SCHIZO_PCICTRL_BUS_UNUS |
                       SCHIZO_PCICTRL_TTO_ERR |
@@ -610,7 +593,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
                       SCHIZO_PCICTRL_SERR);
        if (csr_error_bits) {
                /* Clear the errors.  */
-               schizo_write(csr_reg, csr);
+               upa_writeq(csr, csr_reg);
 
                /* Log 'em.  */
                if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS)
@@ -650,7 +633,6 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
 static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        unsigned long afsr_reg, afar_reg, base;
        unsigned long afsr, afar, error_bits;
        int reported;
@@ -661,8 +643,8 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
        afar_reg = base + SCHIZO_PCI_AFAR;
 
        /* Latch error status. */
-       afar = schizo_read(afar_reg);
-       afsr = schizo_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear primary/secondary error status bits. */
        error_bits = afsr &
@@ -674,7 +656,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
                 SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
        if (!error_bits)
                return schizo_pcierr_intr_other(pbm);
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: PCI Error, primary error type[%s]\n",
@@ -744,7 +726,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
         * a bug in the IOMMU support code or a PCI device driver.
         */
        if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
-               schizo_check_iommu_error(p, PCI_ERR);
+               schizo_check_iommu_error(pbm, PCI_ERR);
                pci_scan_for_target_abort(pbm, pbm->pci_bus);
        }
        if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
@@ -805,12 +787,11 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
 static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        u64 errlog;
 
-       errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
-                    errlog & ~(SAFARI_ERRLOG_ERROUT));
+       errlog = upa_readq(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+       upa_writeq(errlog & ~(SAFARI_ERRLOG_ERROUT),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
 
        if (!(errlog & BUS_ERROR_UNMAP)) {
                printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
@@ -821,7 +802,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 
        printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
               pbm->name);
-       schizo_check_iommu_error(p, SAFARI_ERR);
+       schizo_check_iommu_error(pbm, SAFARI_ERR);
 
        return IRQ_HANDLED;
 }
@@ -863,7 +844,7 @@ static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
  */
 static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->prom_node);
+       struct of_device *op = of_find_device_by_node(pbm->op->node);
        u64 tmp, err_mask, err_no_mask;
        int err;
 
@@ -910,10 +891,9 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
        }
 
        /* Enable UE and CE interrupts for controller. */
-       schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
-                    (SCHIZO_ECCCTRL_EE |
-                     SCHIZO_ECCCTRL_UE |
-                     SCHIZO_ECCCTRL_CE));
+       upa_writeq((SCHIZO_ECCCTRL_EE |
+                   SCHIZO_ECCCTRL_UE |
+                   SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
 
        /* Enable PCI Error interrupts and clear error
         * bits.
@@ -926,10 +906,10 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 
        err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
        tmp |= err_mask;
        tmp &= ~err_no_mask;
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
        err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
                    SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -938,7 +918,7 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
                    SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
                    SCHIZO_PCIAFSR_STTO);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+       upa_writeq(err_mask, pbm->pbm_regs + SCHIZO_PCI_AFSR);
 
        err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
                    BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -950,16 +930,16 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
                    BUS_ERROR_APERR | BUS_ERROR_UNMAP |
                    BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
-                    (SCHIZO_SAFERRCTRL_EN | err_mask));
+       upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
-                    (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
+       upa_writeq((SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)),
+                  pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL);
 }
 
 static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->prom_node);
+       struct of_device *op = of_find_device_by_node(pbm->op->node);
        u64 tmp, err_mask, err_no_mask;
        int err;
 
@@ -1006,10 +986,9 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
        }
 
        /* Enable UE and CE interrupts for controller. */
-       schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
-                    (SCHIZO_ECCCTRL_EE |
-                     SCHIZO_ECCCTRL_UE |
-                     SCHIZO_ECCCTRL_CE));
+       upa_writeq((SCHIZO_ECCCTRL_EE |
+                   SCHIZO_ECCCTRL_UE |
+                   SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
 
        err_mask = (SCHIZO_PCICTRL_BUS_UNUS |
                    SCHIZO_PCICTRL_ESLCK |
@@ -1025,18 +1004,18 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
        /* Enable PCI Error interrupts and clear error
         * bits for each PBM.
         */
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
        tmp |= err_mask;
        tmp &= ~err_no_mask;
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
-                    (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
-                     SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
-                     SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
-                     SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
-                     SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
-                     SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
+       upa_writeq((SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+                   SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+                   SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+                   SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+                   SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+                   SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS),
+                  pbm->pbm_regs + SCHIZO_PCI_AFSR);
 
        /* Make all Safari error conditions fatal except unmapped
         * errors which we make generate interrupts.
@@ -1063,8 +1042,8 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
                      BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
 #endif
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
-                    (SCHIZO_SAFERRCTRL_EN | err_mask));
+       upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
 }
 
 static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1084,14 +1063,15 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void __init schizo_scan_bus(struct pci_pbm_info *pbm)
+static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
+                                     struct device *parent)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable =
-               (of_find_property(pbm->prom_node, "66mhz-capable", NULL)
+               (of_find_property(pbm->op->node, "66mhz-capable", NULL)
                 != NULL);
 
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
                tomatillo_register_error_handlers(pbm);
@@ -1133,12 +1113,12 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
         * streaming buffer and leave the rerun-disable
         * setting however OBP set it.
         */
-       control = schizo_read(pbm->stc.strbuf_control);
+       control = upa_readq(pbm->stc.strbuf_control);
        control &= ~(SCHIZO_STRBUF_CTRL_LPTR |
                     SCHIZO_STRBUF_CTRL_LENAB |
                     SCHIZO_STRBUF_CTRL_DENAB);
        control |= SCHIZO_STRBUF_CTRL_ENAB;
-       schizo_write(pbm->stc.strbuf_control, control);
+       upa_writeq(control, pbm->stc.strbuf_control);
 
        pbm->stc.strbuf_enabled = 1;
 }
@@ -1150,24 +1130,17 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
 
 static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 {
-       struct iommu *iommu = pbm->iommu;
+       static const u32 vdma_default[] = { 0xc0000000, 0x40000000 };
        unsigned long i, tagbase, database;
-       struct property *prop;
-       u32 vdma[2], dma_mask;
+       struct iommu *iommu = pbm->iommu;
        int tsbsize, err;
+       const u32 *vdma;
+       u32 dma_mask;
        u64 control;
 
-       prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
-       if (prop) {
-               u32 *val = prop->value;
-
-               vdma[0] = val[0];
-               vdma[1] = val[1];
-       } else {
-               /* No property, use default values. */
-               vdma[0] = 0xc0000000;
-               vdma[1] = 0x40000000;
-       }
+       vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+       if (!vdma)
+               vdma = vdma_default;
 
        dma_mask = vdma[0];
        switch (vdma[1]) {
@@ -1187,9 +1160,9 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
                        break;
 
                default:
-                       prom_printf("SCHIZO: strange virtual-dma size.\n");
-                       prom_halt();
-       };
+                       printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+                       return -EINVAL;
+       }
 
        /* Register addresses, SCHIZO has iommu ctx flushing. */
        iommu->iommu_control  = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
@@ -1206,15 +1179,15 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
        /*
         * Invalidate TLB Entries.
         */
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        control |= SCHIZO_IOMMU_CTRL_DENAB;
-       schizo_write(iommu->iommu_control, control);
+       upa_writeq(control, iommu->iommu_control);
 
        tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA;
 
-       for(i = 0; i < 16; i++) {
-               schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0);
-               schizo_write(pbm->pbm_regs + database + (i * 8UL), 0);
+       for (i = 0; i < 16; i++) {
+               upa_writeq(0, pbm->pbm_regs + tagbase + (i * 8UL));
+               upa_writeq(0, pbm->pbm_regs + database + (i * 8UL));
        }
 
        /* Leave diag mode enabled for full-flushing done
@@ -1222,12 +1195,14 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
         */
        err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
                               pbm->numa_node);
-       if (err)
+       if (err) {
+               printk(KERN_ERR PFX "iommu_table_init() fails with %d\n", err);
                return err;
+       }
 
-       schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
+       upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
 
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
        switch (tsbsize) {
        case 64:
@@ -1236,10 +1211,10 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
        case 128:
                control |= SCHIZO_IOMMU_TSBSZ_128K;
                break;
-       };
+       }
 
        control |= SCHIZO_IOMMU_CTRL_ENAB;
-       schizo_write(iommu->iommu_control, control);
+       upa_writeq(control, iommu->iommu_control);
 
        return 0;
 }
@@ -1280,12 +1255,11 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 
 static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
 {
-       struct property *prop;
        u64 tmp;
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
+       upa_writeq(5, pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY);
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
        /* Enable arbiter for all PCI slots.  */
        tmp |= 0xff;
@@ -1294,8 +1268,7 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
            pbm->chip_version >= 0x2)
                tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
 
-       prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
-       if (!prop)
+       if (!of_find_property(pbm->op->node, "no-bus-parking", NULL))
                tmp |= SCHIZO_PCICTRL_PARK;
        else
                tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1311,13 +1284,13 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
                        SCHIZO_PCICTRL_RDO_PREF |
                        SCHIZO_PCICTRL_RDL_PREF);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_DIAG);
        tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB |
                 SCHIZO_PCIDIAG_D_RETRY |
                 SCHIZO_PCIDIAG_D_INTSYNC);
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_DIAG);
 
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
                /* Clear prefetch lengths to workaround a bug in
@@ -1329,17 +1302,16 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
                       TOMATILLO_IOC_RDONE_CPENAB |
                       TOMATILLO_IOC_RDLINE_CPENAB);
 
-               schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR,
-                            tmp);
+               upa_writeq(tmp, pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR);
        }
 }
 
-static int __init schizo_pbm_init(struct pci_controller_info *p,
-                                 struct device_node *dp, u32 portid,
-                                 int chip_type)
+static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
+                                    struct of_device *op, u32 portid,
+                                    int chip_type)
 {
        const struct linux_prom64_registers *regs;
-       struct pci_pbm_info *pbm;
+       struct device_node *dp = op->node;
        const char *chipset_name;
        int is_pbm_a, err;
 
@@ -1372,25 +1344,19 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
        regs = of_get_property(dp, "reg", NULL);
 
        is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
-       if (is_pbm_a)
-               pbm = &p->pbm_A;
-       else
-               pbm = &p->pbm_B;
 
        pbm->next = pci_pbm_root;
        pci_pbm_root = pbm;
 
        pbm->numa_node = -1;
 
-       pbm->scan_bus = schizo_scan_bus;
        pbm->pci_ops = &sun4u_pci_ops;
        pbm->config_space_reg_bits = 8;
 
        pbm->index = pci_num_pbms++;
 
        pbm->portid = portid;
-       pbm->parent = p;
-       pbm->prom_node = dp;
+       pbm->op = op;
 
        pbm->chip_type = chip_type;
        pbm->chip_version = of_getintprop_default(dp, "version#", 0);
@@ -1420,6 +1386,8 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
 
        schizo_pbm_strbuf_init(pbm);
 
+       schizo_scan_bus(pbm, &op->dev);
+
        return 0;
 }
 
@@ -1433,62 +1401,104 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
        return (x == y);
 }
 
-static void __init __schizo_init(struct device_node *dp, char *model_name,
-                                int chip_type)
+static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
+                                                          int chip_type)
 {
-       struct pci_controller_info *p;
+       struct pci_pbm_info *pbm;
+
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+               if (portid_compare(pbm->portid, portid, chip_type))
+                       return pbm;
+       }
+       return NULL;
+}
+
+static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
+{
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
        u32 portid;
+       int err;
 
        portid = of_getintprop_default(dp, "portid", 0xff);
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               if (portid_compare(pbm->portid, portid, chip_type)) {
-                       if (schizo_pbm_init(pbm->parent, dp,
-                                           portid, chip_type))
-                               goto fatal_memory_error;
-                       return;
-               }
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+               goto out_err;
+       }
+
+       pbm->sibling = schizo_find_sibling(portid, chip_type);
+
+       iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
+               goto out_free_pbm;
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       if (schizo_pbm_init(pbm, op, portid, chip_type))
+               goto out_free_iommu;
 
-       p->pbm_A.iommu = iommu;
+       if (pbm->sibling)
+               pbm->sibling->sibling = pbm;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       dev_set_drvdata(&op->dev, pbm);
 
-       p->pbm_B.iommu = iommu;
+       return 0;
 
-       if (schizo_pbm_init(p, dp, portid, chip_type))
-               goto fatal_memory_error;
+out_free_iommu:
+       kfree(pbm->iommu);
 
-       return;
+out_free_pbm:
+       kfree(pbm);
 
-fatal_memory_error:
-       prom_printf("SCHIZO: Fatal memory allocation error.\n");
-       prom_halt();
+out_err:
+       return err;
 }
 
-void __init schizo_init(struct device_node *dp, char *model_name)
+static int __devinit schizo_probe(struct of_device *op,
+                                 const struct of_device_id *match)
 {
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
+       return __schizo_init(op, (unsigned long) match->data);
 }
 
-void __init schizo_plus_init(struct device_node *dp, char *model_name)
-{
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
-}
+/* The ordering of this table is very important.  Some Tomatillo
+ * nodes announce that they are compatible with both pci108e,a801
+ * and pci108e,8001.  So list the chips in reverse chronological
+ * order.
+ */
+static struct of_device_id __initdata schizo_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pci108e,a801",
+               .data = (void *) PBM_CHIP_TYPE_TOMATILLO,
+       },
+       {
+               .name = "pci",
+               .compatible = "pci108e,8002",
+               .data = (void *) PBM_CHIP_TYPE_SCHIZO_PLUS,
+       },
+       {
+               .name = "pci",
+               .compatible = "pci108e,8001",
+               .data = (void *) PBM_CHIP_TYPE_SCHIZO,
+       },
+       {},
+};
 
-void __init tomatillo_init(struct device_node *dp, char *model_name)
+static struct of_platform_driver schizo_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = schizo_match,
+       .probe          = schizo_probe,
+};
+
+static int __init schizo_init(void)
 {
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
+       return of_register_driver(&schizo_driver, &of_bus_type);
 }
+
+subsys_initcall(schizo_init);