Commit 1c4c0ff6 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ppc64: Fix POWER3 TCE allocation

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
parent f75bd853
...@@ -44,16 +44,6 @@ ...@@ -44,16 +44,6 @@
#include "pci.h" #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, static void tce_build_pSeries(struct iommu_table *tbl, long index,
long npages, unsigned long uaddr, long npages, unsigned long uaddr,
int direction) int direction)
...@@ -97,13 +87,23 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) ...@@ -97,13 +87,23 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages)
} }
static void iommu_buses_init(void) static void iommu_buses_init(void)
{ {
struct pci_controller* phb; struct pci_controller* phb;
struct device_node *dn, *first_dn; struct device_node *dn, *first_dn;
int num_slots, num_slots_ilog2; int num_slots, num_slots_ilog2;
int first_phb = 1; 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 /* XXX Should we be using pci_root_buses instead? -ojn
*/ */
...@@ -119,7 +119,7 @@ static void iommu_buses_init(void) ...@@ -119,7 +119,7 @@ static void iommu_buses_init(void)
if ((1<<num_slots_ilog2) != num_slots) if ((1<<num_slots_ilog2) != num_slots)
num_slots_ilog2++; 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. /* Reserve 16MB of DMA space on the first PHB.
* We should probably be more careful and use firmware props. * We should probably be more careful and use firmware props.
...@@ -167,7 +167,7 @@ static void iommu_table_setparms(struct pci_controller *phb, ...@@ -167,7 +167,7 @@ static void iommu_table_setparms(struct pci_controller *phb,
{ {
phandle node; phandle node;
unsigned long i; unsigned long i;
struct _of_tce_table *oft; struct of_tce_table *oft;
node = ((struct device_node *)(phb->arch_data))->node; node = ((struct device_node *)(phb->arch_data))->node;
......
...@@ -146,8 +146,8 @@ extern struct rtas_t rtas; ...@@ -146,8 +146,8 @@ extern struct rtas_t rtas;
extern unsigned long klimit; extern unsigned long klimit;
extern struct lmb lmb; extern struct lmb lmb;
#define MAX_PHB 16 * 3 // 16 Towers * 3 PHBs/tower #define MAX_PHB (32 * 6) /* 32 drawers * 6 PHBs/drawer */
struct _of_tce_table of_tce_table[MAX_PHB + 1] = {{0, 0, 0}}; struct of_tce_table of_tce_table[MAX_PHB + 1];
char *bootpath = 0; char *bootpath = 0;
char *bootdevice = 0; char *bootdevice = 0;
...@@ -808,7 +808,7 @@ prom_initialize_tce_table(void) ...@@ -808,7 +808,7 @@ prom_initialize_tce_table(void)
unsigned long i, table = 0; unsigned long i, table = 0;
unsigned long base, vbase, align; unsigned long base, vbase, align;
unsigned int minalign, minsize; 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; unsigned long tce_entry, *tce_entryp;
#ifdef DEBUG_PROM #ifdef DEBUG_PROM
...@@ -817,6 +817,12 @@ prom_initialize_tce_table(void) ...@@ -817,6 +817,12 @@ prom_initialize_tce_table(void)
/* Search all nodes looking for PHBs. */ /* Search all nodes looking for PHBs. */
for (node = 0; prom_next_node(&node); ) { 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; compatible[0] = 0;
type[0] = 0; type[0] = 0;
model[0] = 0; model[0] = 0;
...@@ -856,20 +862,21 @@ prom_initialize_tce_table(void) ...@@ -856,20 +862,21 @@ prom_initialize_tce_table(void)
minsize = 4UL << 20; 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. * 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 * By doing this, we avoid the pitfalls of trying to DMA to
* MMIO space and the DMA alias hole. * MMIO space and the DMA alias hole.
*/ *
/*
* On POWER4, firmware sets the TCE region by assuming * On POWER4, firmware sets the TCE region by assuming
* each TCE table is 8MB. Using this memory for anything * each TCE table is 8MB. Using this memory for anything
* else will impact performance, so we always allocate 8MB. * else will impact performance, so we always allocate 8MB.
* Anton * 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 to the greater of the align or size */
align = max(minalign, minsize); align = max(minalign, minsize);
......
...@@ -60,4 +60,6 @@ extern unsigned long __init lmb_phys_mem_size(void); ...@@ -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_end_of_DRAM(void);
extern unsigned long __init lmb_abs_to_phys(unsigned long); extern unsigned long __init lmb_abs_to_phys(unsigned long);
extern unsigned long io_hole_start;
#endif /* _PPC64_LMB_H */ #endif /* _PPC64_LMB_H */
...@@ -87,11 +87,12 @@ union pci_range { ...@@ -87,11 +87,12 @@ union pci_range {
} pci64; } pci64;
}; };
struct _of_tce_table { struct of_tce_table {
phandle node; phandle node;
unsigned long base; unsigned long base;
unsigned long size; unsigned long size;
}; };
extern struct of_tce_table of_tce_table[];
struct reg_property { struct reg_property {
unsigned long address; unsigned long address;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment