Messages in this thread Patch in this message | | | Date | Sat, 22 Mar 2003 16:56:20 +0000 | From | Russell King <> | Subject | Re: PCI patches (2/3) |
| |
# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1131 -> 1.1132 # drivers/pci/setup-bus.c 1.16 -> 1.17 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/03/22 ink@ru.rmk.(none) 1.1132 # [PCI] Make setup-bus.c aware of cardbus bridges. # # Comments from rmk: # # Make setup-bus.c properly aware of cardbus bridges. We treat the # bus behind a cardbus bridge more or less like any other bus, except # we don't explicitly descend below. We do, however, explicitly # reserve IO and memory space as we have done in the past. Memory # space is doubed to 32MB as a measure to allow the Mobility # cardbus-pci stuff to work. The amount of space reserved is now # specified by a couple of #defines at the top of the file. # # This allows pci_bus_assign_resources() and pci_bus_size_bridges() # to be called for both root buses as well as cardbus secondary buses. # # Comments from Ivan follows: # # This patch combines your(rmk) cardbus changes (formerly pci-11) # and my "arbitrary resource layout" stuff. This + current bk works # on nautilus. # # Most interesting feature: this can be used on partially # allocated PCI tree. For instance, i386 PCI code has always been # absolutely helpless wrt incorrectly initialized p2p bridges. # Now it can just call pci_assign_unassigned_resources() in the # end of PCI init and it would fix following problems: # - completely uninitialized bridge windows (with base and limit 0); # - erroneously "closed" windows; # - windows overlapping with something else. # -------------------------------------------- # diff -Nru a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c --- a/drivers/pci/setup-bus.c Sat Mar 22 16:53:12 2003 +++ b/drivers/pci/setup-bus.c Sat Mar 22 16:53:12 2003 @@ -36,6 +36,13 @@ #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +/* + * FIXME: IO should be max 256 bytes. However, since we may + * have a P2P bridge below a cardbus bridge, we need 4K. + */ +#define CARDBUS_IO_SIZE (4096) +#define CARDBUS_MEM_SIZE (32*1024*1024) + static int __devinit pbus_assign_resources_sorted(struct pci_bus *bus) { @@ -67,12 +74,67 @@ return found_vga; } +static void __devinit +pci_setup_cardbus(struct pci_bus *bus) +{ + struct pci_dev *bridge = bus->self; + struct pci_bus_region region; + + printk("PCI: Bus %d, cardbus bridge: %s\n", + bus->number, bridge->slot_name); + + pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); + if (bus->resource[0]->flags & IORESOURCE_IO) { + /* + * The IO resource is allocated a range twice as large as it + * would normally need. This allows us to set both IO regs. + */ + printk(" IO window: %08lx-%08lx\n", + region.start, region.end); + pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, + region.start); + pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, + region.end); + } + + pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); + if (bus->resource[1]->flags & IORESOURCE_IO) { + printk(" IO window: %08lx-%08lx\n", + region.start, region.end); + pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, + region.start); + pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, + region.end); + } + + pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); + if (bus->resource[2]->flags & IORESOURCE_MEM) { + printk(" PREFETCH window: %08lx-%08lx\n", + region.start, region.end); + pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, + region.start); + pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, + region.end); + } + + pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]); + if (bus->resource[3]->flags & IORESOURCE_MEM) { + printk(" MEM window: %08lx-%08lx\n", + region.start, region.end); + pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, + region.start); + pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, + region.end); + } +} + /* Initialize bridges with base/limit values we have collected. PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998) 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 pci_dev *bridge = bus->self; struct pci_bus_region region; @@ -154,9 +216,6 @@ struct pci_dev *bridge = bus->self; struct resource *b_res; - if (!bridge || (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI) - return; - b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; b_res[1].flags |= IORESOURCE_MEM; @@ -184,6 +243,26 @@ b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; } +/* Helper function for sizing routines: find first available + bus resource of a given type. Note: we intentionally skip + the bus resources which have already been assigned (that is, + have non-NULL parent resource). */ +static struct resource * __devinit +find_free_bus_resource(struct pci_bus *bus, unsigned long type) +{ + int i; + struct resource *r; + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | + IORESOURCE_PREFETCH; + + for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { + r = bus->resource[i]; + if (r && (r->flags & type_mask) == type && !r->parent) + return r; + } + return NULL; +} + /* Sizing the IO windows of the PCI-PCI bridge is trivial, since these windows have 4K granularity and the IO ranges of non-bridge PCI devices are limited to 256 bytes. @@ -192,15 +271,15 @@ pbus_size_io(struct pci_bus *bus) { struct pci_dev *dev; - struct resource *b_res = bus->resource[0]; + struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); unsigned long size = 0, size1 = 0; - if (!(b_res->flags & IORESOURCE_IO)) - return; + if (!b_res) + return; list_for_each_entry(dev, &bus->devices, bus_list) { int i; - + for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *r = &dev->resource[i]; unsigned long r_size; @@ -215,9 +294,6 @@ else size1 += r_size; } - /* ??? Reserve some resources for CardBus. */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) - size1 += 4*1024; } /* To be fixed in 2.5: we should have sort of HAVE_ISA flag in the struct pci_bus. */ @@ -236,15 +312,17 @@ /* Calculate the size of the bus and minimal alignment which guarantees that all child resources fit in this size. */ -static void __devinit +static int __devinit pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) { struct pci_dev *dev; unsigned long min_align, align, size; unsigned long aligns[12]; /* Alignments from 1Mb to 2Gb */ int order, max_order; - struct resource *b_res = (type & IORESOURCE_PREFETCH) ? - bus->resource[2] : bus->resource[1]; + struct resource *b_res = find_free_bus_resource(bus, type); + + if (!b_res) + return 0; memset(aligns, 0, sizeof(aligns)); max_order = 0; @@ -280,11 +358,6 @@ if (order > max_order) max_order = order; } - /* ??? Reserve some resources for CardBus. */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { - size += 1UL << 24; /* 16 Mb */ - aligns[24 - 20] += 1UL << 24; - } } align = 0; @@ -301,38 +374,111 @@ size = ROUND_UP(size, min_align); if (!size) { b_res->flags = 0; - return; + return 1; } b_res->start = min_align; b_res->end = size + min_align - 1; + return 1; +} + +static void __devinit +pci_bus_size_cardbus(struct pci_bus *bus) +{ + struct pci_dev *bridge = bus->self; + struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; + u16 ctrl; + + /* + * Reserve some resources for CardBus. We reserve + * a fixed amount of bus space for CardBus bridges. + */ + b_res[0].start = CARDBUS_IO_SIZE; + b_res[0].end = b_res[0].start + CARDBUS_IO_SIZE - 1; + b_res[0].flags |= IORESOURCE_IO; + + b_res[1].start = CARDBUS_IO_SIZE; + b_res[1].end = b_res[1].start + CARDBUS_IO_SIZE - 1; + b_res[1].flags |= IORESOURCE_IO; + + /* + * Check whether prefetchable memory is supported + * by this bridge. + */ + pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); + if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) { + ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0; + pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl); + pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); + } + + /* + * If we have prefetchable memory support, allocate + * two regions. Otherwise, allocate one region of + * twice the size. + */ + if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { + b_res[2].start = CARDBUS_MEM_SIZE; + b_res[2].end = b_res[2].start + CARDBUS_MEM_SIZE - 1; + b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; + + b_res[3].start = CARDBUS_MEM_SIZE; + b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE - 1; + b_res[3].flags |= IORESOURCE_MEM; + } else { + b_res[3].start = CARDBUS_MEM_SIZE * 2; + b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE * 2 - 1; + b_res[3].flags |= IORESOURCE_MEM; + } } void __devinit pci_bus_size_bridges(struct pci_bus *bus) { - struct pci_bus *b; - unsigned long mask, type; + struct pci_dev *dev; + unsigned long mask, prefmask; - list_for_each_entry(b, &bus->children, node) { - pci_bus_size_bridges(b); + list_for_each_entry(dev, &bus->devices, bus_list) { + struct pci_bus *b = dev->subordinate; + if (!b) + continue; + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_CARDBUS: + pci_bus_size_cardbus(b); + break; + + case PCI_CLASS_BRIDGE_PCI: + default: + pci_bus_size_bridges(b); + break; + } } /* The root bus? */ if (!bus->self) return; - pci_bridge_check_ranges(bus); - - pbus_size_io(bus); - - mask = type = IORESOURCE_MEM; - /* If the bridge supports prefetchable range, size it separately. */ - if (bus->resource[2] && - bus->resource[2]->flags & IORESOURCE_PREFETCH) { - pbus_size_mem(bus, IORESOURCE_PREFETCH, IORESOURCE_PREFETCH); - mask |= IORESOURCE_PREFETCH; /* Size non-prefetch only. */ + switch (bus->self->class >> 8) { + case PCI_CLASS_BRIDGE_CARDBUS: + /* don't size cardbuses yet. */ + break; + + case PCI_CLASS_BRIDGE_PCI: + pci_bridge_check_ranges(bus); + default: + pbus_size_io(bus); + /* If the bridge supports prefetchable range, size it + separately. If it doesn't, or its prefetchable window + has already been allocated by arch code, try + non-prefetchable range for both types of PCI memory + resources. */ + mask = IORESOURCE_MEM; + prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; + if (pbus_size_mem(bus, prefmask, prefmask)) + mask = prefmask; /* Success, size non-prefetch only. */ + pbus_size_mem(bus, mask, IORESOURCE_MEM); + break; } - pbus_size_mem(bus, mask, type); } EXPORT_SYMBOL(pci_bus_size_bridges); @@ -351,9 +497,24 @@ } list_for_each_entry(dev, &bus->devices, bus_list) { b = dev->subordinate; - if (b) { - pci_bus_assign_resources(b); + if (!b) + continue; + + pci_bus_assign_resources(b); + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_PCI: pci_setup_bridge(b); + break; + + case PCI_CLASS_BRIDGE_CARDBUS: + pci_setup_cardbus(b); + break; + + default: + printk(KERN_INFO "PCI: not setting up bridge %s " + "for bus %d\n", dev->slot_name, b->number); + break; } } } -- Russell King (rmk@arm.linux.org.uk) The developer of ARM Linux http://www.arm.linux.org.uk/personal/aboutme.html
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |