Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 114655
b: refs/heads/master
c: b556151
h: refs/heads/master
i:
  114653: 1fea1ef
  114651: 1cba234
  114647: d2fe768
  114639: baeabcd
  114623: f572d57
v: v3
  • Loading branch information
Benjamin Herrenschmidt committed Oct 14, 2008
1 parent 7944cb6 commit 34d2d6d
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 48 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: eef2622a9fcfa964073333ea72c7c9cd20ad45e6
refs/heads/master: b556151110ff003ce77d84597400c84824690ccf
163 changes: 116 additions & 47 deletions trunk/arch/powerpc/kernel/pci-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,11 +780,6 @@ static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)

res->start = (res->start + offset) & mask;
res->end = (res->end + offset) & mask;

pr_debug("PCI:%s %016llx-%016llx\n",
pci_name(dev),
(unsigned long long)res->start,
(unsigned long long)res->end);
}


Expand Down Expand Up @@ -830,6 +825,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
(unsigned int)res->flags);

fixup_resource(res, dev);

pr_debug("PCI:%s %016llx-%016llx\n",
pci_name(dev),
(unsigned long long)res->start,
(unsigned long long)res->end);
}

/* Call machine specific resource fixup */
Expand All @@ -838,58 +838,127 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);

static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
/* This function tries to figure out if a bridge resource has been initialized
* by the firmware or not. It doesn't have to be absolutely bullet proof, but
* things go more smoothly when it gets it right. It should covers cases such
* as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
*/
static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
struct resource *res)
{
struct pci_controller *hose = pci_bus_to_host(bus);
struct pci_dev *dev = bus->self;
resource_size_t offset;
u16 command;
int i;

pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
/* We don't do anything if PCI_PROBE_ONLY is set */
if (ppc_pci_flags & PPC_PCI_PROBE_ONLY)
return 0;

/* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
* now differently between 32 and 64 bits.
*/
if (dev != NULL) {
struct resource *res;
int i;
/* Job is a bit different between memory and IO */
if (res->flags & IORESOURCE_MEM) {
/* If the BAR is non-0 (res != pci_mem_offset) then it's probably been
* initialized by somebody
*/
if (res->start != hose->pci_mem_offset)
return 0;

for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
if ((res = bus->resource[i]) == NULL)
continue;
if (!res->flags)
continue;
if (i >= 3 && bus->self->transparent)
continue;
/* On PowerMac, Apple leaves bridge windows open over
* an inaccessible region of memory space (0...fffff)
* which is somewhat bogus, but that's what they think
* means disabled...
*
* We clear those to force them to be reallocated later
*
* We detect such regions by the fact that the base is
* equal to the pci_mem_offset of the host bridge and
* their size is smaller than 1M.
*/
if (res->flags & IORESOURCE_MEM &&
res->start == hose->pci_mem_offset &&
res->end < 0x100000) {
printk(KERN_INFO
"PCI: Closing bogus Apple Firmware"
" region %d on bus 0x%02x\n",
i, bus->number);
res->flags = 0;
continue;
}
/* The BAR is 0, let's check if memory decoding is enabled on
* the bridge. If not, we consider it unassigned
*/
pci_read_config_word(dev, PCI_COMMAND, &command);
if ((command & PCI_COMMAND_MEMORY) == 0)
return 1;

pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
pci_name(dev), i,
(unsigned long long)res->start,\
(unsigned long long)res->end,
(unsigned int)res->flags);
/* Memory decoding is enabled and the BAR is 0. If any of the bridge
* resources covers that starting address (0 then it's good enough for
* us for memory
*/
for (i = 0; i < 3; i++) {
if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
hose->mem_resources[i].start == hose->pci_mem_offset)
return 0;
}

/* Well, it starts at 0 and we know it will collide so we may as
* well consider it as unassigned. That covers the Apple case.
*/
return 1;
} else {
/* If the BAR is non-0, then we consider it assigned */
offset = (unsigned long)hose->io_base_virt - _IO_BASE;
if (((res->start - offset) & 0xfffffffful) != 0)
return 0;

/* Here, we are a bit different than memory as typically IO space
* starting at low addresses -is- valid. What we do instead if that
* we consider as unassigned anything that doesn't have IO enabled
* in the PCI command register, and that's it.
*/
pci_read_config_word(dev, PCI_COMMAND, &command);
if (command & PCI_COMMAND_IO)
return 0;

/* It's starting at 0 and IO is disabled in the bridge, consider
* it unassigned
*/
return 1;
}
}

/* Fixup resources of a PCI<->PCI bridge */
static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
{
struct resource *res;
int i;

struct pci_dev *dev = bus->self;

fixup_resource(res, dev);
for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
if ((res = bus->resource[i]) == NULL)
continue;
if (!res->flags)
continue;
if (i >= 3 && bus->self->transparent)
continue;

pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
pci_name(dev), i,
(unsigned long long)res->start,\
(unsigned long long)res->end,
(unsigned int)res->flags);

/* Perform fixup */
fixup_resource(res, dev);

/* Try to detect uninitialized P2P bridge resources,
* and clear them out so they get re-assigned later
*/
if (pcibios_uninitialized_bridge_resource(bus, res)) {
res->flags = 0;
pr_debug("PCI:%s (unassigned)\n", pci_name(dev));
} else {

pr_debug("PCI:%s %016llx-%016llx\n",
pci_name(dev),
(unsigned long long)res->start,
(unsigned long long)res->end);
}
}
}

static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_dev *dev = bus->self;

pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");

/* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
* now differently between 32 and 64 bits.
*/
if (dev != NULL)
pcibios_fixup_bridge(bus);

/* Additional setup that is different between 32 and 64 bits for now */
pcibios_do_bus_setup(bus);
Expand Down

0 comments on commit 34d2d6d

Please sign in to comment.