Skip to content

Commit

Permalink
[POWERPC] Improve resource setup of PowerMac G5 HT bridge
Browse files Browse the repository at this point in the history
The device node for the HT bridge on G5s doesn't contain useful ranges.

We used to give it a bunch of the known PCI space and then punch a "hole"
in it based on where the AGP or PCIe region was.  This reworks it to
use the actual register in the bridge that controls the decoding instead.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Benjamin Herrenschmidt authored and Paul Mackerras committed Dec 20, 2007
1 parent 444532d commit d0264ce
Showing 1 changed file with 64 additions and 78 deletions.
142 changes: 64 additions & 78 deletions arch/powerpc/platforms/powermac/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@
static int has_uninorth;
#ifdef CONFIG_PPC64
static struct pci_controller *u3_agp;
static struct pci_controller *u4_pcie;
static struct pci_controller *u3_ht;
#else
static int has_second_ohare;
#endif /* CONFIG_PPC64 */
Expand Down Expand Up @@ -779,16 +777,50 @@ static void __init setup_u4_pcie(struct pci_controller* hose)
*/
hose->first_busno = 0x00;
hose->last_busno = 0xff;
u4_pcie = hose;
}

static void __init parse_region_decode(struct pci_controller *hose,
u32 decode)
{
unsigned long base, end, next = -1;
int i, cur = -1;

/* Iterate through all bits. We ignore the last bit as this region is
* reserved for the ROM among other niceties
*/
for (i = 0; i < 31; i++) {
if ((decode & (0x80000000 >> i)) == 0)
continue;
if (i < 16) {
base = 0xf0000000 | (((u32)i) << 24);
end = base + 0x00ffffff;
} else {
base = ((u32)i-16) << 28;
end = base + 0x0fffffff;
}
if (base != next) {
if (++cur >= 3) {
printk(KERN_WARNING "PCI: Too many ranges !\n");
break;
}
hose->mem_resources[cur].flags = IORESOURCE_MEM;
hose->mem_resources[cur].name = hose->dn->full_name;
hose->mem_resources[cur].start = base;
hose->mem_resources[cur].end = end;
DBG(" %d: 0x%08lx-0x%08lx\n", cur, base, end);
} else {
DBG(" : -0x%08lx\n", end);
hose->mem_resources[cur].end = end;
}
next = end + 1;
}
}

static void __init setup_u3_ht(struct pci_controller* hose)
{
struct device_node *np = hose->dn;
struct pci_controller *other = NULL;
struct resource cfg_res, self_res;
int i, cur;

u32 decode;

hose->ops = &u3_ht_pci_ops;

Expand All @@ -808,12 +840,9 @@ static void __init setup_u3_ht(struct pci_controller* hose)
self_res.end - self_res.start + 1);

/*
* /ht node doesn't expose a "ranges" property, so we "remove"
* regions that have been allocated to AGP. So far, this version of
* the code doesn't assign any of the 0xfxxxxxxx "fine" memory regions
* to /ht. We need to fix that sooner or later by either parsing all
* child "ranges" properties or figuring out the U3 address space
* decoding logic and then read its configuration register (if any).
* /ht node doesn't expose a "ranges" property, we read the register
* that controls the decoding logic and use that for memory regions.
* The IO region is hard coded since it is fixed in HW as well.
*/
hose->io_base_phys = 0xf4000000;
hose->pci_io_size = 0x00400000;
Expand All @@ -824,76 +853,33 @@ static void __init setup_u3_ht(struct pci_controller* hose)
hose->pci_mem_offset = 0;
hose->first_busno = 0;
hose->last_busno = 0xef;
hose->mem_resources[0].name = np->full_name;
hose->mem_resources[0].start = 0x80000000;
hose->mem_resources[0].end = 0xefffffff;
hose->mem_resources[0].flags = IORESOURCE_MEM;

u3_ht = hose;

if (u3_agp != NULL)
other = u3_agp;
else if (u4_pcie != NULL)
other = u4_pcie;

if (other == NULL) {
DBG("U3/4 has no AGP/PCIE, using full resource range\n");
return;
}
/* Note: fix offset when cfg_addr becomes a void * */
decode = in_be32(hose->cfg_addr + 0x80);

/* Fixup bus range vs. PCIE */
if (u4_pcie)
hose->last_busno = u4_pcie->first_busno - 1;
DBG("PCI: Apple HT bridge decode register: 0x%08x\n", decode);

/* We "remove" the AGP resources from the resources allocated to HT,
* that is we create "holes". However, that code does assumptions
* that so far happen to be true (cross fingers...), typically that
* resources in the AGP node are properly ordered
/* NOTE: The decode register setup is a bit weird... region
* 0xf8000000 for example is marked as enabled in there while it's
& actually the memory controller registers.
* That means that we are incorrectly attributing it to HT.
*
* In a similar vein, region 0xf4000000 is actually the HT IO space but
* also marked as enabled in here and 0xf9000000 is used by some other
* internal bits of the northbridge.
*
* Unfortunately, we can't just mask out those bit as we would end
* up with more regions than we can cope (linux can only cope with
* 3 memory regions for a PHB at this stage).
*
* So for now, we just do a little hack. We happen to -know- that
* Apple firmware doesn't assign things below 0xfa000000 for that
* bridge anyway so we mask out all bits we don't want.
*/
cur = 0;
for (i=0; i<3; i++) {
struct resource *res = &other->mem_resources[i];
if (res->flags != IORESOURCE_MEM)
continue;
/* We don't care about "fine" resources */
if (res->start >= 0xf0000000)
continue;
/* Check if it's just a matter of "shrinking" us in one
* direction
*/
if (hose->mem_resources[cur].start == res->start) {
DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
cur, hose->mem_resources[cur].start,
res->end + 1);
hose->mem_resources[cur].start = res->end + 1;
continue;
}
if (hose->mem_resources[cur].end == res->end) {
DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
cur, hose->mem_resources[cur].end,
res->start - 1);
hose->mem_resources[cur].end = res->start - 1;
continue;
}
/* No, it's not the case, we need a hole */
if (cur == 2) {
/* not enough resources for a hole, we drop part
* of the range
*/
printk(KERN_WARNING "Running out of resources"
" for /ht host !\n");
hose->mem_resources[cur].end = res->start - 1;
continue;
}
cur++;
DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
cur-1, res->start - 1, cur, res->end + 1);
hose->mem_resources[cur].name = np->full_name;
hose->mem_resources[cur].flags = IORESOURCE_MEM;
hose->mem_resources[cur].start = res->end + 1;
hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
hose->mem_resources[cur-1].end = res->start - 1;
}
decode &= 0x003fffff;

/* Now parse the resulting bits and build resources */
parse_region_decode(hose, decode);
}
#endif /* CONFIG_PPC64 */

Expand Down

0 comments on commit d0264ce

Please sign in to comment.