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 @@
#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;
......
......@@ -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
*/
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);
......
......@@ -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 */
......@@ -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;
......
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