]> git.hungrycats.org Git - linux/commitdiff
[PATCH] ppc64: Fix POWER3 TCE allocation
authorAndrew Morton <akpm@osdl.org>
Thu, 18 Mar 2004 22:59:02 +0000 (14:59 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 18 Mar 2004 22:59:02 +0000 (14:59 -0800)
From: Anton Blanchard <anton@samba.org>

- Fix for machines with 3GB IO holes (eg nighthawk).
- Increase the maximum number of PHBs and warn if we exceed this (we used
  to walk off the end of the array)
- Only allocate an 8MB TCE table on POWER4

arch/ppc64/kernel/pSeries_iommu.c
arch/ppc64/kernel/prom.c
include/asm-ppc64/lmb.h
include/asm-ppc64/prom.h

index 8a4612c60624d610f5cd60e92e94ea813c8fe23c..72c6726f5a07c60766679d676f515c6ee91755cc 100644 (file)
 #include "pci.h"
 
 
-/* Only used to pass OF initialization data set in prom.c into the main 
- * kernel code -- data ultimately copied into regular tce tables.
- */
-extern struct _of_tce_table of_tce_table[];
-
-
-extern struct pci_controller  *hose_head;
-extern struct pci_controller **hose_tail;
-
-
 static void tce_build_pSeries(struct iommu_table *tbl, long index, 
                              long npages, unsigned long uaddr, 
                              int direction)
@@ -97,13 +87,23 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages)
 }
 
 
-
 static void iommu_buses_init(void)
 {
        struct pci_controller* phb;
        struct device_node *dn, *first_dn;
        int num_slots, num_slots_ilog2;
        int first_phb = 1;
+       unsigned long tcetable_ilog2;
+
+       /*
+        * We default to a TCE table that maps 2GB (4MB table, 22 bits),
+        * however some machines have a 3GB IO hole and for these we
+        * create a table that maps 1GB (2MB table, 21 bits)
+        */
+       if (io_hole_start < 0x80000000UL)
+               tcetable_ilog2 = 21;
+       else
+               tcetable_ilog2 = 22;
 
        /* XXX Should we be using pci_root_buses instead?  -ojn 
         */
@@ -119,7 +119,7 @@ static void iommu_buses_init(void)
                if ((1<<num_slots_ilog2) != num_slots)
                        num_slots_ilog2++;
 
-               phb->dma_window_size = 1 << (22 - num_slots_ilog2);
+               phb->dma_window_size = 1 << (tcetable_ilog2 - num_slots_ilog2);
 
                /* Reserve 16MB of DMA space on the first PHB.
                 * We should probably be more careful and use firmware props.
@@ -167,7 +167,7 @@ static void iommu_table_setparms(struct pci_controller *phb,
 {
        phandle node;
        unsigned long i;
-       struct _of_tce_table *oft;
+       struct of_tce_table *oft;
 
        node = ((struct device_node *)(phb->arch_data))->node;
 
index be56fe9c7b0b47227e60611cfe07db321ae1c802..4c0d1eddcef4a862fb15339324445c6aeccd7ebb 100644 (file)
@@ -146,8 +146,8 @@ extern struct rtas_t rtas;
 extern unsigned long klimit;
 extern struct lmb lmb;
 
-#define MAX_PHB 16 * 3  // 16 Towers * 3 PHBs/tower
-struct _of_tce_table of_tce_table[MAX_PHB + 1] = {{0, 0, 0}};
+#define MAX_PHB (32 * 6)  /* 32 drawers * 6 PHBs/drawer */
+struct of_tce_table of_tce_table[MAX_PHB + 1];
 
 char *bootpath = 0;
 char *bootdevice = 0;
@@ -808,7 +808,7 @@ prom_initialize_tce_table(void)
        unsigned long i, table = 0;
        unsigned long base, vbase, align;
        unsigned int minalign, minsize;
-       struct _of_tce_table *prom_tce_table = RELOC(of_tce_table);
+       struct of_tce_table *prom_tce_table = RELOC(of_tce_table);
        unsigned long tce_entry, *tce_entryp;
 
 #ifdef DEBUG_PROM
@@ -817,6 +817,12 @@ prom_initialize_tce_table(void)
 
        /* Search all nodes looking for PHBs. */
        for (node = 0; prom_next_node(&node); ) {
+               if (table == MAX_PHB) {
+                       prom_print(RELOC("WARNING: PCI host bridge ignored, "
+                                        "need to increase MAX_PHB\n"));
+                       continue;
+               }
+
                compatible[0] = 0;
                type[0] = 0;
                model[0] = 0;
@@ -856,20 +862,21 @@ prom_initialize_tce_table(void)
                        minsize = 4UL << 20;
                }
 
-               /* Even though we read what OF wants, we just set the table
+               /*
+                * Even though we read what OF wants, we just set the table
                 * size to 4 MB.  This is enough to map 2GB of PCI DMA space.
                 * By doing this, we avoid the pitfalls of trying to DMA to
                 * MMIO space and the DMA alias hole.
-                */
-               /* 
+                *
                 * On POWER4, firmware sets the TCE region by assuming
                 * each TCE table is 8MB. Using this memory for anything
                 * else will impact performance, so we always allocate 8MB.
                 * Anton
-                *
-                * XXX FIXME use a cpu feature here
                 */
-               minsize = 8UL << 20;
+               if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
+                       minsize = 8UL << 20;
+               else
+                       minsize = 4UL << 20;
 
                /* Align to the greater of the align or size */
                align = max(minalign, minsize);
index c50670d7e3145b79e7cfb7f5db885b5c52ab43bb..43a2f70cf4d305e29196b4bf63a8b1c36c740aec 100644 (file)
@@ -60,4 +60,6 @@ extern unsigned long __init lmb_phys_mem_size(void);
 extern unsigned long __init lmb_end_of_DRAM(void);
 extern unsigned long __init lmb_abs_to_phys(unsigned long);
 
+extern unsigned long io_hole_start;
+
 #endif /* _PPC64_LMB_H */
index d82661b4488b8688cc3b83429197971181d28a5c..95fea643e01f4fb3296260e5a028c2a59e20286d 100644 (file)
@@ -87,11 +87,12 @@ union pci_range {
        } pci64;
 };
 
-struct _of_tce_table {
+struct of_tce_table {
        phandle node;
        unsigned long base;
        unsigned long size;
 };
+extern struct of_tce_table of_tce_table[];
 
 struct reg_property {
        unsigned long address;