diff options
author | Myles Watson <mylesgw@gmail.com> | 2009-07-02 18:56:24 +0000 |
---|---|---|
committer | Myles Watson <mylesgw@gmail.com> | 2009-07-02 18:56:24 +0000 |
commit | 29cc9eda2021a87396ef31a6fc81daff6fd1be7a (patch) | |
tree | d3dfa07ca85547c77c5d07825fc8afcc19489076 /src/devices | |
parent | 2468331952bae0abdc4d76dbe6cf26f05b7825e5 (diff) | |
download | coreboot-staging-29cc9eda2021a87396ef31a6fc81daff6fd1be7a.zip coreboot-staging-29cc9eda2021a87396ef31a6fc81daff6fd1be7a.tar.gz |
Move the v3 resource allocator to v2.
Major changes:
1. Separate resource allocation into:
A. Read Resources
B. Avoid fixed resources (constrain limits)
C. Allocate resources
D. Set resources
Usage notes:
Resources which have IORESOURCE_FIXED set in the flags constrain the placement
of other resources. All fixed resources will end up outside (above or below)
the allocated resources.
Domains usually start with base = 0 and limit = 2^address_bits - 1.
I've added an IOAPIC to all platforms so that the old limit of 0xfec00000 is
still there for resources. Some platforms may want to change that, but I didn't
want to break anyone's board.
Resources are allocated in a single block for memory and another for I/O.
Currently the resource allocator doesn't support holes.
Signed-off-by: Myles Watson <mylesgw@gmail.com>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Patrick Georgi <patrick.georgi@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4394 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/cardbus_device.c | 2 | ||||
-rw-r--r-- | src/devices/device.c | 830 | ||||
-rw-r--r-- | src/devices/device_util.c | 4 | ||||
-rw-r--r-- | src/devices/pci_device.c | 832 | ||||
-rw-r--r-- | src/devices/root_device.c | 33 |
5 files changed, 994 insertions, 707 deletions
diff --git a/src/devices/cardbus_device.c b/src/devices/cardbus_device.c index 548bdf7..d6dbbb5 100644 --- a/src/devices/cardbus_device.c +++ b/src/devices/cardbus_device.c @@ -77,8 +77,6 @@ static void cardbus_size_bridge_resource(device_t dev, unsigned index) resource = find_resource(dev, index); if (resource) { min_size = resource->size; - compute_allocate_resource(&dev->link[0], resource, - resource->flags, resource->flags); /* Allways allocate at least the miniumum size to a * cardbus bridge in case a new card is plugged in. */ diff --git a/src/devices/device.c b/src/devices/device.c index 51a1203..123d22a 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -12,6 +12,7 @@ * Copyright (C) 2005-2006 Tyan * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan) * Copyright (C) 2005-2006 Stefan Reinauer <stepan@openbios.org> + * Copyright (C) 2009 Myles Watson <mylesgw@gmail.com> */ /* @@ -43,12 +44,6 @@ struct device *all_devices = &dev_root; /** Pointer to the last device */ extern struct device **last_dev_p; -/** The upper limit of MEM resource of the devices. - * Reserve 20M for the system */ -#define DEVICE_MEM_HIGH 0xFEBFFFFFUL -/** The lower limit of IO resource of the devices. - * Reserve 4k for ISA/Legacy devices */ -#define DEVICE_IO_START 0x1000 /** * @brief Allocate a new device structure. @@ -71,25 +66,25 @@ device_t alloc_dev(struct bus *parent, struct device_path *path) spin_lock(&dev_lock); - /* Find the last child of our parent */ - for(child = parent->children; child && child->sibling; ) { + /* Find the last child of our parent. */ + for (child = parent->children; child && child->sibling; /* */ ) { child = child->sibling; } dev = malloc(sizeof(*dev)); - if (dev == 0) { + if (dev == 0) die("DEV: out of memory.\n"); - } + memset(dev, 0, sizeof(*dev)); memcpy(&dev->path, path, sizeof(*path)); - /* Initialize the back pointers in the link fields */ - for(link = 0; link < MAX_LINKS; link++) { - dev->link[link].dev = dev; + /* Initialize the back pointers in the link fields. */ + for (link = 0; link < MAX_LINKS; link++) { + dev->link[link].dev = dev; dev->link[link].link = link; } - /* By default devices are enabled */ + /* By default devices are enabled. */ dev->enabled = 1; /* Add the new device to the list of children of the bus. */ @@ -132,64 +127,46 @@ static void read_resources(struct bus *bus) { struct device *curdev; - printk_spew("%s read_resources bus %d link: %d\n", - dev_path(bus->dev), bus->secondary, bus->link); + printk_spew("%s %s bus %x link: %d\n", dev_path(bus->dev), __func__, + bus->secondary, bus->link); - /* Walk through all of the devices and find which resources they need. */ - for(curdev = bus->children; curdev; curdev = curdev->sibling) { - unsigned links; + /* Walk through all devices and find which resources they need. */ + for (curdev = bus->children; curdev; curdev = curdev->sibling) { int i; - if (curdev->have_resources) { - continue; - } if (!curdev->enabled) { continue; } if (!curdev->ops || !curdev->ops->read_resources) { printk_err("%s missing read_resources\n", - dev_path(curdev)); + dev_path(curdev)); continue; } curdev->ops->read_resources(curdev); - curdev->have_resources = 1; - /* Read in subtractive resources behind the current device */ - links = 0; - for(i = 0; i < curdev->resources; i++) { - struct resource *resource; - unsigned link; - resource = &curdev->resource[i]; - if (!(resource->flags & IORESOURCE_SUBTRACTIVE)) - continue; - link = IOINDEX_SUBTRACTIVE_LINK(resource->index); - if (link > MAX_LINKS) { - printk_err("%s subtractive index on link: %d\n", - dev_path(curdev), link); - continue; - } - if (!(links & (1 << link))) { - links |= (1 << link); - read_resources(&curdev->link[link]); - } - } + + /* Read in the resources behind the current device's links. */ + for (i = 0; i < curdev->links; i++) + read_resources(&curdev->link[i]); } printk_spew("%s read_resources bus %d link: %d done\n", - dev_path(bus->dev), bus->secondary, bus->link); + dev_path(bus->dev), bus->secondary, bus->link); } struct pick_largest_state { struct resource *last; - struct device *result_dev; + struct device *result_dev; struct resource *result; int seen_last; }; -static void pick_largest_resource(void *gp, - struct device *dev, struct resource *resource) +static void pick_largest_resource(void *gp, struct device *dev, + struct resource *resource) { struct pick_largest_state *state = gp; struct resource *last; + last = state->last; - /* Be certain to pick the successor to last */ + + /* Be certain to pick the successor to last. */ if (resource == last) { state->seen_last = 1; return; @@ -206,21 +183,22 @@ static void pick_largest_resource(void *gp, if (!state->result || (state->result->align < resource->align) || ((state->result->align == resource->align) && - (state->result->size < resource->size))) - { + (state->result->size < resource->size))) { state->result_dev = dev; state->result = resource; } } -static struct device *largest_resource(struct bus *bus, struct resource **result_res, - unsigned long type_mask, unsigned long type) +static struct device *largest_resource(struct bus *bus, + struct resource **result_res, + unsigned long type_mask, + unsigned long type) { struct pick_largest_state state; state.last = *result_res; - state.result_dev = 0; - state.result = 0; + state.result_dev = NULL; + state.result = NULL; state.seen_last = 0; search_bus_resources(bus, type_mask, type, pick_largest_resource, @@ -233,144 +211,136 @@ static struct device *largest_resource(struct bus *bus, struct resource **result /* Compute allocate resources is the guts of the resource allocator. * * The problem. - * - Allocate resources locations for every device. + * - Allocate resource locations for every device. * - Don't overlap, and follow the rules of bridges. * - Don't overlap with resources in fixed locations. * - Be efficient so we don't have ugly strategies. * * The strategy. * - Devices that have fixed addresses are the minority so don't - * worry about them too much. Instead only use part of the address - * space for devices with programmable addresses. This easily handles + * worry about them too much. Instead only use part of the address + * space for devices with programmable addresses. This easily handles * everything except bridges. * - * - PCI devices are required to have thier sizes and their alignments - * equal. In this case an optimal solution to the packing problem - * exists. Allocate all devices from highest alignment to least - * alignment or vice versa. Use this. + * - PCI devices are required to have their sizes and their alignments + * equal. In this case an optimal solution to the packing problem + * exists. Allocate all devices from highest alignment to least + * alignment or vice versa. Use this. * - * - So we can handle more than PCI run two allocation passes on - * bridges. The first to see how large the resources are behind - * the bridge, and what their alignment requirements are. The - * second to assign a safe address to the devices behind the - * bridge. This allows me to treat a bridge as just a device with - * a couple of resources, and not need to special case it in the - * allocator. Also this allows handling of other types of bridges. + * - So we can handle more than PCI run two allocation passes on bridges. The + * first to see how large the resources are behind the bridge, and what + * their alignment requirements are. The second to assign a safe address to + * the devices behind the bridge. This allows us to treat a bridge as just + * a device with a couple of resources, and not need to special case it in + * the allocator. Also this allows handling of other types of bridges. * */ - -void compute_allocate_resource( - struct bus *bus, - struct resource *bridge, - unsigned long type_mask, - unsigned long type) +void compute_resources(struct bus *bus, struct resource *bridge, + unsigned long type_mask, unsigned long type) { struct device *dev; struct resource *resource; resource_t base; - unsigned long align, min_align; - min_align = 0; - base = bridge->base; + base = round(bridge->base, bridge->align); - printk_spew("%s compute_allocate_resource %s: base: %08Lx size: %08Lx align: %d gran: %d\n", - dev_path(bus->dev), - (bridge->flags & IORESOURCE_IO)? "io": - (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", - base, bridge->size, bridge->align, bridge->gran); + printk_spew( "%s %s_%s: base: %llx size: %llx align: %d gran: %d limit: %llx\n", + dev_path(bus->dev), __func__, + (type & IORESOURCE_IO) ? "io" : (type & IORESOURCE_PREFETCH) ? + "prefmem" : "mem", + base, bridge->size, bridge->align, bridge->gran, bridge->limit); - /* We want different minimum alignments for different kinds of - * resources. These minimums are not device type specific - * but resource type specific. - */ - if (bridge->flags & IORESOURCE_IO) { - min_align = log2(DEVICE_IO_ALIGN); - } - if (bridge->flags & IORESOURCE_MEM) { - min_align = log2(DEVICE_MEM_ALIGN); - } + /* For each child which is a bridge, compute_resource_needs. */ + for (dev = bus->children; dev; dev = dev->sibling) { + unsigned i; + struct resource *child_bridge; - /* Make certain I have read in all of the resources */ - read_resources(bus); + if (!dev->links) + continue; - /* Remember I haven't found anything yet. */ - resource = 0; + /* Find the resources with matching type flags. */ + for (i = 0; i < dev->resources; i++) { + unsigned link; + child_bridge = &dev->resource[i]; - /* Walk through all the devices on the current bus and - * compute the addresses. - */ - while((dev = largest_resource(bus, &resource, type_mask, type))) { - resource_t size; - /* Do NOT I repeat do not ignore resources which have zero size. - * If they need to be ignored dev->read_resources should not even - * return them. Some resources must be set even when they have - * no size. PCI bridge resources are a good example of this. - */ - /* Make certain we are dealing with a good minimum size */ - size = resource->size; - align = resource->align; - if (align < min_align) { - align = min_align; - } + if (!(child_bridge->flags & IORESOURCE_BRIDGE) || + (child_bridge->flags & type_mask) != type) + continue; - /* Propagate the resource alignment to the bridge register */ - if (align > bridge->align) { - bridge->align = align; + /* Split prefetchable memory if combined. Many domains + * use the same address space for prefetchable memory + * and non-prefetchable memory. Bridges below them + * need it separated. Add the PREFETCH flag to the + * type_mask and type. + */ + link = IOINDEX_LINK(child_bridge->index); + compute_resources(&dev->link[link], child_bridge, + type_mask | IORESOURCE_PREFETCH, + type | (child_bridge->flags & + IORESOURCE_PREFETCH)); } + } + + /* Remember we haven't found anything yet. */ + resource = NULL; + + /* Walk through all the resources on the current bus and compute the + * amount of address space taken by them. Take granularity and + * alignment into account. + */ + while ((dev = largest_resource(bus, &resource, type_mask, type))) { - if (resource->flags & IORESOURCE_FIXED) { + /* Size 0 resources can be skipped. */ + if (!resource->size) { continue; } - /* Propogate the resource limit to the bridge register */ + /* Propagate the resource alignment to the bridge resource. */ + if (resource->align > bridge->align) { + bridge->align = resource->align; + } + + /* Propagate the resource limit to the bridge register. */ if (bridge->limit > resource->limit) { bridge->limit = resource->limit; } -#warning This heuristic should be replaced by real devices with fixed resources. - /* Artificially deny limits between DEVICE_MEM_HIGH and 0xffffffff */ - if ((bridge->limit > DEVICE_MEM_HIGH) && (bridge->limit <= 0xffffffff)) { - bridge->limit = DEVICE_MEM_HIGH; + + /* Warn if it looks like APICs aren't declared. */ + if ((resource->limit == 0xffffffff) && + (resource->flags & IORESOURCE_ASSIGNED)) { + printk_err("Resource limit looks wrong! (no APIC?)\n"); + printk_err("%s %02lx limit %08Lx\n", dev_path(dev), + resource->index, resource->limit); } if (resource->flags & IORESOURCE_IO) { - /* Don't allow potential aliases over the - * legacy pci expansion card addresses. - * The legacy pci decodes only 10 bits, - * uses 100h - 3ffh. Therefor, only 0 - ff - * can be used out of each 400h block of io - * space. + /* Don't allow potential aliases over the legacy PCI + * expansion card addresses. The legacy PCI decodes + * only 10 bits, uses 0x100 - 0x3ff. Therefore, only + * 0x00 - 0xff can be used out of each 0x400 block of + * I/O space. */ if ((base & 0x300) != 0) { base = (base & ~0x3ff) + 0x400; } - /* Don't allow allocations in the VGA IO range. + /* Don't allow allocations in the VGA I/O range. * PCI has special cases for that. */ else if ((base >= 0x3b0) && (base <= 0x3df)) { base = 0x3e0; } } - if (((round(base, align) + size) -1) <= resource->limit) { - /* base must be aligned to size */ - base = round(base, align); - resource->base = base; - resource->flags |= IORESOURCE_ASSIGNED; - resource->flags &= ~IORESOURCE_STORED; - base += size; - - printk_spew("%s %02lx * [0x%08Lx - 0x%08Lx] %s\n", - dev_path(dev), - resource->index, - resource->base, - resource->base + resource->size - 1, - (resource->flags & IORESOURCE_IO)? "io": - (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem"); - } -#if CONFIG_PCIE_CONFIGSPACE_HOLE -#warning Handle PCIe hole differently... - if (base >= 0xf0000000 && base < 0xf4000000) { - base = 0xf4000000; - } -#endif + /* Base must be aligned. */ + base = round(base, resource->align); + resource->base = base; + base += resource->size; + + printk_spew("%s %02lx * [0x%llx - 0x%llx] %s\n", + dev_path(dev), resource->index, + resource->base, + resource->base + resource->size - 1, + (resource->flags & IORESOURCE_IO) ? "io" : + (resource->flags & IORESOURCE_PREFETCH) ? + "prefmem" : "mem"); } /* A pci bridge resource does not need to be a power * of two size, but it does have a minimum granularity. @@ -378,13 +348,317 @@ void compute_allocate_resource( * know not to place something else at an address postitively * decoded by the bridge. */ - bridge->size = round(base, bridge->gran) - bridge->base; + bridge->size = round(base, bridge->gran) - + round(bridge->base, bridge->align); + + printk_spew("%s %s_%s: base: %llx size: %llx align: %d gran: %d limit: %llx done\n", + dev_path(bus->dev), __func__, + (bridge->flags & IORESOURCE_IO) ? "io" : + (bridge->flags & IORESOURCE_PREFETCH) ? "prefmem" : "mem", + base, bridge->size, bridge->align, bridge->gran, bridge->limit); +} + +/** + * This function is the second part of the resource allocator. + * + * The problem. + * - Allocate resource locations for every device. + * - Don't overlap, and follow the rules of bridges. + * - Don't overlap with resources in fixed locations. + * - Be efficient so we don't have ugly strategies. + * + * The strategy. + * - Devices that have fixed addresses are the minority so don't + * worry about them too much. Instead only use part of the address + * space for devices with programmable addresses. This easily handles + * everything except bridges. + * + * - PCI devices are required to have their sizes and their alignments + * equal. In this case an optimal solution to the packing problem + * exists. Allocate all devices from highest alignment to least + * alignment or vice versa. Use this. + * + * - So we can handle more than PCI run two allocation passes on bridges. The + * first to see how large the resources are behind the bridge, and what + * their alignment requirements are. The second to assign a safe address to + * the devices behind the bridge. This allows us to treat a bridge as just + * a device with a couple of resources, and not need to special case it in + * the allocator. Also this allows handling of other types of bridges. + * + * - This function assigns the resources a value. + * + * @param bus The bus we are traversing. + * @param bridge The bridge resource which must contain the bus' resources. + * @param type_mask This value gets anded with the resource type. + * @param type This value must match the result of the and. + */ +void allocate_resources(struct bus *bus, struct resource *bridge, + unsigned long type_mask, unsigned long type) +{ + struct device *dev; + struct resource *resource; + resource_t base; + base = bridge->base; + + printk_spew("%s %s_%s: base:%llx size:%llx align:%d gran:%d limit:%llx\n", + dev_path(bus->dev), __func__, + (type & IORESOURCE_IO) ? "io" : (type & IORESOURCE_PREFETCH) ? + "prefmem" : "mem", + base, bridge->size, bridge->align, bridge->gran, bridge->limit); + + /* Remember we haven't found anything yet. */ + resource = NULL; + + /* Walk through all the resources on the current bus and allocate them + * address space. + */ + while ((dev = largest_resource(bus, &resource, type_mask, type))) { + + /* Propagate the bridge limit to the resource register. */ + if (resource->limit > bridge->limit) { + resource->limit = bridge->limit; + } + + /* Size 0 resources can be skipped. */ + if (!resource->size) { + /* Set the base to limit so it doesn't confuse tolm. */ + resource->base = resource->limit; + resource->flags |= IORESOURCE_ASSIGNED; + continue; + } + + if (resource->flags & IORESOURCE_IO) { + /* Don't allow potential aliases over the legacy PCI + * expansion card addresses. The legacy PCI decodes + * only 10 bits, uses 0x100 - 0x3ff. Therefore, only + * 0x00 - 0xff can be used out of each 0x400 block of + * I/O space. + */ + if ((base & 0x300) != 0) { + base = (base & ~0x3ff) + 0x400; + } + /* Don't allow allocations in the VGA I/O range. + * PCI has special cases for that. + */ + else if ((base >= 0x3b0) && (base <= 0x3df)) { + base = 0x3e0; + } + } + + if ((round(base, resource->align) + resource->size - 1) <= + resource->limit) { + /* Base must be aligned. */ + base = round(base, resource->align); + resource->base = base; + resource->flags |= IORESOURCE_ASSIGNED; + resource->flags &= ~IORESOURCE_STORED; + base += resource->size; + } else { + printk_err("!! Resource didn't fit !!\n"); + printk_err(" aligned base %llx size %llx limit %llx\n", + round(base, resource->align), resource->size, + resource->limit); + printk_err(" %llx needs to be <= %llx (limit)\n", + (round(base, resource->align) + + resource->size) - 1, resource->limit); + printk_err(" %s%s %02lx * [0x%llx - 0x%llx] %s\n", + (resource-> + flags & IORESOURCE_ASSIGNED) ? "Assigned: " : + "", dev_path(dev), resource->index, + resource->base, + resource->base + resource->size - 1, + (resource-> + flags & IORESOURCE_IO) ? "io" : (resource-> + flags & + IORESOURCE_PREFETCH) + ? "prefmem" : "mem"); + } + + printk_spew("%s%s %02lx * [0x%llx - 0x%llx] %s\n", + (resource->flags & IORESOURCE_ASSIGNED) ? "Assigned: " + : "", + dev_path(dev), resource->index, resource->base, + resource->size ? resource->base + resource->size - 1 : + resource->base, + (resource->flags & IORESOURCE_IO) ? "io" : + (resource->flags & IORESOURCE_PREFETCH) ? "prefmem" : + "mem"); + } + /* A PCI bridge resource does not need to be a power of two size, but + * it does have a minimum granularity. Round the size up to that + * minimum granularity so we know not to place something else at an + * address positively decoded by the bridge. + */ + + bridge->flags |= IORESOURCE_ASSIGNED; + + printk_spew("%s %s_%s: next_base: %llx size: %llx align: %d gran: %d done\n", + dev_path(bus->dev), __func__, + (type & IORESOURCE_IO) ? "io" : (type & IORESOURCE_PREFETCH) ? + "prefmem" : "mem", + base, bridge->size, bridge->align, bridge->gran); + + /* For each child which is a bridge, allocate_resources. */ + for (dev = bus->children; dev; dev = dev->sibling) { + unsigned i; + struct resource *child_bridge; - printk_spew("%s compute_allocate_resource %s: base: %08Lx size: %08Lx align: %d gran: %d done\n", - dev_path(bus->dev), - (bridge->flags & IORESOURCE_IO)? "io": - (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", - base, bridge->size, bridge->align, bridge->gran); + if (!dev->links) + continue; + + /* Find the resources with matching type flags. */ + for (i = 0; i < dev->resources; i++) { + unsigned link; + child_bridge = &dev->resource[i]; + + if (!(child_bridge->flags & IORESOURCE_BRIDGE) || + (child_bridge->flags & type_mask) != type) + continue; + + /* Split prefetchable memory if combined. Many domains + * use the same address space for prefetchable memory + * and non-prefetchable memory. Bridges below them + * need it separated. Add the PREFETCH flag to the + * type_mask and type. + */ + link = IOINDEX_LINK(child_bridge->index); + allocate_resources(&dev->link[link], child_bridge, + type_mask | IORESOURCE_PREFETCH, + type | (child_bridge->flags & + IORESOURCE_PREFETCH)); + } + } +} + +#if CONFIG_PCI_64BIT_PREF_MEM == 1 + #define MEM_MASK (IORESOURCE_PREFETCH | IORESOURCE_MEM) +#else + #define MEM_MASK (IORESOURCE_MEM) +#endif +#define IO_MASK (IORESOURCE_IO) +#define PREF_TYPE (IORESOURCE_PREFETCH | IORESOURCE_MEM) +#define MEM_TYPE (IORESOURCE_MEM) +#define IO_TYPE (IORESOURCE_IO) + +struct constraints { + struct resource pref, io, mem; +}; + +static void constrain_resources(struct device *dev, struct constraints* limits) +{ + struct device *child; + struct resource *res; + struct resource *lim; + int i; + + printk_spew("%s: %s\n", __func__, dev_path(dev)); + + /* Constrain limits based on the fixed resources of this device. */ + for (i = 0; i < dev->resources; i++) { + res = &dev->resource[i]; + if (!(res->flags & IORESOURCE_FIXED)) + continue; + + /* PREFETCH, MEM, or I/O - skip any others. */ + if ((res->flags & MEM_MASK) == PREF_TYPE) + lim = &limits->pref; + else if ((res->flags & MEM_MASK) == MEM_TYPE) + lim = &limits->mem; + else if ((res->flags & IO_MASK) == IO_TYPE) + lim = &limits->io; + else + continue; + + /* Is it already outside the limits? */ + if (res->size && (((res->base + res->size -1) < lim->base) || + (res->base > lim->limit))) + continue; + + /* Choose to be above or below fixed resources. This + * check is signed so that "negative" amounts of space + * are handled correctly. + */ + if ((signed long long)(lim->limit - (res->base + res->size -1)) > + (signed long long)(res->base - lim->base)) + lim->base = res->base + res->size; + else + lim->limit = res->base -1; + } + + /* Descend into every enabled child and look for fixed resources. */ + for (i = 0; i < dev->links; i++) + for (child = dev->link[i].children; child; + child = child->sibling) + if (child->enabled) + constrain_resources(child, limits); +} + +static void avoid_fixed_resources(struct device *dev) +{ + struct constraints limits; + struct resource *res; + int i; + + printk_spew("%s: %s\n", __func__, dev_path(dev)); + /* Initialize constraints to maximum size. */ + + limits.pref.base = 0; + limits.pref.limit = 0xffffffffffffffffULL; + limits.io.base = 0; + limits.io.limit = 0xffffffffffffffffULL; + limits.mem.base = 0; + limits.mem.limit = 0xffffffffffffffffULL; + + /* Constrain the limits to dev's initial resources. */ + for (i = 0; i < dev->resources; i++) { + res = &dev->resource[i]; + if ((res->flags & IORESOURCE_FIXED)) + continue; + printk_spew("%s:@%s %02lx limit %08Lx\n", __func__, + dev_path(dev), res->index, res->limit); + if ((res->flags & MEM_MASK) == PREF_TYPE && + (res->limit < limits.pref.limit)) + limits.pref.limit = res->limit; + if ((res->flags & MEM_MASK) == MEM_TYPE && + (res->limit < limits.mem.limit)) + limits.mem.limit = res->limit; + if ((res->flags & IO_MASK) == IO_TYPE && + (res->limit < limits.io.limit)) + limits.io.limit = res->limit; + } + + /* Look through the tree for fixed resources and update the limits. */ + constrain_resources(dev, &limits); + + /* Update dev's resources with new limits. */ + for (i = 0; i < dev->resources; i++) { + struct resource *lim; + res = &dev->resource[i]; + + if ((res->flags & IORESOURCE_FIXED)) + continue; + + /* PREFETCH, MEM, or I/O - skip any others. */ + if ((res->flags & MEM_MASK) == PREF_TYPE) + lim = &limits.pref; + else if ((res->flags & MEM_MASK) == MEM_TYPE) + lim = &limits.mem; + else if ((res->flags & IO_MASK) == IO_TYPE) + lim = &limits.io; + else + continue; + + printk_spew("%s2: %s@%02lx limit %08Lx\n", __func__, + dev_path(dev), res->index, res->limit); + printk_spew("\tlim->base %08Lx lim->limit %08Lx\n", + lim->base, lim->limit); + + /* Is the resource outside the limits? */ + if (lim->base > res->base) + res->base = lim->base; + if (res->limit > lim->limit) + res->limit = lim->limit; + } } #if CONFIG_CONSOLE_VGA == 1 @@ -392,9 +666,9 @@ device_t vga_pri = 0; static void allocate_vga_resource(void) { #warning "FIXME modify allocate_vga_resource so it is less pci centric!" -#warning "This function knows to much about PCI stuff, it should be just a ietrator/visitor." +#warning "This function knows too much about PCI stuff, it should be just a iterator/visitor." - /* FIXME handle the VGA pallette snooping */ + /* FIXME: Handle the VGA palette snooping. */ struct device *dev, *vga, *vga_onboard, *vga_first, *vga_last; struct bus *bus; bus = 0; @@ -402,66 +676,63 @@ static void allocate_vga_resource(void) vga_onboard = 0; vga_first = 0; vga_last = 0; - for(dev = all_devices; dev; dev = dev->next) { - if (!dev->enabled) continue; + for (dev = all_devices; dev; dev = dev->next) { + if (!dev->enabled) + continue; if (((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) && - ((dev->class >> 8) != PCI_CLASS_DISPLAY_OTHER)) - { - if (!vga_first) { - if (dev->on_mainboard) { - vga_onboard = dev; - } else { - vga_first = dev; - } - } else { - if (dev->on_mainboard) { - vga_onboard = dev; - } else { - vga_last = dev; - } - } - - /* It isn't safe to enable other VGA cards */ + ((dev->class >> 8) != PCI_CLASS_DISPLAY_OTHER)) { + if (!vga_first) { + if (dev->on_mainboard) { + vga_onboard = dev; + } else { + vga_first = dev; + } + } else { + if (dev->on_mainboard) { + vga_onboard = dev; + } else { + vga_last = dev; + } + } + + /* It isn't safe to enable other VGA cards. */ dev->command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO); } } - vga = vga_last; - - if(!vga) { - vga = vga_first; - } + vga = vga_last; + if (!vga) { + vga = vga_first; + } #if CONFIG_CONSOLE_VGA_ONBOARD_AT_FIRST == 1 - if (vga_onboard) // will use on board vga as pri + if (vga_onboard) // Will use on board VGA as pri. #else - if (!vga) // will use last add on adapter as pri + if (!vga) // Will use last add on adapter as pri. #endif - { - vga = vga_onboard; - } - + { + vga = vga_onboard; + } if (vga) { - /* vga is first add on card or the only onboard vga */ + /* VGA is first add on card or the only onboard VGA. */ printk_debug("Allocating VGA resource %s\n", dev_path(vga)); - /* All legacy VGA cards have MEM & I/O space registers */ + /* All legacy VGA cards have MEM & I/O space registers. */ vga->command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_IO); vga_pri = vga; bus = vga->bus; } - /* Now walk up the bridges setting the VGA enable */ - while(bus) { + /* Now walk up the bridges setting the VGA enable. */ + while (bus) { printk_debug("Setting PCI_BRIDGE_CTL_VGA for bridge %s\n", dev_path(bus->dev)); bus->bridge_ctrl |= PCI_BRIDGE_CTL_VGA; - bus = (bus == bus->dev->bus)? 0 : bus->dev->bus; + bus = (bus == bus->dev->bus) ? 0 : bus->dev->bus; } } #endif - /** * @brief Assign the computed resources to the devices on the bus. * @@ -480,21 +751,21 @@ void assign_resources(struct bus *bus) struct device *curdev; printk_spew("%s assign_resources, bus %d link: %d\n", - dev_path(bus->dev), bus->secondary, bus->link); + dev_path(bus->dev), bus->secondary, bus->link); - for(curdev = bus->children; curdev; curdev = curdev->sibling) { + for (curdev = bus->children; curdev; curdev = curdev->sibling) { if (!curdev->enabled || !curdev->resources) { continue; } if (!curdev->ops || !curdev->ops->set_resources) { printk_err("%s missing set_resources\n", - dev_path(curdev)); + dev_path(curdev)); continue; } curdev->ops->set_resources(curdev); } printk_spew("%s assign_resources, bus %d link: %d\n", - dev_path(bus->dev), bus->secondary, bus->link); + dev_path(bus->dev), bus->secondary, bus->link); } /** @@ -539,8 +810,7 @@ void enable_resources(struct device *dev) */ int reset_bus(struct bus *bus) { - if (bus && bus->dev && bus->dev->ops && bus->dev->ops->reset_bus) - { + if (bus && bus->dev && bus->dev->ops && bus->dev->ops->reset_bus) { bus->dev->ops->reset_bus(bus); bus->reset_needed = 0; return 1; @@ -551,37 +821,34 @@ int reset_bus(struct bus *bus) /** * @brief Scan for devices on a bus. * - * If there are bridges on the bus, recursively scan the buses behind the bridges. - * If the setting up and tuning of the bus causes a reset to be required, - * reset the bus and scan it again. + * If there are bridges on the bus, recursively scan the buses behind the + * bridges. If the setting up and tuning of the bus causes a reset to be + * required, reset the bus and scan it again. * - * @param bus pointer to the bus device - * @param max current bus number - * - * @return The maximum bus number found, after scanning all subordinate busses + * @param busdev Pointer to the bus device. + * @param max Current bus number. + * @return The maximum bus number found, after scanning all subordinate buses. */ -unsigned int scan_bus(device_t bus, unsigned int max) +unsigned int scan_bus(struct device *busdev, unsigned int max) { unsigned int new_max; int do_scan_bus; - if ( !bus || - !bus->enabled || - !bus->ops || - !bus->ops->scan_bus) - { + if (!busdev || !busdev->enabled || !busdev->ops || + !busdev->ops->scan_bus) { return max; } + do_scan_bus = 1; - while(do_scan_bus) { + while (do_scan_bus) { int link; - new_max = bus->ops->scan_bus(bus, max); + new_max = busdev->ops->scan_bus(busdev, max); do_scan_bus = 0; - for(link = 0; link < bus->links; link++) { - if (bus->link[link].reset_needed) { - if (reset_bus(&bus->link[link])) { + for (link = 0; link < busdev->links; link++) { + if (busdev->link[link].reset_needed) { + if (reset_bus(&busdev->link[link])) { do_scan_bus = 1; } else { - bus->bus->reset_needed = 1; + busdev->bus->reset_needed = 1; } } } @@ -589,7 +856,6 @@ unsigned int scan_bus(device_t bus, unsigned int max) return new_max; } - /** * @brief Determine the existence of devices and extend the device tree. * @@ -619,7 +885,7 @@ void dev_enumerate(void) printk_info("Enumerating buses...\n"); root = &dev_root; - show_all_devs(BIOS_DEBUG, "Before Phase 3."); + show_all_devs(BIOS_DEBUG, "Before Device Enumeration."); printk_debug("Compare with tree...\n"); show_devs_tree(root, BIOS_DEBUG, 0, 0); @@ -643,66 +909,115 @@ void dev_enumerate(void) * requried by each device. In the second pass, the resources ranges are * relocated to their final position and stored to the hardware. * - * I/O resources start at DEVICE_IO_START and grow upward. MEM resources start - * at DEVICE_MEM_HIGH and grow downward. + * I/O resources grow upward. MEM resources grow downward. * * Since the assignment is hierarchical we set the values into the dev_root * struct. */ void dev_configure(void) { - struct resource *io, *mem; + struct resource *res; struct device *root; + struct device *child; + int i; printk_info("Allocating resources...\n"); root = &dev_root; - print_resource_tree(root, BIOS_DEBUG, "Original."); + /* Each domain should create resources which contain the entire address + * space for IO, MEM, and PREFMEM resources in the domain. The + * allocation of device resources will be done from this address space. + */ - if (!root->ops || !root->ops->read_resources) { - printk_err("dev_root missing read_resources\n"); - return; - } - if (!root->ops || !root->ops->set_resources) { - printk_err("dev_root missing set_resources\n"); - return; - } + /* Read the resources for the entire tree. */ printk_info("Reading resources...\n"); - root->ops->read_resources(root); + read_resources(&root->link[0]); printk_info("Done reading resources.\n"); print_resource_tree(root, BIOS_DEBUG, "After reading."); - /* Get the resources */ - io = &root->resource[0]; - mem = &root->resource[1]; - /* Make certain the io devices are allocated somewhere safe. */ - io->base = DEVICE_IO_START; - io->flags |= IORESOURCE_ASSIGNED; - io->flags &= ~IORESOURCE_STORED; - /* Now reallocate the pci resources memory with the - * highest addresses I can manage. + /* Compute resources for all domains. */ + for (child = root->link[0].children; child; child = child->sibling) { + if (!(child->path.type == DEVICE_PATH_PCI_DOMAIN)) + continue; + for (i = 0; i < child->resources; i++) { + res = &child->resource[i]; + if (res->flags & IORESOURCE_FIXED) + continue; + if (res->flags & IORESOURCE_PREFETCH) { + compute_resources(&child->link[0], + res, MEM_MASK, PREF_TYPE); + continue; + } + if (res->flags & IORESOURCE_MEM) { + compute_resources(&child->link[0], + res, MEM_MASK, MEM_TYPE); + continue; + } + if (res->flags & IORESOURCE_IO) { + compute_resources(&child->link[0], + res, IO_MASK, IO_TYPE); + continue; + } + } + } + + /* For all domains. */ + for (child = root->link[0].children; child; child=child->sibling) + if (child->path.type == DEVICE_PATH_PCI_DOMAIN) + avoid_fixed_resources(child); + + /* Now we need to adjust the resources. MEM resources need to start at + * the highest address managable. */ - mem->base = resource_max(&root->resource[1]); - mem->flags |= IORESOURCE_ASSIGNED; - mem->flags &= ~IORESOURCE_STORED; + for (child = root->link[0].children; child; child = child->sibling) { + if (child->path.type != DEVICE_PATH_PCI_DOMAIN) + continue; + for (i = 0; i < child->resources; i++) { + res = &child->resource[i]; + if (!(res->flags & IORESOURCE_MEM) || + res->flags & IORESOURCE_FIXED) + continue; + res->base = resource_max(res); + } + } #if CONFIG_CONSOLE_VGA == 1 - /* Allocate the VGA I/O resource.. */ + /* Allocate the VGA I/O resource. */ allocate_vga_resource(); print_resource_tree(root, BIOS_DEBUG, "After VGA."); #endif /* Store the computed resource allocations into device registers ... */ printk_info("Setting resources...\n"); - root->ops->set_resources(root); + for (child = root->link[0].children; child; child = child->sibling) { + if (!(child->path.type == DEVICE_PATH_PCI_DOMAIN)) + continue; + for (i = 0; i < child->resources; i++) { + res = &child->resource[i]; + if (res->flags & IORESOURCE_FIXED) + continue; + if (res->flags & IORESOURCE_PREFETCH) { + allocate_resources(&child->link[0], + res, MEM_MASK, PREF_TYPE); + continue; + } + if (res->flags & IORESOURCE_MEM) { + allocate_resources(&child->link[0], + res, MEM_MASK, MEM_TYPE); + continue; + } + if (res->flags & IORESOURCE_IO) { + allocate_resources(&child->link[0], + res, IO_MASK, IO_TYPE); + continue; + } + } + } + assign_resources(&root->link[0]); printk_info("Done setting resources.\n"); -#if 0 - mem->flags |= IORESOURCE_STORED; - report_resource_stored(root, mem, ""); -#endif print_resource_tree(root, BIOS_DEBUG, "After assigning values."); printk_info("Done allocating resources.\n"); @@ -736,13 +1051,13 @@ void dev_initialize(void) struct device *dev; printk_info("Initializing devices...\n"); - for(dev = all_devices; dev; dev = dev->next) { + for (dev = all_devices; dev; dev = dev->next) { if (dev->enabled && !dev->initialized && - dev->ops && dev->ops->init) - { + dev->ops && dev->ops->init) { if (dev->path.type == DEVICE_PATH_I2C) { - printk_debug("smbus: %s[%d]->", - dev_path(dev->bus->dev), dev->bus->link); + printk_debug("smbus: %s[%d]->", + dev_path(dev->bus->dev), + dev->bus->link); } printk_debug("%s init\n", dev_path(dev)); dev->initialized = 1; @@ -752,4 +1067,3 @@ void dev_initialize(void) printk_info("Devices initialized\n"); show_all_devs(BIOS_DEBUG, "After init."); } - diff --git a/src/devices/device_util.c b/src/devices/device_util.c index c5a2f64..eef4c6f 100644 --- a/src/devices/device_util.c +++ b/src/devices/device_util.c @@ -487,7 +487,7 @@ void search_bus_resources(struct bus *bus, for(curdev = bus->children; curdev; curdev = curdev->sibling) { int i; /* Ignore disabled devices */ - if (!curdev->have_resources) continue; + if (!curdev->enabled) continue; for(i = 0; i < curdev->resources; i++) { struct resource *resource = &curdev->resource[i]; /* If it isn't the right kind of resource ignore it */ @@ -514,7 +514,7 @@ void search_global_resources( for(curdev = all_devices; curdev; curdev = curdev->next) { int i; /* Ignore disabled devices */ - if (!curdev->have_resources) continue; + if (!curdev->enabled) continue; for(i = 0; i < curdev->resources; i++) { struct resource *resource = &curdev->resource[i]; /* If it isn't the right kind of resource ignore it */ diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index 2531bfd..4a7a2cd 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -15,12 +15,12 @@ */ /* - * PCI Bus Services, see include/linux/pci.h for further explanation. + * PCI Bus Services, see include/linux/pci.h for further explanation. * - * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, - * David Mosberger-Tang + * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, + * David Mosberger-Tang * - * Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz> + * Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz> */ #include <console/console.h> @@ -51,9 +51,9 @@ #include <device/cardbus.h> #endif -uint8_t pci_moving_config8(struct device *dev, unsigned reg) +u8 pci_moving_config8(struct device *dev, unsigned int reg) { - uint8_t value, ones, zeroes; + u8 value, ones, zeroes; value = pci_read_config8(dev, reg); pci_write_config8(dev, reg, 0xff); @@ -67,9 +67,9 @@ uint8_t pci_moving_config8(struct device *dev, unsigned reg) return ones ^ zeroes; } -uint16_t pci_moving_config16(struct device *dev, unsigned reg) +u16 pci_moving_config16(struct device * dev, unsigned int reg) { - uint16_t value, ones, zeroes; + u16 value, ones, zeroes; value = pci_read_config16(dev, reg); pci_write_config16(dev, reg, 0xffff); @@ -83,9 +83,9 @@ uint16_t pci_moving_config16(struct device *dev, unsigned reg) return ones ^ zeroes; } -uint32_t pci_moving_config32(struct device *dev, unsigned reg) +u32 pci_moving_config32(struct device * dev, unsigned int reg) { - uint32_t value, ones, zeroes; + u32 value, ones, zeroes; value = pci_read_config32(dev, reg); pci_write_config32(dev, reg, 0xffffffff); @@ -99,7 +99,16 @@ uint32_t pci_moving_config32(struct device *dev, unsigned reg) return ones ^ zeroes; } -unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last) +/** + * Given a device, a capability type, and a last position, return the next + * matching capability. Always start at the head of the list. + * + * @param dev Pointer to the device structure. + * @param cap_type PCI_CAP_LIST_ID of the PCI capability we're looking for. + * @param last Location of the PCI capability register to start from. + */ +unsigned pci_find_next_capability(struct device *dev, unsigned cap, + unsigned last) { unsigned pos; unsigned status; @@ -109,7 +118,7 @@ unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last) if (!(status & PCI_STATUS_CAP_LIST)) { return 0; } - switch(dev->hdr_type & 0x7f) { + switch (dev->hdr_type & 0x7f) { case PCI_HEADER_TYPE_NORMAL: case PCI_HEADER_TYPE_BRIDGE: pos = PCI_CAPABILITY_LIST; @@ -121,11 +130,12 @@ unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last) return 0; } pos = pci_read_config8(dev, pos); - while(reps-- && (pos >= 0x40)) { /* loop through the linked list */ + while (reps-- && (pos >= 0x40)) { /* Loop through the linked list. */ int this_cap; pos &= ~3; this_cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID); - printk_spew("Capability: 0x%02x @ 0x%02x\n", cap, pos); + printk_spew("Capability: type 0x%02x @ 0x%02x\n", this_cap, + pos); if (this_cap == 0xff) { break; } @@ -140,64 +150,71 @@ unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last) return 0; } +/** + * Given a device, and a capability type, return the next matching + * capability. Always start at the head of the list. + * + * @param dev Pointer to the device structure. + * @param cap_type PCI_CAP_LIST_ID of the PCI capability we're looking for. + */ unsigned pci_find_capability(device_t dev, unsigned cap) { return pci_find_next_capability(dev, cap, 0); - } -/** Given a device and register, read the size of the BAR for that register. - * @param dev Pointer to the device structure - * @param resource Pointer to the resource structure - * @param index Address of the pci configuration register +/** + * Given a device and register, read the size of the BAR for that register. + * + * @param dev Pointer to the device structure. + * @param index Address of the PCI configuration register. */ struct resource *pci_get_resource(struct device *dev, unsigned long index) { struct resource *resource; unsigned long value, attr; - resource_t moving, limit; + resource_t moving, limit; - /* Initialize the resources to nothing */ + /* Initialize the resources to nothing. */ resource = new_resource(dev, index); - /* Get the initial value */ + /* Get the initial value. */ value = pci_read_config32(dev, index); - /* See which bits move */ + /* See which bits move. */ moving = pci_moving_config32(dev, index); - /* Initialize attr to the bits that do not move */ + /* Initialize attr to the bits that do not move. */ attr = value & ~moving; - /* If it is a 64bit resource look at the high half as well */ + /* If it is a 64bit resource look at the high half as well. */ if (((attr & PCI_BASE_ADDRESS_SPACE_IO) == 0) && - ((attr & PCI_BASE_ADDRESS_MEM_LIMIT_MASK) == PCI_BASE_ADDRESS_MEM_LIMIT_64)) - { - /* Find the high bits that move */ - moving |= ((resource_t)pci_moving_config32(dev, index + 4)) << 32; + ((attr & PCI_BASE_ADDRESS_MEM_LIMIT_MASK) == + PCI_BASE_ADDRESS_MEM_LIMIT_64)) { + /* Find the high bits that move. */ + moving |= + ((resource_t) pci_moving_config32(dev, index + 4)) << 32; } /* Find the resource constraints. - * * Start by finding the bits that move. From there: * - Size is the least significant bit of the bits that move. * - Limit is all of the bits that move plus all of the lower bits. - * See PCI Spec 6.2.5.1 ... + * See PCI Spec 6.2.5.1. */ limit = 0; if (moving) { resource->size = 1; resource->align = resource->gran = 0; - while(!(moving & resource->size)) { + while (!(moving & resource->size)) { resource->size <<= 1; resource->align += 1; - resource->gran += 1; + resource->gran += 1; } resource->limit = limit = moving | (resource->size - 1); } - /* - * some broken hardware has read-only registers that do not + + /* Some broken hardware has read-only registers that do not * really size correctly. - * Example: the acer m7229 has BARs 1-4 normally read-only. + * Example: the Acer M7229 has BARs 1-4 normally read-only. * so BAR1 at offset 0x10 reads 0x1f1. If you size that register * by writing 0xffffffff to it, it will read back as 0x1f1 -- a * violation of the spec. @@ -207,21 +224,19 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index) */ if (moving == 0) { if (value != 0) { - printk_debug( - "%s register %02lx(%08lx), read-only ignoring it\n", - dev_path(dev), index, value); + printk_debug + ("%s register %02lx(%08lx), read-only ignoring it\n", + dev_path(dev), index, value); } resource->flags = 0; - } - else if (attr & PCI_BASE_ADDRESS_SPACE_IO) { - /* An I/O mapped base address */ + } else if (attr & PCI_BASE_ADDRESS_SPACE_IO) { + /* An I/O mapped base address. */ attr &= PCI_BASE_ADDRESS_IO_ATTR_MASK; resource->flags |= IORESOURCE_IO; - /* I don't want to deal with 32bit I/O resources */ + /* I don't want to deal with 32bit I/O resources. */ resource->limit = 0xffff; - } - else { - /* A Memory mapped base address */ + } else { + /* A Memory mapped base address. */ attr &= PCI_BASE_ADDRESS_MEM_ATTR_MASK; resource->flags |= IORESOURCE_MEM; if (attr & PCI_BASE_ADDRESS_MEM_PREFETCH) { @@ -229,73 +244,65 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index) } attr &= PCI_BASE_ADDRESS_MEM_LIMIT_MASK; if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_32) { - /* 32bit limit */ + /* 32bit limit. */ resource->limit = 0xffffffffUL; - } - else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_1M) { - /* 1MB limit */ + } else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_1M) { + /* 1MB limit. */ resource->limit = 0x000fffffUL; - } - else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_64) { - /* 64bit limit */ + } else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_64) { + /* 64bit limit. */ resource->limit = 0xffffffffffffffffULL; resource->flags |= IORESOURCE_PCI64; - } - else { - /* Invalid value */ + } else { + /* Invalid value. */ + printk_err("Broken BAR with value %lx\n", attr); + printk_err(" on dev %s at index %02lx\n", + dev_path(dev), index); resource->flags = 0; } } - /* Don't let the limit exceed which bits can move */ + /* Don't let the limit exceed which bits can move. */ if (resource->limit > limit) { resource->limit = limit; } -#if 0 - if (resource->flags) { - printk_debug("%s %02x ->", - dev_path(dev), resource->index); - printk_debug(" value: 0x%08Lx zeroes: 0x%08Lx ones: 0x%08Lx attr: %08lx\n", - value, zeroes, ones, attr); - printk_debug( - "%s %02x -> size: 0x%08Lx max: 0x%08Lx %s\n ", - dev_path(dev), - resource->index, - resource->size, resource->limit, - resource_type(resource)); - } -#endif return resource; } +/** + * Given a device and an index, read the size of the BAR for that register. + * + * @param dev Pointer to the device structure. + * @param index Address of the PCI configuration register. + */ static void pci_get_rom_resource(struct device *dev, unsigned long index) { struct resource *resource; unsigned long value; - resource_t moving; + resource_t moving; - if ((dev->on_mainboard) && (dev->rom_address == 0)) { - //skip it if rom_address is not set in MB Config.lb - return; - } + if ((dev->on_mainboard) && (dev->rom_address == 0)) { + /* Skip it if rom_address is not set in the MB Config.lb. */ + return; + } - /* Initialize the resources to nothing */ + /* Initialize the resources to nothing. */ resource = new_resource(dev, index); - /* Get the initial value */ + /* Get the initial value. */ value = pci_read_config32(dev, index); - /* See which bits move */ + /* See which bits move. */ moving = pci_moving_config32(dev, index); - /* clear the Enable bit */ + + /* Clear the Enable bit. */ moving = moving & ~PCI_ROM_ADDRESS_ENABLE; /* Find the resource constraints. - * * Start by finding the bits that move. From there: * - Size is the least significant bit of the bits that move. * - Limit is all of the bits that move plus all of the lower bits. - * See PCI Spec 6.2.5.1 ... + * See PCI Spec 6.2.5.1. */ if (moving) { resource->size = 1; @@ -303,59 +310,57 @@ static void pci_get_rom_resource(struct device *dev, unsigned long index) while (!(moving & resource->size)) { resource->size <<= 1; resource->align += 1; - resource->gran += 1; + resource->gran += 1; } resource->limit = moving | (resource->size - 1); - } - - if (moving == 0) { + resource->flags |= IORESOURCE_MEM | IORESOURCE_READONLY; + } else { if (value != 0) { - printk_debug("%s register %02lx(%08lx), read-only ignoring it\n", - dev_path(dev), index, value); + printk_debug + ("%s register %02lx(%08lx), read-only ignoring it\n", + dev_path(dev), index, value); } resource->flags = 0; - } else { - resource->flags |= IORESOURCE_MEM | IORESOURCE_READONLY; } - /* for on board device with embedded ROM image, the ROM image is at + /* For on board device with embedded ROM image, the ROM image is at * fixed address specified in the Config.lb, the dev->rom_address is * inited by driver_pci_onboard_ops::enable_dev() */ if ((dev->on_mainboard) && (dev->rom_address != 0)) { - resource->base = dev->rom_address; + resource->base = dev->rom_address; resource->flags |= IORESOURCE_MEM | IORESOURCE_READONLY | - IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; } compact_resources(dev); } -/** Read the base address registers for a given device. - * @param dev Pointer to the dev structure - * @param howmany How many registers to read (6 for device, 2 for bridge) +/** + * Read the base address registers for a given device. + * + * @param dev Pointer to the dev structure. + * @param howmany How many registers to read (6 for device, 2 for bridge). */ static void pci_read_bases(struct device *dev, unsigned int howmany) { unsigned long index; - for(index = PCI_BASE_ADDRESS_0; (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { + for (index = PCI_BASE_ADDRESS_0; + (index < PCI_BASE_ADDRESS_0 + (howmany << 2));) { struct resource *resource; resource = pci_get_resource(dev, index); - index += (resource->flags & IORESOURCE_PCI64)?8:4; + index += (resource->flags & IORESOURCE_PCI64) ? 8 : 4; } compact_resources(dev); } -static void pci_set_resource(struct device *dev, struct resource *resource); - -static void pci_record_bridge_resource( - struct device *dev, resource_t moving, - unsigned index, unsigned long mask, unsigned long type) +static void pci_record_bridge_resource(struct device *dev, resource_t moving, + unsigned index, unsigned long type) { - /* Initiliaze the constraints on the current bus */ + /* Initialize the constraints on the current bus. */ struct resource *resource; - resource = 0; + resource = NULL; if (moving) { unsigned long gran; resource_t step; @@ -363,29 +368,15 @@ static void pci_record_bridge_resource( resource->size = 0; gran = 0; step = 1; - while((moving & step) == 0) { + while ((moving & step) == 0) { gran += 1; step <<= 1; } resource->gran = gran; resource->align = gran; resource->limit = moving | (step - 1); - resource->flags = type | IORESOURCE_PCI_BRIDGE; - compute_allocate_resource(&dev->link[0], resource, mask, type); - /* If there is nothing behind the resource, - * clear it and forget it. - */ - if (resource->size == 0) { -#if CONFIG_PCI_64BIT_PREF_MEM == 1 - resource->base = moving; -#else - resource->base = moving & 0xffffffff; -#endif - resource->flags |= IORESOURCE_ASSIGNED; - resource->flags &= ~IORESOURCE_STORED; - pci_set_resource(dev, resource); - resource->flags = 0; - } + resource->flags = type | IORESOURCE_PCI_BRIDGE | + IORESOURCE_BRIDGE; } return; } @@ -394,47 +385,48 @@ static void pci_bridge_read_bases(struct device *dev) { resource_t moving_base, moving_limit, moving; - /* See if the bridge I/O resources are implemented */ - moving_base = ((uint32_t)pci_moving_config8(dev, PCI_IO_BASE)) << 8; - moving_base |= ((uint32_t)pci_moving_config16(dev, PCI_IO_BASE_UPPER16)) << 16; + /* See if the bridge I/O resources are implemented. */ + moving_base = ((u32) pci_moving_config8(dev, PCI_IO_BASE)) << 8; + moving_base |= + ((u32) pci_moving_config16(dev, PCI_IO_BASE_UPPER16)) << 16; - moving_limit = ((uint32_t)pci_moving_config8(dev, PCI_IO_LIMIT)) << 8; - moving_limit |= ((uint32_t)pci_moving_config16(dev, PCI_IO_LIMIT_UPPER16)) << 16; + moving_limit = ((u32) pci_moving_config8(dev, PCI_IO_LIMIT)) << 8; + moving_limit |= + ((u32) pci_moving_config16(dev, PCI_IO_LIMIT_UPPER16)) << 16; moving = moving_base & moving_limit; - /* Initialize the io space constraints on the current bus */ - pci_record_bridge_resource( - dev, moving, PCI_IO_BASE, - IORESOURCE_IO, IORESOURCE_IO); + /* Initialize the I/O space constraints on the current bus. */ + pci_record_bridge_resource(dev, moving, PCI_IO_BASE, IORESOURCE_IO); + /* See if the bridge prefmem resources are implemented. */ + moving_base = + ((resource_t) pci_moving_config16(dev, PCI_PREF_MEMORY_BASE)) << 16; + moving_base |= + ((resource_t) pci_moving_config32(dev, PCI_PREF_BASE_UPPER32)) << + 32; - /* See if the bridge prefmem resources are implemented */ - moving_base = ((resource_t)pci_moving_config16(dev, PCI_PREF_MEMORY_BASE)) << 16; - moving_base |= ((resource_t)pci_moving_config32(dev, PCI_PREF_BASE_UPPER32)) << 32; - - moving_limit = ((resource_t)pci_moving_config16(dev, PCI_PREF_MEMORY_LIMIT)) << 16; - moving_limit |= ((resource_t)pci_moving_config32(dev, PCI_PREF_LIMIT_UPPER32)) << 32; + moving_limit = + ((resource_t) pci_moving_config16(dev, PCI_PREF_MEMORY_LIMIT)) << + 16; + moving_limit |= + ((resource_t) pci_moving_config32(dev, PCI_PREF_LIMIT_UPPER32)) << + 32; moving = moving_base & moving_limit; - /* Initiliaze the prefetchable memory constraints on the current bus */ - pci_record_bridge_resource( - dev, moving, PCI_PREF_MEMORY_BASE, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM | IORESOURCE_PREFETCH); - + /* Initialize the prefetchable memory constraints on the current bus. */ + pci_record_bridge_resource(dev, moving, PCI_PREF_MEMORY_BASE, + IORESOURCE_MEM | IORESOURCE_PREFETCH); - /* See if the bridge mem resources are implemented */ - moving_base = ((uint32_t)pci_moving_config16(dev, PCI_MEMORY_BASE)) << 16; - moving_limit = ((uint32_t)pci_moving_config16(dev, PCI_MEMORY_LIMIT)) << 16; + /* See if the bridge mem resources are implemented. */ + moving_base = ((u32) pci_moving_config16(dev, PCI_MEMORY_BASE)) << 16; + moving_limit = ((u32) pci_moving_config16(dev, PCI_MEMORY_LIMIT)) << 16; moving = moving_base & moving_limit; - /* Initialize the memory resources on the current bus */ - pci_record_bridge_resource( - dev, moving, PCI_MEMORY_BASE, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM); + /* Initialize the memory resources on the current bus. */ + pci_record_bridge_resource(dev, moving, PCI_MEMORY_BASE, + IORESOURCE_MEM); compact_resources(dev); } @@ -452,34 +444,50 @@ void pci_bus_read_resources(struct device *dev) pci_get_rom_resource(dev, PCI_ROM_ADDRESS1); } +void pci_domain_read_resources(struct device *dev) +{ + struct resource *res; + + /* Initialize the system-wide I/O space constraints. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); + res->limit = 0xffffUL; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED; + + /* Initialize the system-wide memory resources constraints. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + res->limit = 0xffffffffULL; + res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED; +} + static void pci_set_resource(struct device *dev, struct resource *resource) { resource_t base, end; - /* Make certain the resource has actually been set */ + /* Make certain the resource has actually been assigned a value. */ if (!(resource->flags & IORESOURCE_ASSIGNED)) { - printk_err("ERROR: %s %02lx %s size: 0x%010Lx not assigned\n", - dev_path(dev), resource->index, - resource_type(resource), - resource->size); + printk_err("ERROR: %s %02lx %s size: 0x%010llx not assigned\n", + dev_path(dev), resource->index, + resource_type(resource), resource->size); return; } - /* If I have already stored this resource don't worry about it */ + /* If I have already stored this resource don't worry about it. */ if (resource->flags & IORESOURCE_STORED) { return; } - /* If the resources is substractive don't worry about it */ + /* If the resource is subtractive don't worry about it. */ if (resource->flags & IORESOURCE_SUBTRACTIVE) { return; } - /* Only handle PCI memory and IO resources for now */ - if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO))) + /* Only handle PCI memory and I/O resources for now. */ + if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO))) return; - /* Enable the resources in the command register */ + /* Enable the resources in the command register. */ if (resource->size) { if (resource->flags & IORESOURCE_MEM) { dev->command |= PCI_COMMAND_MEMORY; @@ -491,19 +499,29 @@ static void pci_set_resource(struct device *dev, struct resource *resource) dev->command |= PCI_COMMAND_MASTER; } } - /* Get the base address */ + /* Get the base address. */ base = resource->base; - /* Get the end */ + /* Get the end. */ end = resource_end(resource); - /* Now store the resource */ + /* Now store the resource. */ resource->flags |= IORESOURCE_STORED; + + /* PCI Bridges have no enable bit. They are disabled if the base of + * the range is greater than the limit. If the size is zero, disable + * by setting the base = limit and end = limit - 2^gran. + */ + if (resource->size == 0 && (resource->flags & IORESOURCE_PCI_BRIDGE)) { + base = resource->limit; + end = resource->limit - (1 << resource->gran); + resource->base = base; + } + if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) { unsigned long base_lo, base_hi; - /* - * some chipsets allow us to set/clear the IO bit. - * (e.g. VIA 82c686a.) So set it to be safe) + /* Some chipsets allow us to set/clear the I/O bit + * (e.g. VIA 82c686a). So set it to be safe. */ base_lo = base & 0xffffffff; base_hi = (base >> 32) & 0xffffffff; @@ -514,39 +532,27 @@ static void pci_set_resource(struct device *dev, struct resource *resource) if (resource->flags & IORESOURCE_PCI64) { pci_write_config32(dev, resource->index + 4, base_hi); } - } - else if (resource->index == PCI_IO_BASE) { - /* set the IO ranges */ - compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_IO, IORESOURCE_IO); - pci_write_config8(dev, PCI_IO_BASE, base >> 8); + } else if (resource->index == PCI_IO_BASE) { + /* Set the I/O ranges. */ + pci_write_config8(dev, PCI_IO_BASE, base >> 8); pci_write_config16(dev, PCI_IO_BASE_UPPER16, base >> 16); - pci_write_config8(dev, PCI_IO_LIMIT, end >> 8); + pci_write_config8(dev, PCI_IO_LIMIT, end >> 8); pci_write_config16(dev, PCI_IO_LIMIT_UPPER16, end >> 16); - } - else if (resource->index == PCI_MEMORY_BASE) { - /* set the memory range */ - compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM); + } else if (resource->index == PCI_MEMORY_BASE) { + /* Set the memory range. */ pci_write_config16(dev, PCI_MEMORY_BASE, base >> 16); pci_write_config16(dev, PCI_MEMORY_LIMIT, end >> 16); - } - else if (resource->index == PCI_PREF_MEMORY_BASE) { - /* set the prefetchable memory range */ - compute_allocate_resource(&dev->link[0], resource, - IORESOURCE_MEM | IORESOURCE_PREFETCH, - IORESOURCE_MEM | IORESOURCE_PREFETCH); + } else if (resource->index == PCI_PREF_MEMORY_BASE) { + /* Set the prefetchable memory range. */ pci_write_config16(dev, PCI_PREF_MEMORY_BASE, base >> 16); pci_write_config32(dev, PCI_PREF_BASE_UPPER32, base >> 32); pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, end >> 16); pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, end >> 32); - } - else { - /* Don't let me think I stored the resource */ + } else { + /* Don't let me think I stored the resource. */ resource->flags &= ~IORESOURCE_STORED; printk_err("ERROR: invalid resource->index %lx\n", - resource->index); + resource->index); } report_resource_stored(dev, resource, ""); return; @@ -556,14 +562,14 @@ void pci_dev_set_resources(struct device *dev) { struct resource *resource, *last; unsigned link; - uint8_t line; + u8 line; last = &dev->resource[dev->resources]; - for(resource = &dev->resource[0]; resource < last; resource++) { + for (resource = &dev->resource[0]; resource < last; resource++) { pci_set_resource(dev, resource); } - for(link = 0; link < dev->links; link++) { + for (link = 0; link < dev->links; link++) { struct bus *bus; bus = &dev->link[link]; if (bus->children) { @@ -571,60 +577,64 @@ void pci_dev_set_resources(struct device *dev) } } - /* set a default latency timer */ + /* Set a default latency timer. */ pci_write_config8(dev, PCI_LATENCY_TIMER, 0x40); - /* set a default secondary latency timer */ + /* Set a default secondary latency timer. */ if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { pci_write_config8(dev, PCI_SEC_LATENCY_TIMER, 0x40); } - /* zero the irq settings */ + /* Zero the IRQ settings. */ line = pci_read_config8(dev, PCI_INTERRUPT_PIN); if (line) { pci_write_config8(dev, PCI_INTERRUPT_LINE, 0); } - /* set the cache line size, so far 64 bytes is good for everyone */ + /* Set the cache line size, so far 64 bytes is good for everyone. */ pci_write_config8(dev, PCI_CACHE_LINE_SIZE, 64 >> 2); } void pci_dev_enable_resources(struct device *dev) { const struct pci_operations *ops; - uint16_t command; + u16 command; - /* Set the subsystem vendor and device id for mainboard devices */ + /* Set the subsystem vendor and device id for mainboard devices. */ ops = ops_pci(dev); if (dev->on_mainboard && ops && ops->set_subsystem) { printk_debug("%s subsystem <- %02x/%02x\n", - dev_path(dev), - CONFIG_MAINBOARD_PCI_SUBSYSTEM_VENDOR_ID, - CONFIG_MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID); + dev_path(dev), + CONFIG_MAINBOARD_PCI_SUBSYSTEM_VENDOR_ID, + CONFIG_MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID); ops->set_subsystem(dev, - CONFIG_MAINBOARD_PCI_SUBSYSTEM_VENDOR_ID, - CONFIG_MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID); + CONFIG_MAINBOARD_PCI_SUBSYSTEM_VENDOR_ID, + CONFIG_MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID); } command = pci_read_config16(dev, PCI_COMMAND); command |= dev->command; + /* v3 has + * command |= (PCI_COMMAND_PARITY + PCI_COMMAND_SERR); // Error check. + */ printk_debug("%s cmd <- %02x\n", dev_path(dev), command); pci_write_config16(dev, PCI_COMMAND, command); } void pci_bus_enable_resources(struct device *dev) { - uint16_t ctrl; - /* enable IO in command register if there is VGA card - * connected with (even it does not claim IO resource) */ + u16 ctrl; + + /* Enable I/O in command register if there is VGA card + * connected with (even it does not claim I/O resource). + */ if (dev->link[0].bridge_ctrl & PCI_BRIDGE_CTL_VGA) dev->command |= PCI_COMMAND_IO; ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); ctrl |= dev->link[0].bridge_ctrl; - ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* error check */ + ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* Error check. */ printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); pci_dev_enable_resources(dev); - enable_childrens_resources(dev); } @@ -640,17 +650,17 @@ void pci_bus_reset(struct bus *bus) delay(1); } -void pci_dev_set_subsystem(device_t dev, unsigned vendor, unsigned device) +void pci_dev_set_subsystem(struct device *dev, unsigned vendor, unsigned device) { pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, - ((device & 0xffff) << 16) | (vendor & 0xffff)); + ((device & 0xffff) << 16) | (vendor & 0xffff)); } /** default handler: only runs the relevant pci bios. */ void pci_dev_init(struct device *dev) { #if CONFIG_PCI_ROM_RUN == 1 || CONFIG_VGA_ROM_RUN == 1 - void run_bios(struct device * dev, unsigned long addr); + void run_bios(struct device *dev, unsigned long addr); struct rom_header *rom, *ram; #if CONFIG_PCI_ROM_RUN != 1 @@ -658,7 +668,7 @@ void pci_dev_init(struct device *dev) * is set but CONFIG_PCI_ROM_RUN is not. In this case we skip * all other option ROM types. */ - if ((dev->class>>8)!=PCI_CLASS_DISPLAY_VGA) + if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) return; #endif @@ -685,13 +695,13 @@ static struct pci_operations pci_dev_ops_pci = { }; struct device_operations default_pci_ops_dev = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, - .init = pci_dev_init, - .scan_bus = 0, - .enable = 0, - .ops_pci = &pci_dev_ops_pci, + .init = pci_dev_init, + .scan_bus = 0, + .enable = 0, + .ops_pci = &pci_dev_ops_pci, }; /** Default device operations for PCI bridges */ @@ -700,32 +710,29 @@ static struct pci_operations pci_bus_ops_pci = { }; struct device_operations default_pci_ops_bus = { - .read_resources = pci_bus_read_resources, - .set_resources = pci_dev_set_resources, + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, .enable_resources = pci_bus_enable_resources, - .init = 0, - .scan_bus = pci_scan_bridge, - .enable = 0, - .reset_bus = pci_bus_reset, - .ops_pci = &pci_bus_ops_pci, + .init = 0, + .scan_bus = pci_scan_bridge, + .enable = 0, + .reset_bus = pci_bus_reset, + .ops_pci = &pci_bus_ops_pci, }; /** * @brief Detect the type of downstream bridge * - * This function is a heuristic to detect which type - * of bus is downstream of a pci to pci bridge. This - * functions by looking for various capability blocks - * to figure out the type of downstream bridge. PCI-X - * PCI-E, and Hypertransport all seem to have appropriate - * capabilities. + * This function is a heuristic to detect which type of bus is downstream + * of a PCI-to-PCI bridge. This functions by looking for various capability + * blocks to figure out the type of downstream bridge. PCI-X, PCI-E, and + * Hypertransport all seem to have appropriate capabilities. * * When only a PCI-Express capability is found the type * is examined to see which type of bridge we have. * - * @param dev - * - * @return appropriate bridge operations + * @param dev Pointer to the device structure of the bridge. + * @return Appropriate bridge operations. */ static struct device_operations *get_pci_bridge_ops(device_t dev) { @@ -743,13 +750,13 @@ static struct device_operations *get_pci_bridge_ops(device_t dev) #endif #if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT == 1 pos = 0; - while((pos = pci_find_next_capability(dev, PCI_CAP_ID_HT, pos))) { + while ((pos = pci_find_next_capability(dev, PCI_CAP_ID_HT, pos))) { unsigned flags; flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); if ((flags >> 13) == 1) { /* Host or Secondary Interface */ printk_debug("%s subbordinate bus Hypertransport\n", - dev_path(dev)); + dev_path(dev)); return &default_ht_ops_bus; } } @@ -759,16 +766,15 @@ static struct device_operations *get_pci_bridge_ops(device_t dev) if (pos) { unsigned flags; flags = pci_read_config16(dev, pos + PCI_EXP_FLAGS); - switch((flags & PCI_EXP_FLAGS_TYPE) >> 4) { + switch ((flags & PCI_EXP_FLAGS_TYPE) >> 4) { case PCI_EXP_TYPE_ROOT_PORT: case PCI_EXP_TYPE_UPSTREAM: case PCI_EXP_TYPE_DOWNSTREAM: printk_debug("%s subbordinate bus PCI Express\n", - dev_path(dev)); + dev_path(dev)); return &default_pciexp_ops_bus; case PCI_EXP_TYPE_PCI_BRIDGE: - printk_debug("%s subbordinate PCI\n", - dev_path(dev)); + printk_debug("%s subbordinate PCI\n", dev_path(dev)); return &default_pci_ops_bus; default: break; @@ -779,11 +785,10 @@ static struct device_operations *get_pci_bridge_ops(device_t dev) } /** - * @brief Set up PCI device operation - * - * - * @param dev + * Set up PCI device operation. Check if it already has a driver. If not, use + * find_device_operations, or set to a default based on type. * + * @param dev Pointer to the device whose pci_ops you want to set. * @see pci_drivers */ static void set_pci_ops(struct device *dev) @@ -794,23 +799,22 @@ static void set_pci_ops(struct device *dev) } /* Look through the list of setup drivers and find one for - * this pci device + * this PCI device. */ - for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) { + for (driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) { if ((driver->vendor == dev->vendor) && - (driver->device == dev->device)) - { + (driver->device == dev->device)) { dev->ops = driver->ops; printk_spew("%s [%04x/%04x] %sops\n", - dev_path(dev), - driver->vendor, driver->device, - (driver->ops->scan_bus?"bus ":"")); + dev_path(dev), + driver->vendor, driver->device, + (driver->ops->scan_bus ? "bus " : "")); return; } } /* If I don't have a specific driver use the default operations */ - switch(dev->hdr_type & 0x7f) { /* header type */ + switch (dev->hdr_type & 0x7f) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) goto bad; @@ -827,20 +831,18 @@ static void set_pci_ops(struct device *dev) break; #endif default: - bad: + bad: if (dev->enabled) { printk_err("%s [%04x/%04x/%06x] has unknown header " - "type %02x, ignoring.\n", - dev_path(dev), - dev->vendor, dev->device, - dev->class >> 8, dev->hdr_type); + "type %02x, ignoring.\n", + dev_path(dev), + dev->vendor, dev->device, + dev->class >> 8, dev->hdr_type); } } return; } - - /** * @brief See if we have already allocated a device structure for a given devfn. * @@ -848,42 +850,43 @@ static void set_pci_ops(struct device *dev) * device structure correspond to the devfn, if present. This function also * removes the device structure from the linked list. * - * @param list the device structure list - * @param devfn a device/function number + * @param list The device structure list. + * @param devfn A device/function number. * - * @return pointer to the device structure found or null of we have not + * @return Pointer to the device structure found or NULL if we have not * allocated a device for this devfn yet. */ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) { struct device *dev; dev = 0; - for(; *list; list = &(*list)->sibling) { + for (; *list; list = &(*list)->sibling) { if ((*list)->path.type != DEVICE_PATH_PCI) { printk_err("child %s not a pci device\n", - dev_path(*list)); + dev_path(*list)); continue; } if ((*list)->path.pci.devfn == devfn) { - /* Unlink from the list */ + /* Unlink from the list. */ dev = *list; *list = (*list)->sibling; - dev->sibling = 0; + dev->sibling = NULL; break; } } - /* Just like alloc_dev add the device to the list of device on the bus. - * When the list of devices was formed we removed all of the parents - * children, and now we are interleaving static and dynamic devices in - * order on the bus. + + /* Just like alloc_dev() add the device to the list of devices on the + * bus. When the list of devices was formed we removed all of the + * parents children, and now we are interleaving static and dynamic + * devices in order on the bus. */ if (dev) { - device_t child; - /* Find the last child of our parent */ - for(child = dev->bus->children; child && child->sibling; ) { + struct device *child; + /* Find the last child of our parent. */ + for (child = dev->bus->children; child && child->sibling;) { child = child->sibling; } - /* Place the device on the list of children of it's parent. */ + /* Place the device on the list of children of its parent. */ if (child) { child->sibling = dev; } else { @@ -897,7 +900,8 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) /** * @brief Scan a PCI bus. * - * Determine the existence of a given PCI device. + * Determine the existence of a given PCI device. Allocate a new struct device + * if dev==NULL was passed in and the device exists in hardware. * * @param bus pointer to the bus structure * @param devfn to look at @@ -905,107 +909,94 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) * @return The device structure for hte device (if found) * or the NULL if no device is found. */ -device_t pci_probe_dev(device_t dev, struct bus *bus, unsigned devfn) +device_t pci_probe_dev(device_t dev, struct bus * bus, unsigned devfn) { - uint32_t id, class; - uint8_t hdr_type; + u32 id, class; + u8 hdr_type; - /* Detect if a device is present */ + /* Detect if a device is present. */ if (!dev) { struct device dummy; - dummy.bus = bus; - dummy.path.type = DEVICE_PATH_PCI; + dummy.bus = bus; + dummy.path.type = DEVICE_PATH_PCI; dummy.path.pci.devfn = devfn; id = pci_read_config32(&dummy, PCI_VENDOR_ID); - /* Have we found somthing? + /* Have we found something? * Some broken boards return 0 if a slot is empty. */ - if ( (id == 0xffffffff) || (id == 0x00000000) || - (id == 0x0000ffff) || (id == 0xffff0000)) - { + if ((id == 0xffffffff) || (id == 0x00000000) || + (id == 0x0000ffff) || (id == 0xffff0000)) { printk_spew("%s, bad id 0x%x\n", dev_path(&dummy), id); return NULL; } dev = alloc_dev(bus, &dummy.path); - } - else { - /* Enable/disable the device. Once we have - * found the device specific operations this - * operations we will disable the device with - * those as well. + } else { + /* Enable/disable the device. Once we have found the device- + * specific operations this operations we will disable the + * device with those as well. * * This is geared toward devices that have subfunctions * that do not show up by default. * * If a device is a stuff option on the motherboard - * it may be absent and enable_dev must cope. - * + * it may be absent and enable_dev() must cope. */ - /* Run the magice enable sequence for the device */ + /* Run the magic enable sequence for the device. */ if (dev->chip_ops && dev->chip_ops->enable_dev) { dev->chip_ops->enable_dev(dev); } - /* Now read the vendor and device id */ + /* Now read the vendor and device ID. */ id = pci_read_config32(dev, PCI_VENDOR_ID); - - /* If the device does not have a pci id disable it. - * Possibly this is because we have already disabled - * the device. But this also handles optional devices - * that may not always show up. + /* If the device does not have a PCI ID disable it. Possibly + * this is because we have already disabled the device. But + * this also handles optional devices that may not always + * show up. */ /* If the chain is fully enumerated quit */ - if ( (id == 0xffffffff) || (id == 0x00000000) || - (id == 0x0000ffff) || (id == 0xffff0000)) - { + if ((id == 0xffffffff) || (id == 0x00000000) || + (id == 0x0000ffff) || (id == 0xffff0000)) { if (dev->enabled) { printk_info("Disabling static device: %s\n", - dev_path(dev)); + dev_path(dev)); dev->enabled = 0; } return dev; } } - /* Read the rest of the pci configuration information */ + /* Read the rest of the PCI configuration information. */ hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); class = pci_read_config32(dev, PCI_CLASS_REVISION); - /* Store the interesting information in the device structure */ + /* Store the interesting information in the device structure. */ dev->vendor = id & 0xffff; dev->device = (id >> 16) & 0xffff; dev->hdr_type = hdr_type; - /* class code, the upper 3 bytes of PCI_CLASS_REVISION */ - dev->class = class >> 8; + /* Class code, the upper 3 bytes of PCI_CLASS_REVISION. */ + dev->class = class >> 8; - /* Architectural/System devices always need to - * be bus masters. - */ + /* Architectural/System devices always need to be bus masters. */ if ((dev->class >> 16) == PCI_BASE_CLASS_SYSTEM) { dev->command |= PCI_COMMAND_MASTER; } - /* Look at the vendor and device id, or at least the - * header type and class and figure out which set of - * configuration methods to use. Unless we already - * have some pci ops. + /* Look at the vendor and device ID, or at least the header type and + * class and figure out which set of configuration methods to use. + * Unless we already have some PCI ops. */ set_pci_ops(dev); - /* Now run the magic enable/disable sequence for the device */ + /* Now run the magic enable/disable sequence for the device. */ if (dev->ops && dev->ops->enable) { dev->ops->enable(dev); } - - /* Display the device and error if we don't have some pci operations - * for it. - */ + /* Display the device. */ printk_debug("%s [%04x/%04x] %s%s\n", - dev_path(dev), - dev->vendor, dev->device, - dev->enabled?"enabled": "disabled", - dev->ops?"" : " No operations" - ); + dev_path(dev), + dev->vendor, dev->device, + dev->enabled ? "enabled" : "disabled", + dev->ops ? "" : " No operations"); return dev; } @@ -1027,73 +1018,69 @@ device_t pci_probe_dev(device_t dev, struct bus *bus, unsigned devfn) * @return The maximum bus number found, after scanning all subordinate busses */ unsigned int pci_scan_bus(struct bus *bus, - unsigned min_devfn, unsigned max_devfn, - unsigned int max) + unsigned min_devfn, unsigned max_devfn, + unsigned int max) { unsigned int devfn; - device_t old_devices; - device_t child; + struct device *old_devices; + struct device *child; #if CONFIG_PCI_BUS_SEGN_BITS - printk_debug("PCI: pci_scan_bus for bus %04x:%02x\n", bus->secondary >> 8, bus->secondary & 0xff); + printk_debug("PCI: pci_scan_bus for bus %04x:%02x\n", + bus->secondary >> 8, bus->secondary & 0xff); #else printk_debug("PCI: pci_scan_bus for bus %02x\n", bus->secondary); #endif old_devices = bus->children; - bus->children = 0; + bus->children = NULL; post_code(0x24); - /* probe all devices/functions on this bus with some optimization for - * non-existence and single funcion devices + /* Probe all devices/functions on this bus with some optimization for + * non-existence and single function devices. */ for (devfn = min_devfn; devfn <= max_devfn; devfn++) { - device_t dev; + struct device *dev; /* First thing setup the device structure */ dev = pci_scan_get_dev(&old_devices, devfn); - /* See if a device is present and setup the device - * structure. - */ + /* See if a device is present and setup the device structure. */ dev = pci_probe_dev(dev, bus, devfn); - /* if this is not a multi function device, - * or the device is not present don't waste - * time probing another function. + /* If this is not a multi function device, or the device is + * not present don't waste time probing another function. * Skip to next device. */ if ((PCI_FUNC(devfn) == 0x00) && - (!dev || (dev->enabled && ((dev->hdr_type & 0x80) != 0x80)))) - { + (!dev + || (dev->enabled && ((dev->hdr_type & 0x80) != 0x80)))) { devfn += 0x07; } } post_code(0x25); - /* Die if any left over static devices are are found. + /* Warn if any leftover static devices are are found. * There's probably a problem in the Config.lb. - */ - if(old_devices) { + */ + if (old_devices) { device_t left; - for(left = old_devices; left; left = left->sibling) { - printk_err("%s\n", dev_path(left)); + printk_warning("PCI: Left over static devices:\n"); + for (left = old_devices; left; left = left->sibling) { + printk_warning("%s\n", dev_path(left)); } - printk_warning("PCI: Left over static devices. Check your mainboard Config.lb\n"); + printk_warning("PCI: Check your mainboard Config.lb.\n"); } - /* For all children that implement scan_bus (i.e. bridges) + /* For all children that implement scan_bus() (i.e. bridges) * scan the bus behind that child. */ - for(child = bus->children; child; child = child->sibling) { + for (child = bus->children; child; child = child->sibling) { max = scan_bus(child, max); } - /* - * We've scanned the bus and so we know all about what's on - * the other side of any bridges that may be on this bus plus - * any devices. - * + /* We've scanned the bus and so we know all about what's on the other + * side of any bridges that may be on this bus plus any devices. * Return how far we've got finding sub-buses. */ printk_debug("PCI: pci_scan_bus returning with max=%03x\n", max); @@ -1101,7 +1088,6 @@ unsigned int pci_scan_bus(struct bus *bus, return max; } - /** * @brief Scan a PCI bridge and the buses behind the bridge. * @@ -1110,18 +1096,19 @@ unsigned int pci_scan_bus(struct bus *bus, * * This function is the default scan_bus() method for PCI bridge devices. * - * @param dev pointer to the bridge device - * @param max the highest bus number assgined up to now - * - * @return The maximum bus number found, after scanning all subordinate busses + * @param dev Pointer to the bridge device. + * @param max The highest bus number assigned up to now. + * @return The maximum bus number found, after scanning all subordinate buses. */ unsigned int do_pci_scan_bridge(struct device *dev, unsigned int max, - unsigned int (*do_scan_bus)(struct bus *bus, - unsigned min_devfn, unsigned max_devfn, unsigned int max)) + unsigned int (*do_scan_bus) (struct bus * bus, + unsigned min_devfn, + unsigned max_devfn, + unsigned int max)) { struct bus *bus; - uint32_t buses; - uint16_t cr; + u32 buses; + u16 cr; printk_spew("%s for %s\n", __func__, dev_path(dev)); @@ -1141,8 +1128,7 @@ unsigned int do_pci_scan_bridge(struct device *dev, unsigned int max, pci_write_config16(dev, PCI_COMMAND, 0x0000); pci_write_config16(dev, PCI_STATUS, 0xffff); - /* - * Read the existing primary/secondary/subordinate bus + /* Read the existing primary/secondary/subordinate bus * number configuration. */ buses = pci_read_config32(dev, PCI_PRIMARY_BUS); @@ -1152,9 +1138,9 @@ unsigned int do_pci_scan_bridge(struct device *dev, unsigned int max, * correctly configured. */ buses &= 0xff000000; - buses |= (((unsigned int) (dev->bus->secondary) << 0) | - ((unsigned int) (bus->secondary) << 8) | - ((unsigned int) (bus->subordinate) << 16)); + buses |= (((unsigned int)(dev->bus->secondary) << 0) | + ((unsigned int)(bus->secondary) << 8) | + ((unsigned int)(bus->subordinate) << 16)); pci_write_config32(dev, PCI_PRIMARY_BUS, buses); /* Now we can scan all subordinate buses @@ -1166,8 +1152,7 @@ unsigned int do_pci_scan_bridge(struct device *dev, unsigned int max, * bus number to its real value. */ bus->subordinate = max; - buses = (buses & 0xff00ffff) | - ((unsigned int) (bus->subordinate) << 16); + buses = (buses & 0xff00ffff) | ((unsigned int)(bus->subordinate) << 16); pci_write_config32(dev, PCI_PRIMARY_BUS, buses); pci_write_config16(dev, PCI_COMMAND, cr); @@ -1183,90 +1168,109 @@ unsigned int do_pci_scan_bridge(struct device *dev, unsigned int max, * * This function is the default scan_bus() method for PCI bridge devices. * - * @param dev pointer to the bridge device + * @param dev Pointer to the bridge device. + * @param max The highest bus number assigned up to now. + * @return The maximum bus number found, after scanning all subordinate buses. + */ +unsigned int pci_scan_bridge(struct device *dev, unsigned int max) +{ + return do_pci_scan_bridge(dev, max, pci_scan_bus); +} + +/** + * @brief Scan a PCI domain. + * + * This function is the default scan_bus() method for PCI domains. + * + * @param dev pointer to the domain * @param max the highest bus number assgined up to now * * @return The maximum bus number found, after scanning all subordinate busses */ -unsigned int pci_scan_bridge(struct device *dev, unsigned int max) +unsigned int pci_domain_scan_bus(device_t dev, unsigned int max) { - return do_pci_scan_bridge(dev, max, pci_scan_bus); + max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max); + return max; } -/* - Tell the EISA int controller this int must be level triggered - THIS IS A KLUDGE -- sorry, this needs to get cleaned up. -*/ +/** + * Tell the EISA int controller this int must be level triggered. + * + * THIS IS A KLUDGE -- sorry, this needs to get cleaned up. + */ void pci_level_irq(unsigned char intNum) { - unsigned short intBits = inb(0x4d0) | (((unsigned) inb(0x4d1)) << 8); + unsigned short intBits = inb(0x4d0) | (((unsigned)inb(0x4d1)) << 8); printk_spew("%s: current ints are 0x%x\n", __func__, intBits); intBits |= (1 << intNum); printk_spew("%s: try to set ints 0x%x\n", __func__, intBits); - // Write new values - outb((unsigned char) intBits, 0x4d0); - outb((unsigned char) (intBits >> 8), 0x4d1); + /* Write new values. */ + outb((unsigned char)intBits, 0x4d0); + outb((unsigned char)(intBits >> 8), 0x4d1); - /* this seems like an error but is not ... */ -#if 1 + /* This seems like an error but is not. */ if (inb(0x4d0) != (intBits & 0xff)) { - printk_err("%s: lower order bits are wrong: want 0x%x, got 0x%x\n", - __func__, intBits &0xff, inb(0x4d0)); + printk_err( + "%s: lower order bits are wrong: want 0x%x, got 0x%x\n", + __func__, intBits & 0xff, inb(0x4d0)); } if (inb(0x4d1) != ((intBits >> 8) & 0xff)) { - printk_err("%s: lower order bits are wrong: want 0x%x, got 0x%x\n", - __func__, (intBits>>8) &0xff, inb(0x4d1)); + printk_err( + "%s: lower order bits are wrong: want 0x%x, got 0x%x\n", + __func__, (intBits >> 8) & 0xff, inb(0x4d1)); } -#endif } -/* - This function assigns IRQs for all functions contained within - the indicated device address. If the device does not exist or does - not require interrupts then this function has no effect. - - This function should be called for each PCI slot in your system. - - pIntAtoD is an array of IRQ #s that are assigned to PINTA through PINTD of - this slot. - The particular irq #s that are passed in depend on the routing inside - your southbridge and on your motherboard. - - -kevinh@ispiri.com +/** + * This function assigns IRQs for all functions contained within the + * indicated device address. If the device does not exist or does not + * require interrupts then this function has no effect. + * + * This function should be called for each PCI slot in your system. + * + * pIntAtoD is an array of IRQ #s that are assigned to PINTA through PINTD of + * this slot. + * + * The particular irq #s that are passed in depend on the routing inside + * your southbridge and on your motherboard. + * + * -kevinh@ispiri.com + * */ void pci_assign_irqs(unsigned bus, unsigned slot, - const unsigned char pIntAtoD[4]) + const unsigned char pIntAtoD[4]) { unsigned functNum; - device_t pdev; + struct device *pdev; unsigned char line; unsigned char irq; unsigned char readback; - /* Each slot may contain up to eight functions */ + /* Each slot may contain up to eight functions. */ for (functNum = 0; functNum < 8; functNum++) { pdev = dev_find_slot(bus, (slot << 3) + functNum); if (pdev) { - line = pci_read_config8(pdev, PCI_INTERRUPT_PIN); + line = pci_read_config8(pdev, PCI_INTERRUPT_PIN); - // PCI spec says all other values are reserved + /* PCI spec says all other values are reserved. */ if ((line >= 1) && (line <= 4)) { irq = pIntAtoD[line - 1]; - printk_debug("Assigning IRQ %d to %d:%x.%d\n", \ - irq, bus, slot, functNum); + printk_debug("Assigning IRQ %d to %d:%x.%d\n", + irq, bus, slot, functNum); - pci_write_config8(pdev, PCI_INTERRUPT_LINE,\ - pIntAtoD[line - 1]); + pci_write_config8(pdev, PCI_INTERRUPT_LINE, + pIntAtoD[line - 1]); - readback = pci_read_config8(pdev, PCI_INTERRUPT_LINE); + readback = + pci_read_config8(pdev, PCI_INTERRUPT_LINE); printk_debug(" Readback = %d\n", readback); - // Change to level triggered + // Change to level triggered. pci_level_irq(pIntAtoD[line - 1]); } } diff --git a/src/devices/root_device.c b/src/devices/root_device.c index 9c5bf86..affb75b 100644 --- a/src/devices/root_device.c +++ b/src/devices/root_device.c @@ -34,29 +34,7 @@ */ void root_dev_read_resources(device_t root) { - struct resource *resource; - - /* Initialize the system wide io space constraints */ - resource = new_resource(root, 0); - resource->base = 0x400; - resource->size = 0; - resource->align = 0; - resource->gran = 0; - resource->limit = 0xffffUL; - resource->flags = IORESOURCE_IO; - compute_allocate_resource(&root->link[0], resource, - IORESOURCE_IO, IORESOURCE_IO); - - /* Initialize the system wide memory resources constraints */ - resource = new_resource(root, 1); - resource->base = 0; - resource->size = 0; - resource->align = 0; - resource->gran = 0; - resource->limit = 0xffffffffUL; - resource->flags = IORESOURCE_MEM; - compute_allocate_resource(&root->link[0], resource, - IORESOURCE_MEM, IORESOURCE_MEM); + printk_err("%s should never be called.\n", __func__); } /** @@ -68,14 +46,7 @@ void root_dev_read_resources(device_t root) */ void root_dev_set_resources(device_t root) { - struct bus *bus; - - bus = &root->link[0]; - compute_allocate_resource(bus, - &root->resource[0], IORESOURCE_IO, IORESOURCE_IO); - compute_allocate_resource(bus, - &root->resource[1], IORESOURCE_MEM, IORESOURCE_MEM); - assign_resources(bus); + printk_err("%s should never be called.\n", __func__); } /** |