sparc64: Start commonizing code common between SABRE and PSYCHO.
authorDavid S. Miller <davem@davemloft.net>
Wed, 10 Sep 2008 10:07:03 +0000 (03:07 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 11 Sep 2008 06:11:56 +0000 (23:11 -0700)
These are very similar chips, in fact they are identical in some
macro blocks.

So start commonizing code which they can share.  We begin with
the IOMMU initialization sequence.

Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/pci_psycho.c
arch/sparc64/kernel/pci_sabre.c
arch/sparc64/kernel/psycho_common.c [new file with mode: 0644]
arch/sparc64/kernel/psycho_common.h [new file with mode: 0644]

index fb02807..c0b8009 100644 (file)
@@ -16,7 +16,7 @@ obj-y         := process.o setup.o cpu.o idprom.o reboot.o \
 
 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
index 4562b3e..4681e3d 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
 #define DRIVER_NAME    "psycho"
 #define PFX            DRIVER_NAME ": "
@@ -787,63 +788,6 @@ static void __init psycho_scan_bus(struct pci_pbm_info *pbm,
        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
@@ -1053,9 +997,14 @@ static int __devinit psycho_probe(struct of_device *op,
 
        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);
index 196049b..a3a276d 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
 #define DRIVER_NAME    "sabre"
 #define PFX            DRIVER_NAME ": "
@@ -674,66 +675,6 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm,
        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)
 {
@@ -862,7 +803,7 @@ static int __devinit sabre_probe(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;
 
diff --git a/arch/sparc64/kernel/psycho_common.c b/arch/sparc64/kernel/psycho_common.c
new file mode 100644 (file)
index 0000000..07acc13
--- /dev/null
@@ -0,0 +1,93 @@
+/* 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;
+
+}
diff --git a/arch/sparc64/kernel/psycho_common.h b/arch/sparc64/kernel/psycho_common.h
new file mode 100644 (file)
index 0000000..bffaff5
--- /dev/null
@@ -0,0 +1,8 @@
+#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 */