X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc%2Fkernel%2Fpci.c;h=04d04c5bfdd0ed79b16b45cf4ee3edec8edf5cd8;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=5b49655343bb312c153d2aff76b1b907e61dd8b3;hpb=daddc0d38b3571bed170afa273a49a0eba090c1e;p=linux-2.6.git diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 5b4965534..04d04c5bf 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,5 +1,5 @@ /* - * Common pmac/prep/chrp pci routines. -- Cort + * Common prep/chrp pci routines. -- Cort */ #include @@ -21,6 +21,7 @@ #include #include #include +#include #undef DEBUG @@ -33,6 +34,7 @@ unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; unsigned long pci_dram_offset = 0; +int pcibios_assign_bus_offset = 1; void pcibios_make_OF_bus_map(void); @@ -43,63 +45,29 @@ static void update_bridge_base(struct pci_bus *bus, int i); 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_rev1_53c810(struct pci_dev* dev); static void fixup_cpc710_pci64(struct pci_dev* dev); -#ifdef CONFIG_PPC_PMAC -extern void pmac_pci_fixup_cardbus(struct pci_dev* dev); -extern void pmac_pci_fixup_pciata(struct pci_dev* dev); -extern void pmac_pci_fixup_k2_sata(struct pci_dev* dev); -#endif #ifdef CONFIG_PPC_OF static u8* pci_to_OF_bus_map; #endif -/* By default, we don't re-assign bus numbers. We do this only on - * some pmacs +/* By default, we don't re-assign bus numbers. */ -int pci_assign_all_busses; +int pci_assign_all_buses; struct pci_controller* hose_head; struct pci_controller** hose_tail = &hose_head; static int pci_bus_count; -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810 }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64}, - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, -#ifdef CONFIG_PPC_PMAC - /* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus }, - { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata }, -#endif /* CONFIG_PPC_PMAC */ - { 0 } -}; - -static void -fixup_rev1_53c810(struct pci_dev* dev) -{ - /* rev 1 ncr53c810 chips don't set the class at all which means - * they don't get their resources remapped. Fix that here. - */ - - if ((dev->class == PCI_CLASS_NOT_DEFINED)) { - printk("NCR 53c810 rev 1 detected, setting PCI class.\n"); - dev->class = PCI_CLASS_STORAGE_SCSI; - } -} - static void fixup_broken_pcnet32(struct pci_dev* dev) { if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { dev->vendor = PCI_VENDOR_ID_AMD; pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); - pci_name_device(dev); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); static void fixup_cpc710_pci64(struct pci_dev* dev) @@ -112,6 +80,7 @@ fixup_cpc710_pci64(struct pci_dev* dev) dev->resource[1].start = dev->resource[1].end = 0; dev->resource[1].flags = 0; } +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) @@ -128,7 +97,7 @@ pcibios_fixup_resources(struct pci_dev *dev) struct resource *res = dev->resource + i; if (!res->flags) continue; - if (!res->start || res->end == 0xffffffff) { + if (res->end == 0xffffffff) { DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n", pci_name(dev), i, res->start, res->end); res->end -= res->start; @@ -158,9 +127,9 @@ pcibios_fixup_resources(struct pci_dev *dev) 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); -void -pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, +void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, struct resource *res) { unsigned long offset = 0; @@ -173,6 +142,22 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, region->start = res->start - offset; region->end = res->end - offset; } +EXPORT_SYMBOL(pcibios_resource_to_bus); + +void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, + struct pci_bus_region *region) +{ + unsigned long offset = 0; + struct pci_controller *hose = dev->sysdata; + + if (hose && res->flags & IORESOURCE_IO) + offset = (unsigned long)hose->io_base_virt - isa_io_base; + else if (hose && res->flags & IORESOURCE_MEM) + offset = hose->pci_mem_offset; + res->start = region->start + offset; + res->end = region->end + offset; +} +EXPORT_SYMBOL(pcibios_bus_to_resource); /* * We need to avoid collisions with `mirrored' VGA ports @@ -187,8 +172,7 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, * but we want to try to avoid allocating at 0x2900-0x2bff * which might have be mirrored at 0x0100-0x03ff.. */ -void -pcibios_align_resource(void *data, struct resource *res, unsigned long size, +void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align) { struct pci_dev *dev = data; @@ -208,7 +192,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size, } } } - +EXPORT_SYMBOL(pcibios_align_resource); /* * Handle resources of PCI devices. If the world were perfect, we could @@ -246,14 +230,12 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size, static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { - struct list_head *ln; struct pci_bus *bus; int i; struct resource *res, *pr; /* Depth-First Search on bus tree */ - for (ln = bus_list->next; ln != bus_list; ln=ln->next) { - bus = pci_bus_b(ln); + list_for_each_entry(bus, bus_list, node) { for (i = 0; i < 4; ++i) { if ((res = bus->resource[i]) == NULL || !res->flags || res->start > res->end) @@ -347,6 +329,8 @@ pci_relocate_bridge_resource(struct pci_bus *bus, int i) return -1; } res = bus->resource[i]; + if (res == NULL) + return -1; pr = NULL; for (j = 0; j < 4; j++) { struct resource *r = parent->resource[j]; @@ -394,7 +378,6 @@ probe_resource(struct pci_bus *parent, struct resource *pr, struct pci_bus *bus; struct pci_dev *dev; struct resource *r; - struct list_head *ln; int i; for (r = pr->child; r != NULL; r = r->sibling) { @@ -403,9 +386,7 @@ probe_resource(struct pci_bus *parent, struct resource *pr, return 1; } } - for (ln = parent->children.next; ln != &parent->children; - ln = ln->next) { - bus = pci_bus_b(ln); + list_for_each_entry(bus, &parent->children, node) { for (i = 0; i < 4; ++i) { if ((r = bus->resource[i]) == NULL) continue; @@ -419,13 +400,12 @@ probe_resource(struct pci_bus *parent, struct resource *pr, } } } - for (ln = parent->devices.next; ln != &parent->devices; ln=ln->next) { - dev = pci_dev_b(ln); + list_for_each_entry(dev, &parent->devices, bus_list) { for (i = 0; i < 6; ++i) { r = &dev->resource[i]; if (!r->flags || (r->flags & IORESOURCE_UNSET)) continue; - if (pci_find_parent_resource(bus->self, r) != pr) + if (pci_find_parent_resource(dev, r) != pr) continue; if (r->end >= res->start && res->end >= r->start) { *conflict = r; @@ -522,7 +502,7 @@ pcibios_allocate_resources(int pass) u16 command; struct resource *r; - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) { pci_read_config_word(dev, PCI_COMMAND, &command); for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -540,11 +520,11 @@ pcibios_allocate_resources(int pass) if (pass) continue; r = &dev->resource[PCI_ROM_RESOURCE]; - if (r->flags & PCI_ROM_ADDRESS_ENABLE) { + if (r->flags & IORESOURCE_ROM_ENABLE) { /* Turn the ROM off, leave the resource region, but keep it unregistered. */ u32 reg; DBG("PCI: Switching off ROM of %s\n", pci_name(dev)); - r->flags &= ~PCI_ROM_ADDRESS_ENABLE; + r->flags &= ~IORESOURCE_ROM_ENABLE; pci_read_config_dword(dev, dev->rom_base_reg, ®); pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); @@ -559,7 +539,7 @@ pcibios_assign_resources(void) int idx; struct resource *r; - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ @@ -649,7 +629,7 @@ pcibios_alloc_controller(void) /* * Functions below are used on OpenFirmware machines. */ -static void __openfirmware +static void make_one_node_map(struct device_node* node, u8 pci_bus) { int *bus_range; @@ -659,21 +639,21 @@ make_one_node_map(struct device_node* node, u8 pci_bus) return; bus_range = (int *) get_property(node, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - node->full_name); - return; - } - pci_to_OF_bus_map[pci_bus] = bus_range[0]; + printk(KERN_WARNING "Can't get bus-range for %s, " + "assuming it starts at 0\n", node->full_name); + pci_to_OF_bus_map[pci_bus] = 0; + } else + pci_to_OF_bus_map[pci_bus] = bus_range[0]; for (node=node->child; node != 0;node = node->sibling) { struct pci_dev* dev; unsigned int *class_code, *reg; - class_code = (unsigned int *) get_property(node, "class-code", 0); + class_code = (unsigned int *) get_property(node, "class-code", NULL); if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) continue; - reg = (unsigned int *)get_property(node, "reg", 0); + reg = (unsigned int *)get_property(node, "reg", NULL); if (!reg) continue; dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff)); @@ -683,7 +663,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus) } } -void __openfirmware +void pcibios_make_OF_bus_map(void) { int i; @@ -710,7 +690,7 @@ pcibios_make_OF_bus_map(void) continue; make_one_node_map(node, hose->first_busno); } - of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", 0); + of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", NULL); if (of_prop_map) memcpy(of_prop_map, pci_to_OF_bus_map, pci_bus_count); #ifdef DEBUG @@ -725,7 +705,7 @@ pcibios_make_OF_bus_map(void) typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data); -static struct device_node* __openfirmware +static struct device_node* scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data) { struct device_node* sub_node; @@ -741,7 +721,7 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* * a fake root for all functions of a multi-function device, * we go down them as well. */ - class_code = (unsigned int *) get_property(node, "class-code", 0); + class_code = (unsigned int *) get_property(node, "class-code", NULL); if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) && strcmp(node->name, "multifunc-device")) @@ -759,14 +739,14 @@ scan_OF_pci_childs_iterator(struct device_node* node, void* data) unsigned int *reg; u8* fdata = (u8*)data; - reg = (unsigned int *) get_property(node, "reg", 0); + reg = (unsigned int *) get_property(node, "reg", NULL); if (reg && ((reg[0] >> 8) & 0xff) == fdata[1] && ((reg[0] >> 16) & 0xff) == fdata[0]) return 1; return 0; } -static struct device_node* __openfirmware +static struct device_node* scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) { u8 filter_data[2] = {bus, dev_fn}; @@ -799,17 +779,6 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) return NULL; /* Fixup bus number according to what OF think it is. */ -#ifdef CONFIG_PPC_PMAC - /* The G5 need a special case here. Basically, we don't remap all - * busses on it so we don't create the pci-OF-map. However, we do - * remap the AGP bus and so have to deal with it. A future better - * fix has to be done by making the remapping per-host and always - * filling the pci_to_OF map. --BenH - */ - if (_machine == _MACH_Pmac && busnr >= 0xf0) - busnr -= 0xf0; - else -#endif if (pci_to_OF_bus_map) busnr = pci_to_OF_bus_map[busnr]; if (busnr == 0xff) @@ -818,22 +787,23 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) /* Now, lookup childs of the hose */ return scan_OF_childs_for_device(node->child, busnr, devfn); } +EXPORT_SYMBOL(pci_busdev_to_OF_node); struct device_node* pci_device_to_OF_node(struct pci_dev *dev) { return pci_busdev_to_OF_node(dev->bus, dev->devfn); } +EXPORT_SYMBOL(pci_device_to_OF_node); /* This routine is meant to be used early during boot, when the * PCI bus numbers have not yet been assigned, and you need to * issue PCI config cycles to an OF device. * It could also be used to "fix" RTAS config cycles if you want - * to set pci_assign_all_busses to 1 and still use RTAS for PCI + * to set pci_assign_all_buses to 1 and still use RTAS for PCI * config cycles. */ -struct pci_controller* -pci_find_hose_for_OF_device(struct device_node* node) +struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) { if (!have_of) return NULL; @@ -847,7 +817,7 @@ pci_find_hose_for_OF_device(struct device_node* node) return NULL; } -static int __openfirmware +static int find_OF_pci_device_filter(struct device_node* node, void* data) { return ((void *)node == data); @@ -872,7 +842,7 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn) if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child, find_OF_pci_device_filter, (void *)node)) return -ENODEV; - reg = (unsigned int *) get_property(node, "reg", 0); + reg = (unsigned int *) get_property(node, "reg", NULL); if (!reg) return -ENODEV; *bus = (reg[0] >> 16) & 0xff; @@ -885,16 +855,18 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn) */ if (!pci_to_OF_bus_map) return 0; - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (pci_to_OF_bus_map[dev->bus->number] != *bus) - continue; - if (dev->devfn != *devfn) - continue; - *bus = dev->bus->number; - return 0; - } + + for_each_pci_dev(dev) + if (pci_to_OF_bus_map[dev->bus->number] == *bus && + dev->devfn == *devfn) { + *bus = dev->bus->number; + pci_dev_put(dev); + return 0; + } + return -ENODEV; } +EXPORT_SYMBOL(pci_device_from_OF_node); void __init pci_process_bridge_OF_ranges(struct pci_controller *hose, @@ -958,7 +930,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { res = NULL; size = ranges[na+4]; - switch (ranges[0] >> 24) { + switch ((ranges[0] >> 24) & 0x3) { case 1: /* I/O space */ if (ranges[2] != 0) break; @@ -972,6 +944,8 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, res = &hose->io_resource; res->flags = IORESOURCE_IO; res->start = ranges[2]; + DBG("PCI: IO 0x%lx -> 0x%lx\n", + res->start, res->start + size - 1); break; case 2: /* memory space */ memno = 0; @@ -989,7 +963,11 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, if (memno < 3) { res = &hose->mem_resources[memno]; res->flags = IORESOURCE_MEM; + if(ranges[0] & 0x40000000) + res->flags |= IORESOURCE_PREFETCH; res->start = ranges[na+2]; + DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno, + res->start, res->start + size - 1); } break; } @@ -1022,7 +1000,7 @@ pci_create_OF_bus_map(void) } } -static ssize_t pci_show_devspec(struct device *dev, char *buf) +static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev; struct device_node *np; @@ -1035,6 +1013,10 @@ static ssize_t pci_show_devspec(struct device *dev, char *buf) } static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); +#else /* CONFIG_PPC_OF */ +void pcibios_make_OF_bus_map(void) +{ +} #endif /* CONFIG_PPC_OF */ /* Add sysfs properties */ @@ -1046,217 +1028,6 @@ void pcibios_add_platform_entries(struct pci_dev *pdev) } -#ifdef CONFIG_PPC_PMAC -/* - * This set of routines checks for PCI<->PCI bridges that have closed - * IO resources and have child devices. It tries to re-open an IO - * window on them. - * - * This is a _temporary_ fix to workaround a problem with Apple's OF - * closing IO windows on P2P bridges when the OF drivers of cards - * below this bridge don't claim any IO range (typically ATI or - * Adaptec). - * - * A more complete fix would be to use drivers/pci/setup-bus.c, which - * involves a working pcibios_fixup_pbus_ranges(), some more care about - * ordering when creating the host bus resources, and maybe a few more - * minor tweaks - */ - -/* Initialize bridges with base/limit values we have collected */ -static void __init -do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga) -{ - struct pci_dev *bridge = bus->self; - struct pci_controller* hose = (struct pci_controller *)bridge->sysdata; - u32 l; - u16 w; - struct resource res; - - res = *(bus->resource[0]); - - DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->slot_name); - res.start -= ((unsigned long) hose->io_base_virt - isa_io_base); - res.end -= ((unsigned long) hose->io_base_virt - isa_io_base); - DBG(" IO window: %08lx-%08lx\n", res.start, res.end); - - /* Set up the top and bottom of the PCI I/O segment for this bus. */ - pci_read_config_dword(bridge, PCI_IO_BASE, &l); - l &= 0xffff000f; - l |= (res.start >> 8) & 0x00f0; - l |= res.end & 0xf000; - pci_write_config_dword(bridge, PCI_IO_BASE, l); - - if ((l & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { - l = (res.start >> 16) | (res.end & 0xffff0000); - pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, l); - } - - pci_read_config_word(bridge, PCI_COMMAND, &w); - w |= PCI_COMMAND_IO; - pci_write_config_word(bridge, PCI_COMMAND, w); - -#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */ - if (enable_vga) { - pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w); - w |= PCI_BRIDGE_CTL_VGA; - pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w); - } -#endif -} - -/* This function is pretty basic and actually quite broken for the - * general case, it's enough for us right now though. It's supposed - * to tell us if we need to open an IO range at all or not and what - * size. - */ -static int __init -check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga) -{ - struct list_head *ln; - int i; - int rc = 0; - -#define push_end(res, size) do { unsigned long __sz = (size) ; \ - res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \ - } while (0) - - for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { - struct pci_dev *dev = pci_dev_b(ln); - u16 class = dev->class >> 8; - - if (class == PCI_CLASS_DISPLAY_VGA || - class == PCI_CLASS_NOT_DEFINED_VGA) - *found_vga = 1; - if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate) - rc |= check_for_io_childs(dev->subordinate, res, found_vga); - if (class == PCI_CLASS_BRIDGE_CARDBUS) - push_end(res, 0xfff); - - for (i=0; iclass >> 8 == PCI_CLASS_BRIDGE_PCI - && i >= PCI_BRIDGE_RESOURCES) - continue; - r = &dev->resource[i]; - r_size = r->end - r->start; - if (r_size < 0xfff) - r_size = 0xfff; - if (r->flags & IORESOURCE_IO && (r_size) != 0) { - rc = 1; - push_end(res, r_size); - } - } - } - - return rc; -} - -/* Here we scan all P2P bridges of a given level that have a closed - * IO window. Note that the test for the presence of a VGA card should - * be improved to take into account already configured P2P bridges, - * currently, we don't see them and might end up configuring 2 bridges - * with VGA pass through enabled - */ -static void __init -do_fixup_p2p_level(struct pci_bus *bus) -{ - struct list_head *ln; - int i, parent_io; - int has_vga = 0; - - for (parent_io=0; parent_io<4; parent_io++) - if (bus->resource[parent_io]->flags & IORESOURCE_IO) - break; - if (parent_io >= 4) - return; - - for (ln=bus->children.next; ln != &bus->children; ln=ln->next) { - struct pci_bus *b = pci_bus_b(ln); - struct pci_dev *d = b->self; - struct pci_controller* hose = (struct pci_controller *)d->sysdata; - struct resource *res = b->resource[0]; - struct resource tmp_res; - unsigned long max; - int found_vga = 0; - - memset(&tmp_res, 0, sizeof(tmp_res)); - tmp_res.start = bus->resource[parent_io]->start; - - /* We don't let low addresses go through that closed P2P bridge, well, - * that may not be necessary but I feel safer that way - */ - if (tmp_res.start == 0) - tmp_res.start = 0x1000; - - if (!list_empty(&b->devices) && res && res->flags == 0 && - res != bus->resource[parent_io] && - (d->class >> 8) == PCI_CLASS_BRIDGE_PCI && - check_for_io_childs(b, &tmp_res, &found_vga)) { - u8 io_base_lo; - - printk(KERN_INFO "Fixing up IO bus %s\n", b->name); - - if (found_vga) { - if (has_vga) { - printk(KERN_WARNING "Skipping VGA, already active" - " on bus segment\n"); - found_vga = 0; - } else - has_vga = 1; - } - pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo); - - if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) - max = ((unsigned long) hose->io_base_virt - - isa_io_base) + 0xffffffff; - else - max = ((unsigned long) hose->io_base_virt - - isa_io_base) + 0xffff; - - *res = tmp_res; - res->flags = IORESOURCE_IO; - res->name = b->name; - - /* Find a resource in the parent where we can allocate */ - for (i = 0 ; i < 4; i++) { - struct resource *r = bus->resource[i]; - if (!r) - continue; - if ((r->flags & IORESOURCE_IO) == 0) - continue; - DBG("Trying to allocate from %08lx, size %08lx from parent" - " res %d: %08lx -> %08lx\n", - res->start, res->end, i, r->start, r->end); - - if (allocate_resource(r, res, res->end + 1, res->start, max, - res->end + 1, NULL, NULL) < 0) { - DBG("Failed !\n"); - continue; - } - do_update_p2p_io_resource(b, found_vga); - break; - } - } - do_fixup_p2p_level(b); - } -} - -static void -pcibios_fixup_p2p_bridges(void) -{ - struct list_head *ln; - - for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) { - struct pci_bus *b = pci_bus_b(ln); - do_fixup_p2p_level(b); - } -} - -#endif /* CONFIG_PPC_PMAC */ - static int __init pcibios_init(void) { @@ -1268,13 +1039,13 @@ pcibios_init(void) /* Scan all of the recorded PCI controllers. */ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { - if (pci_assign_all_busses) + if (pci_assign_all_buses) hose->first_busno = next_busno; hose->last_busno = 0xff; bus = pci_scan_bus(hose->first_busno, hose->ops, hose); hose->last_busno = bus->subordinate; - if (pci_assign_all_busses || next_busno <= hose->last_busno) - next_busno = hose->last_busno+1; + if (pci_assign_all_buses || next_busno <= hose->last_busno) + next_busno = hose->last_busno + pcibios_assign_bus_offset; } pci_bus_count = next_busno; @@ -1282,7 +1053,7 @@ pcibios_init(void) * numbers vs. kernel bus numbers since we may have to * remap them. */ - if (pci_assign_all_busses && have_of) + if (pci_assign_all_buses && have_of) pcibios_make_OF_bus_map(); /* Do machine dependent PCI interrupt routing */ @@ -1297,9 +1068,6 @@ pcibios_init(void) pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); pcibios_allocate_resources(1); -#ifdef CONFIG_PPC_PMAC - pcibios_fixup_p2p_bridges(); -#endif /* CONFIG_PPC_PMAC */ pcibios_assign_resources(); /* Call machine dependent post-init code */ @@ -1452,7 +1220,7 @@ pci_bus_to_hose(int bus) return NULL; } -void* +void __iomem * pci_bus_io_base(unsigned int bus) { struct pci_controller *hose; @@ -1498,96 +1266,145 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res) return res->start; } -/* - * Platform support for /proc/bus/pci/X/Y mmap()s, - * modelled on the sparc64 implementation by Dave Miller. - * -- paulus. - */ -/* - * Adjust vm_pgoff of VMA such that it is the physical page offset - * corresponding to the 32-bit pci bus offset for DEV requested by the user. - * - * Basically, the user finds the base address for his device which he wishes - * to mmap. They read the 32-bit value from the config space base register, - * add whatever PAGE_SIZE multiple offset they wish, and feed this into the - * offset parameter of mmap on /proc/bus/pci/XXX for that device. - * - * Returns negative error code on failure, zero on success. - */ -static __inline__ int -__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state) +static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, + unsigned long *offset, + enum pci_mmap_state mmap_state) { - struct pci_controller *hose = (struct pci_controller *) dev->sysdata; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long base; - struct resource *res; - int i; - int ret = -EINVAL; + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + unsigned long io_offset = 0; + int i, res_bit; if (hose == 0) - return -EINVAL; /* should never happen */ - if (offset + size <= offset) - return -EINVAL; + return NULL; /* should never happen */ + /* If memory, add on the PCI bridge address offset */ if (mmap_state == pci_mmap_mem) { - /* PCI memory space */ - base = hose->pci_mem_offset; - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - if (res->flags == 0) - continue; - if (offset >= res->start - base - && offset + size - 1 <= res->end - base) { - ret = 0; - break; - } - } - offset += hose->pci_mem_offset; + *offset += hose->pci_mem_offset; + res_bit = IORESOURCE_MEM; } else { - /* PCI I/O space */ - base = (unsigned long)hose->io_base_virt - isa_io_base; - res = &hose->io_resource; - if (offset >= res->start - base - && offset + size - 1 <= res->end - base) - ret = 0; - offset += hose->io_base_phys; + io_offset = hose->io_base_virt - ___IO_BASE; + *offset += io_offset; + res_bit = IORESOURCE_IO; } - vma->vm_pgoff = offset >> PAGE_SHIFT; - return ret; -} + /* + * Check that the offset requested corresponds to one of the + * resources of the device. + */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *rp = &dev->resource[i]; + int flags = rp->flags; -/* - * Set vm_flags of VMA, as appropriate for this architecture, for a pci device - * mapping. - */ -static __inline__ void -__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state) -{ - vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO; + /* treat ROM as memory (should be already) */ + if (i == PCI_ROM_RESOURCE) + flags |= IORESOURCE_MEM; + + /* Active and same type? */ + if ((flags & res_bit) == 0) + continue; + + /* In the range of this resource? */ + if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end) + continue; + + /* found it! construct the final physical address */ + if (mmap_state == pci_mmap_io) + *offset += hose->io_base_phys - io_offset; + return rp; + } + + return NULL; } /* * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci * device mapping. */ -static __inline__ void -__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, int write_combine) +static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, + pgprot_t protection, + enum pci_mmap_state mmap_state, + int write_combine) { - int prot = pgprot_val(vma->vm_page_prot); + unsigned long prot = pgprot_val(protection); + + /* Write combine is always 0 on non-memory space mappings. On + * memory space, if the user didn't pass 1, we check for a + * "prefetchable" resource. This is a bit hackish, but we use + * this to workaround the inability of /sysfs to provide a write + * combine bit + */ + if (mmap_state != pci_mmap_mem) + write_combine = 0; + else if (write_combine == 0) { + if (rp->flags & IORESOURCE_PREFETCH) + write_combine = 1; + } /* XXX would be nice to have a way to ask for write-through */ prot |= _PAGE_NO_CACHE; - if (!write_combine) + if (write_combine) + prot &= ~_PAGE_GUARDED; + else prot |= _PAGE_GUARDED; - vma->vm_page_prot = __pgprot(prot); + + printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start, + prot); + + return __pgprot(prot); +} + +/* + * This one is used by /dev/mem and fbdev who have no clue about the + * PCI device, it tries to find the PCI device first and calls the + * above routine + */ +pgprot_t pci_phys_mem_access_prot(struct file *file, + unsigned long pfn, + unsigned long size, + pgprot_t protection) +{ + struct pci_dev *pdev = NULL; + struct resource *found = NULL; + unsigned long prot = pgprot_val(protection); + unsigned long offset = pfn << PAGE_SHIFT; + int i; + + if (page_is_ram(pfn)) + return prot; + + prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; + + for_each_pci_dev(pdev) { + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *rp = &pdev->resource[i]; + int flags = rp->flags; + + /* Active and same type? */ + if ((flags & IORESOURCE_MEM) == 0) + continue; + /* In the range of this resource? */ + if (offset < (rp->start & PAGE_MASK) || + offset > rp->end) + continue; + found = rp; + break; + } + if (found) + break; + } + if (found) { + if (found->flags & IORESOURCE_PREFETCH) + prot &= ~_PAGE_GUARDED; + pci_dev_put(pdev); + } + + DBG("non-PCI map for %lx, prot: %lx\n", offset, prot); + + return __pgprot(prot); } + /* * Perform the actual remap of the pages for a PCI device mapping, as * appropriate for this architecture. The region in the process to map @@ -1602,16 +1419,21 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine) { + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + struct resource *rp; int ret; - ret = __pci_mmap_make_offset(dev, vma, mmap_state); - if (ret < 0) - return ret; + rp = __pci_mmap_make_offset(dev, &offset, mmap_state); + if (rp == NULL) + return -EINVAL; - __pci_mmap_set_flags(dev, vma, mmap_state); - __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine); + vma->vm_pgoff = offset >> PAGE_SHIFT; + vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO; + vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp, + vma->vm_page_prot, + mmap_state, write_combine); - ret = remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, + ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot); return ret; @@ -1675,17 +1497,6 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) struct pci_controller* hose; long result = -EOPNOTSUPP; - /* Argh ! Please forgive me for that hack, but that's the - * simplest way to get existing XFree to not lockup on some - * G5 machines... So when something asks for bus 0 io base - * (bus 0 is HT root), we return the AGP one instead. - */ -#ifdef CONFIG_PPC_PMAC - if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4")) - if (bus == 0) - bus = 0xf0; -#endif /* CONFIG_PPC_PMAC */ - hose = pci_bus_to_hose(bus); if (!hose) return -ENODEV; @@ -1706,6 +1517,23 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) return result; } +void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, + u64 *start, u64 *end) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + unsigned long offset = 0; + + if (hose == NULL) + return; + + if (rsrc->flags & IORESOURCE_IO) + offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys; + + *start = rsrc->start + offset; + *end = rsrc->end + offset; +} + void __init pci_init_resource(struct resource *res, unsigned long start, unsigned long end, int flags, char *name) @@ -1719,6 +1547,53 @@ pci_init_resource(struct resource *res, unsigned long start, unsigned long end, res->child = NULL; } +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len) + return NULL; + if (max && len > max) + len = max; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) + /* Not checking IORESOURCE_CACHEABLE because PPC does + * not currently distinguish between ioremap and + * ioremap_nocache. + */ + return ioremap(start, len); + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); + +unsigned long pci_address_to_pio(phys_addr_t address) +{ + struct pci_controller* hose = hose_head; + + for (; hose; hose = hose->next) { + unsigned int size = hose->io_resource.end - + hose->io_resource.start + 1; + if (address >= hose->io_base_phys && + address < (hose->io_base_phys + size)) { + unsigned long base = + (unsigned long)hose->io_base_virt - _IO_BASE; + return base + (address - hose->io_base_phys); + } + } + return (unsigned int)-1; +} +EXPORT_SYMBOL(pci_address_to_pio); + /* * Null PCI config access functions, for the case when we can't * find a hose.