Commit 2ef9c88b authored by Russell King's avatar Russell King

[PCI] pci-8: pci_resource_to_bus()

Convert pcibios_fixup_pbus_ranges() into something more generic, namely
pcibios_resource_to_bus() - we are really trying to convert resources
to something to program into bus registers for bridge windows, and in
fact, PCI device BARs.

This is necessary since some architectures, namely Alpha, ARM and PARISC
have an offset between PCI addressing and host-based addressing, so
resources need to be adjusted when read or when written back to the bus.

We provide a generic version in asm-generic/pci.h, which most
architectures use.

This patch finds the following architectures with something to think
consider:

        - ppc, ppc64
                adjusts resources for devices, but not buses.
		This is inconsistent, and leads to improperly
		programmed windows/BARs.

PPC people (Anton) has a replacement PCI resource implementation
which should do the right thing.
parent 032d6c6e
......@@ -12,7 +12,7 @@
* Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
* PCI-PCI bridges cleanup
*/
#include <linux/config.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/init.h>
......@@ -334,21 +334,25 @@ common_swizzle(struct pci_dev *dev, u8 *pinp)
}
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges)
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res)
{
struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
unsigned long offset = 0;
if (res->flags & IORESOURCE_IO)
offset = hose->io_space->start;
else if (res->flags & IORESOURCE_MEM)
offset = hose->mem_space->start;
ranges->io_start -= hose->io_space->start;
ranges->io_end -= hose->io_space->start;
ranges->mem_start -= hose->mem_space->start;
ranges->mem_end -= hose->mem_space->start;
/* FIXME: On older alphas we could use dense memory space
to access prefetchable resources. */
ranges->prefetch_start -= hose->mem_space->start;
ranges->prefetch_end -= hose->mem_space->start;
region->start = res->start - offset;
region->end = res->end - offset;
}
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pcibios_resource_to_bus);
#endif
int
pcibios_enable_device(struct pci_dev *dev, int mask)
{
......
......@@ -439,18 +439,26 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
* Convert from Linux-centric to bus-centric addresses for bridge devices.
*/
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res)
{
struct pci_sys_data *root = bus->sysdata;
struct pci_sys_data *root = dev->sysdata;
unsigned long offset = 0;
if (res->flags & IORESOURCE_IO)
offset = root->io_offset;
if (res->flags & IORESOURCE_MEM)
offset = root->mem_offset;
ranges->io_start -= root->io_offset;
ranges->io_end -= root->io_offset;
ranges->mem_start -= root->mem_offset;
ranges->mem_end -= root->mem_offset;
ranges->prefetch_start -= root->mem_offset;
ranges->prefetch_end -= root->mem_offset;
region->start = res->start - offset;
region->end = res->end - offset;
}
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pcibios_fixup_bus);
EXPORT_SYMBOL(pcibios_resource_to_bus);
#endif
/*
* This is the standard PCI-PCI bridge swizzling algorithm:
*
......
......@@ -90,11 +90,6 @@ static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
}
}
void __devinit
pcibios_fixup_pbus_ranges (struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
{
}
/*
* Called after each bus is probed, but before its children
* are examined.
......
......@@ -168,11 +168,6 @@ pcibios_update_irq (struct pci_dev *dev, int irq)
/* ??? FIXME -- record old value for shutdown. */
}
void __devinit
pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
{
}
static inline int
pcibios_enable_resources (struct pci_dev *dev, int mask)
{
......
......@@ -297,11 +297,6 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
{
}
int pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd, old_cmd;
......
......@@ -341,8 +341,10 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
#if 0 /* original DDB5074 code */
void __devinit
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res)
{
/*
* our caller figure out range by going through the dev structures.
......@@ -350,15 +352,14 @@ void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus,
* different view of the addressing space.
*/
#if 0 /* original DDB5074 code */
if (bus->number == 0) {
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
}
#endif
}
#endif
int pcibios_enable_resources(struct pci_dev *dev)
{
......
......@@ -235,12 +235,6 @@ pcibios_fixup_bus(struct pci_bus *b)
pci_fixup_irqs(pci_swizzle, pci_map_irq);
}
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges)
{
}
int __init
pcibios_enable_device(struct pci_dev *dev)
{
......
......@@ -348,12 +348,6 @@ void __init pcibios_fixup_bus (struct pci_bus *b)
pci_fixup_irqs (macepci_swizzle, macepci_map_irq);
}
/* XXX anybody know what this is supposed to do? */
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges)
{
}
/*
* Handle errors from the bridge. This includes master and target aborts,
* various command and address errors, and the interrupt test. This gets
......
......@@ -344,13 +344,16 @@ pcibios_link_hba_resources( struct resource *hba_res, struct resource *r)
/*
** called by drivers/pci/setup-res.c:pci_setup_bridge().
*/
void __devinit pcibios_fixup_pbus_ranges(
struct pci_bus *bus,
struct pbus_set_ranges_data *ranges
void __devinit pcibios_resource_to_bus(
struct pci_dev *dev,
struct pci_bus_region *region,
struct resource *res
)
{
struct pci_bus *bus = dev->bus;
struct pci_hba_data *hba = HBA_DATA(bus->dev->platform_data);
if (res->flags & IORESOURCE_IO) {
/*
** I/O space may see busnumbers here. Something
** in the form of 0xbbxxxx where bb is the bus num
......@@ -358,16 +361,17 @@ void __devinit pcibios_fixup_pbus_ranges(
** Remaining address translation are done in the
** PCI Host adapter specific code - ie dino_out8.
*/
ranges->io_start = PCI_PORT_ADDR(ranges->io_start);
ranges->io_end = PCI_PORT_ADDR(ranges->io_end);
region->start = PCI_PORT_ADDR(res->start);
region->end = PCI_PORT_ADDR(res->end);
} else if (res->flags & IORESOURCE_MEM) {
/* Convert MMIO addr to PCI addr (undo global virtualization) */
ranges->mem_start = PCI_BUS_ADDR(hba, ranges->mem_start);
ranges->mem_end = PCI_BUS_ADDR(hba, ranges->mem_end);
region->start = PCI_BUS_ADDR(hba, res->start);
region->end = PCI_BUS_ADDR(hba, res->end);
}
DBG_RES("pcibios_fixup_pbus_ranges(%02x, [%lx,%lx %lx,%lx])\n", bus->number,
ranges->io_start, ranges->io_end,
ranges->mem_start, ranges->mem_end);
DBG_RES("pcibios_resource_to_bus(%02x %s [%lx,%lx])\n",
bus->number, res->flags & IORESOURCE_IO ? "IO" : "MEM",
region->start, region->end);
/* KLUGE ALERT
** if this resource isn't linked to a "parent", then it seems
......@@ -377,6 +381,10 @@ void __devinit pcibios_fixup_pbus_ranges(
pcibios_link_hba_resources(&hba->lmmio_space, bus->resource[1]);
}
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pcibios_resource_to_bus);
#endif
#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2))
......
......@@ -1107,11 +1107,6 @@ common_swizzle(struct pci_dev *dev, unsigned char *pinp)
return PCI_SLOT(dev->devfn);
}
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
{
}
unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
unsigned long start, unsigned long size)
{
......
......@@ -127,11 +127,6 @@ struct pci_dev *pci_find_dev_by_addr(unsigned long addr)
return NULL;
}
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
struct pbus_set_ranges_data *pranges)
{
}
void
pcibios_update_resource(struct pci_dev *dev, struct resource *res,
int resource)
......
......@@ -113,10 +113,6 @@ void pci_free_consistent(struct pci_dev *hwdev, size_t size,
}
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
{
}
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
struct list_head *ln;
......
......@@ -250,12 +250,6 @@ struct pci_fixup pcibios_fixups[] = {
{ 0 }
};
void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *b,
struct pbus_set_ranges_data *range)
{
/* No fixups needed */
}
/*
* Called after each bus is probed, but before its children
* are examined.
......
......@@ -380,12 +380,6 @@ static int __init map_harp_irq(struct pci_dev *dev, u8 slot, u8 pin)
}
void __devinit
pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
{
}
void __init pcibios_init(void)
{
extern unsigned long memory_start, memory_end;
......
......@@ -19,7 +19,6 @@
* pcibios_fixup_bus()
* pcibios_init()
* pcibios_setup()
* pcibios_fixup_pbus_ranges()
*/
#include <linux/kernel.h>
......
......@@ -72,40 +72,29 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
requires that if there is no I/O ports or memory behind the
bridge, corresponding range must be turned off by writing base
value greater than limit to the bridge's base/limit registers. */
static void __devinit
pci_setup_bridge(struct pci_bus *bus)
static void __devinit pci_setup_bridge(struct pci_bus *bus)
{
struct pbus_set_ranges_data ranges;
struct pci_dev *bridge = bus->self;
struct pci_bus_region region;
u32 l;
if (!bridge || (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
return;
ranges.io_start = bus->resource[0]->start;
ranges.io_end = bus->resource[0]->end;
ranges.mem_start = bus->resource[1]->start;
ranges.mem_end = bus->resource[1]->end;
ranges.prefetch_start = bus->resource[2]->start;
ranges.prefetch_end = bus->resource[2]->end;
pcibios_fixup_pbus_ranges(bus, &ranges);
DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n",
bus->number, bridge->dev.name));
/* Set up the top and bottom of the PCI I/O segment for this bus. */
pcibios_resource_to_bus(bridge, &region, bus->resource[0]);
if (bus->resource[0]->flags & IORESOURCE_IO) {
pci_read_config_dword(bridge, PCI_IO_BASE, &l);
l &= 0xffff0000;
l |= (ranges.io_start >> 8) & 0x00f0;
l |= ranges.io_end & 0xf000;
l |= (region.start >> 8) & 0x00f0;
l |= region.end & 0xf000;
/* Set up upper 16 bits of I/O base/limit. */
pci_write_config_word(bridge, PCI_IO_BASE_UPPER16,
ranges.io_start >> 16);
region.start >> 16);
pci_write_config_word(bridge, PCI_IO_LIMIT_UPPER16,
ranges.io_end >> 16);
region.end >> 16);
DBGC((KERN_INFO " IO window: %04lx-%04lx\n",
ranges.io_start, ranges.io_end));
region.start, region.end));
}
else {
/* Clear upper 16 bits of I/O base/limit. */
......@@ -117,11 +106,12 @@ pci_setup_bridge(struct pci_bus *bus)
/* Set up the top and bottom of the PCI Memory segment
for this bus. */
pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
if (bus->resource[1]->flags & IORESOURCE_MEM) {
l = (ranges.mem_start >> 16) & 0xfff0;
l |= ranges.mem_end & 0xfff00000;
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
DBGC((KERN_INFO " MEM window: %08lx-%08lx\n",
ranges.mem_start, ranges.mem_end));
region.start, region.end));
}
else {
l = 0x0000fff0;
......@@ -134,11 +124,12 @@ pci_setup_bridge(struct pci_bus *bus)
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
/* Set up PREF base/limit. */
pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
l = (ranges.prefetch_start >> 16) & 0xfff0;
l |= ranges.prefetch_end & 0xfff00000;
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
DBGC((KERN_INFO " PREFETCH window: %08lx-%08lx\n",
ranges.prefetch_start, ranges.prefetch_end));
region.start, region.end));
}
else {
l = 0x0000fff0;
......
......@@ -190,6 +190,11 @@ pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len,
/* Return the index of the PCI controller for device PDEV. */
extern int pci_controller_num(struct pci_dev *pdev);
extern void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res);
#endif /* __KERNEL__ */
/* Values for the `which' argument to sys_pciconfig_iobase. */
......
......@@ -175,6 +175,10 @@ void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
extern void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res);
#endif /* __KERNEL__ */
#endif
/*
* linux/include/asm-generic/pci.h
*
* Copyright (C) 2003 Russell King
*/
#ifndef _ASM_GENERIC_PCI_H
#define _ASM_GENERIC_PCI_H
/**
* pcibios_resource_to_bus - convert resource to PCI bus address
* @dev: device which owns this resource
* @region: converted bus-centric region (start,end)
* @res: resource to convert
*
* Convert a resource to a PCI device bus address or bus window.
*/
static inline void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res)
{
region->start = res->start;
region->end = res->end;
}
#endif
......@@ -105,4 +105,7 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
/* implement the pci_ DMA API in terms of the generic device dma_ one */
#include <asm-generic/pci-dma-compat.h>
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* __i386_PCI_H */
......@@ -97,4 +97,7 @@ extern int pcibios_prep_mwi (struct pci_dev *);
extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* _ASM_IA64_PCI_H */
......@@ -252,4 +252,7 @@ extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
#endif /* __KERNEL__ */
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* _ASM_PCI_H */
......@@ -272,4 +272,8 @@ static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
#endif /* __KERNEL__ */
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* _ASM_PCI_H */
......@@ -186,4 +186,8 @@ extern inline void pcibios_register_hba(struct pci_hba_data *x)
/* export the pci_ DMA API in terms of the dma_ one */
#include <asm-generic/pci-dma-compat.h>
extern void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res);
#endif /* __ASM_PARISC_PCI_H */
......@@ -273,4 +273,7 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
#endif /* __KERNEL__ */
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* __PPC_PCI_H */
......@@ -124,4 +124,7 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
#endif /* __KERNEL__ */
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* __PPC64_PCI_H */
......@@ -240,6 +240,8 @@ static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
#endif /* __KERNEL__ */
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* __ASM_SH_PCI_H */
......@@ -207,4 +207,7 @@ extern int pcibios_prep_mwi(struct pci_dev *dev);
#endif /* __KERNEL__ */
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* __SPARC64_PCI_H */
......@@ -279,4 +279,7 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
#endif /* __KERNEL__ */
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* __x8664_PCI_H */
......@@ -485,11 +485,9 @@ struct pci_ops {
int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
};
struct pbus_set_ranges_data
{
unsigned long io_start, io_end;
unsigned long mem_start, mem_end;
unsigned long prefetch_start, prefetch_end;
struct pci_bus_region {
unsigned long start;
unsigned long end;
};
struct pci_driver {
......@@ -533,7 +531,6 @@ void pcibios_align_resource(void *, struct resource *,
unsigned long, unsigned long);
void pcibios_update_resource(struct pci_dev *, struct resource *, int);
void pcibios_update_irq(struct pci_dev *, int irq);
void pcibios_fixup_pbus_ranges(struct pci_bus *, struct pbus_set_ranges_data *);
/* Generic PCI functions used internally */
......
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