Skip to content

Commit

Permalink
[POWERPC] Merge PCI resource fixups
Browse files Browse the repository at this point in the history
The PCI code in 32 and 64 bits fixes up resources differently.

32 bits uses a header quirk plus handles bridges in pcibios_fixup_bus()
while 64 bits does things in various places depending on whether you
are using OF probing, using PCI hotplug, etc...

This merges those by basically using the 32 bits approach for both,
with various tweaks to make 64 bits work with the new approach.

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 fe2d338 commit bf5e2ba
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 188 deletions.
130 changes: 130 additions & 0 deletions arch/powerpc/kernel/pci-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -691,3 +691,133 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
res->end = (region->end + offset) & mask;
}
EXPORT_SYMBOL(pcibios_bus_to_resource);

/* Fixup a bus resource into a linux resource */
static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
resource_size_t offset = 0, mask = (resource_size_t)-1;

if (res->flags & IORESOURCE_IO) {
offset = (unsigned long)hose->io_base_virt - _IO_BASE;
mask = 0xffffffffu;
} else if (res->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;

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);
}


/* This header fixup will do the resource fixup for all devices as they are
* probed, but not for bridge ranges
*/
static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
int i;

if (!hose) {
printk(KERN_ERR "No host bridge for PCI dev %s !\n",
pci_name(dev));
return;
}
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
struct resource *res = dev->resource + i;
if (!res->flags)
continue;
if (res->end == 0xffffffff) {
pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] is unassigned\n",
pci_name(dev), i,
(unsigned long long)res->start,
(unsigned long long)res->end,
(unsigned int)res->flags);
res->end -= res->start;
res->start = 0;
res->flags |= IORESOURCE_UNSET;
continue;
}

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

fixup_resource(res, dev);
}

/* Call machine specific resource fixup */
if (ppc_md.pcibios_fixup_resources)
ppc_md.pcibios_fixup_resources(dev);
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);

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) {
struct resource *res;
int i;

for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
if ((res = bus->resource[i]) == NULL)
continue;
if (!res->flags || 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);

fixup_resource(res, dev);
}
}

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

/* Platform specific bus fixups */
if (ppc_md.pcibios_fixup_bus)
ppc_md.pcibios_fixup_bus(bus);

/* Read default IRQs and fixup if necessary */
list_for_each_entry(dev, &bus->devices, bus_list) {
pci_read_irq_line(dev);
if (ppc_md.pci_irq_fixup)
ppc_md.pci_irq_fixup(dev);
}
}

void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
/* When called from the generic PCI probe, read PCI<->PCI bridge
* bases before proceeding
*/
if (bus->self != NULL)
pci_read_bridge_bases(bus);
__pcibios_fixup_bus(bus);
}
EXPORT_SYMBOL(pcibios_fixup_bus);

/* When building a bus from the OF tree rather than probing, we need a
* slightly different version of the fixup which doesn't read the
* bridge bases using config space accesses
*/
void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus)
{
__pcibios_fixup_bus(bus);
}
83 changes: 2 additions & 81 deletions arch/powerpc/kernel/pci_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ unsigned int ppc_pci_flags;

void pcibios_make_OF_bus_map(void);

static void pcibios_fixup_resources(struct pci_dev* dev);
static void fixup_broken_pcnet32(struct pci_dev* dev);
static int reparent_resources(struct resource *parent, struct resource *res);
static void fixup_cpc710_pci64(struct pci_dev* dev);
Expand Down Expand Up @@ -98,53 +97,6 @@ fixup_cpc710_pci64(struct pci_dev* dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);

static void
pcibios_fixup_resources(struct pci_dev *dev)
{
struct pci_controller* hose = (struct pci_controller *)dev->sysdata;
int i;
resource_size_t offset, mask;

if (!hose) {
printk(KERN_ERR "No hose for PCI dev %s!\n", pci_name(dev));
return;
}
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
struct resource *res = dev->resource + i;
if (!res->flags)
continue;
if (res->end == 0xffffffff) {
DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n",
pci_name(dev), i, (u64)res->start, (u64)res->end);
res->end -= res->start;
res->start = 0;
res->flags |= IORESOURCE_UNSET;
continue;
}
offset = 0;
mask = (resource_size_t)-1;
if (res->flags & IORESOURCE_MEM) {
offset = hose->pci_mem_offset;
} else if (res->flags & IORESOURCE_IO) {
offset = (unsigned long) hose->io_base_virt
- isa_io_base;
mask = 0xffffffffu;
}
if (offset != 0) {
res->start = (res->start + offset) & mask;
res->end = (res->end + offset) & mask;
DBG("PCI: Fixup res %d (0x%lx) of dev %s: %llx -> %llx\n",
i, res->flags, pci_name(dev),
(u64)res->start - offset, (u64)res->start);
}
}

/* Call machine specific resource fixup */
if (ppc_md.pcibios_fixup_resources)
ppc_md.pcibios_fixup_resources(dev);
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);

static int skip_isa_ioresource_align(struct pci_dev *dev)
{
if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) &&
Expand Down Expand Up @@ -757,14 +709,14 @@ pcibios_init(void)

subsys_initcall(pcibios_init);

void pcibios_fixup_bus(struct pci_bus *bus)
void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
{
struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
unsigned long io_offset;
struct resource *res;
struct pci_dev *dev;
int i;

/* Hookup PHB resources */
io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
if (bus->parent == NULL) {
/* This is a host bridge - fill in its resources */
Expand Down Expand Up @@ -795,37 +747,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
}
bus->resource[i+1] = res;
}
} else {
/* This is a subordinate bridge */
pci_read_bridge_bases(bus);

for (i = 0; i < 4; ++i) {
if ((res = bus->resource[i]) == NULL)
continue;
if (!res->flags || bus->self->transparent)
continue;
if (io_offset && (res->flags & IORESOURCE_IO)) {
res->start = (res->start + io_offset) &
0xffffffffu;
res->end = (res->end + io_offset) &
0xffffffffu;
} else if (hose->pci_mem_offset
&& (res->flags & IORESOURCE_MEM)) {
res->start += hose->pci_mem_offset;
res->end += hose->pci_mem_offset;
}
}
}

/* Platform specific bus fixups */
if (ppc_md.pcibios_fixup_bus)
ppc_md.pcibios_fixup_bus(bus);

/* Read default IRQs and fixup if necessary */
list_for_each_entry(dev, &bus->devices, bus_list) {
pci_read_irq_line(dev);
if (ppc_md.pci_irq_fixup)
ppc_md.pci_irq_fixup(dev);
}
}

Expand Down
Loading

0 comments on commit bf5e2ba

Please sign in to comment.