lkml.org 
[lkml]   [2003]   [Mar]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: 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, &region, 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, &region, 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, &region, 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, &region, 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/

    \
     
     \ /
      Last update: 2005-03-22 13:34    [W:0.042 / U:29.824 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site