Kyösti Mälkki (kyosti.malkki@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8892
-gerrit
commit a6bbd5f2e422816e6d740b34e6d336ac07dc0308 Author: Kyösti Mälkki kyosti.malkki@gmail.com Date: Thu Mar 26 23:27:54 2015 +0200
resource: Add prefetchable memory resource for PCI domain
With the change, prefetchable and non-prefetchable MMIO resources will no longer be interleaved for the domain, but one window will appear below the other in memory space.
There is no need to negotiate the resource limits via intermediate limits structure. Recursively walk the devicetree for each type of resource and apply the constraints directly on the domain path.
Change-ID: Ibf44deab0aed0a05759e78855e23146fc45cdc43 Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- src/device/device.c | 169 +++++++++++++----------------------------------- src/device/pci_device.c | 6 ++ 2 files changed, 50 insertions(+), 125 deletions(-)
diff --git a/src/device/device.c b/src/device/device.c index 72f2373..51cd4c6 100644 --- a/src/device/device.c +++ b/src/device/device.c @@ -278,10 +278,11 @@ static void pick_largest_resource(void *gp, struct device *dev,
static struct device *largest_resource(struct bus *bus, struct resource **result_res, - unsigned long type_mask, - unsigned long type) + struct resource *bridge) { struct pick_largest_state state; + u32 type_mask = (IORESOURCE_TYPE_MASK | IORESOURCE_PREFETCH); + u32 type = bridge->flags & type_mask;
state.last = *result_res; state.result_dev = NULL; @@ -295,6 +296,20 @@ static struct device *largest_resource(struct bus *bus, return state.result_dev; }
+static int resource_match(struct resource *res, struct resource *lim) +{ + return (res->flags & IORESOURCE_TYPE_MASK) == + (lim->flags & IORESOURCE_TYPE_MASK); +} + +static int resource_match_bridge(struct resource *res, struct resource *win) +{ + u32 type_mask = (IORESOURCE_TYPE_MASK | IORESOURCE_PREFETCH); + if (!(res->flags & IORESOURCE_BRIDGE)) + return 0; + return (res->flags & type_mask) == (win->flags & type_mask); +} + /** * This function is the guts of the resource allocator. * @@ -324,12 +339,8 @@ static struct device *largest_resource(struct bus *bus, * * @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. - * @return TODO */ -static void compute_resources(struct bus *bus, struct resource *bridge, - unsigned long type_mask, unsigned long type) +static void compute_resources(struct bus *bus, struct resource *bridge) { struct device *dev; struct resource *resource; @@ -353,17 +364,9 @@ static void compute_resources(struct bus *bus, struct resource *bridge, child_bridge = child_bridge->next) { struct bus* link;
- if (!(child_bridge->flags & IORESOURCE_BRIDGE) - || (child_bridge->flags & type_mask) != type) + if (!resource_match_bridge(child_bridge, bridge)) 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 = dev->link_list; while (link && link->link_num != IOINDEX_LINK(child_bridge->index)) @@ -375,10 +378,7 @@ static void compute_resources(struct bus *bus, struct resource *bridge, dev_path(dev)); }
- compute_resources(link, child_bridge, - type_mask | IORESOURCE_PREFETCH, - type | (child_bridge->flags & - IORESOURCE_PREFETCH)); + compute_resources(link, child_bridge); } }
@@ -390,7 +390,7 @@ static void compute_resources(struct bus *bus, struct resource *bridge, * amount of address space taken by them. Take granularity and * alignment into account. */ - while ((dev = largest_resource(bus, &resource, type_mask, type))) { + while ((dev = largest_resource(bus, &resource, bridge))) {
/* Size 0 resources can be skipped. */ if (!resource->size) @@ -467,13 +467,10 @@ static void compute_resources(struct bus *bus, struct resource *bridge, * * @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. * * @see compute_resources */ -static void allocate_resources(struct bus *bus, struct resource *bridge, - unsigned long type_mask, unsigned long type) +static void allocate_resources(struct bus *bus, struct resource *bridge) { struct device *dev; struct resource *resource; @@ -492,7 +489,7 @@ static void allocate_resources(struct bus *bus, struct resource *bridge, * Walk through all the resources on the current bus and allocate them * address space. */ - while ((dev = largest_resource(bus, &resource, type_mask, type))) { + while ((dev = largest_resource(bus, &resource, bridge))) {
/* Propagate the bridge limit to the resource register. */ if (resource->limit > bridge->limit) @@ -583,17 +580,9 @@ static void allocate_resources(struct bus *bus, struct resource *bridge, child_bridge = child_bridge->next) { struct bus* link;
- if (!(child_bridge->flags & IORESOURCE_BRIDGE) || - (child_bridge->flags & type_mask) != type) + if (!resource_match_bridge(child_bridge, bridge)) 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 = dev->link_list; while (link && link->link_num != IOINDEX_LINK(child_bridge->index)) @@ -603,47 +592,25 @@ static void allocate_resources(struct bus *bus, struct resource *bridge, IOINDEX_LINK(child_bridge->index), dev_path(dev));
- allocate_resources(link, child_bridge, - type_mask | IORESOURCE_PREFETCH, - type | (child_bridge->flags & - IORESOURCE_PREFETCH)); + allocate_resources(link, child_bridge); } } }
-static int resource_is(struct resource *res, u32 type) -{ - return (res->flags & IORESOURCE_TYPE_MASK) == type; -} - -struct constraints { - struct resource io, mem; -}; - -static struct resource * resource_limit(struct constraints *limits, struct resource *res) -{ - struct resource *lim = NULL; - - /* MEM, or I/O - skip any others. */ - if (resource_is(res, IORESOURCE_MEM)) - lim = &limits->mem; - else if (resource_is(res, IORESOURCE_IO)) - lim = &limits->io; - - return lim; -} - -static void constrain_resources(struct device *dev, struct constraints* limits) +static void constrain_resources(struct device *dev, struct resource *lim) { struct device *child; struct resource *res; - struct resource *lim; struct bus *link;
/* Constrain limits based on the fixed resources of this device. */ for (res = dev->resource_list; res; res = res->next) { if (!(res->flags & IORESOURCE_FIXED)) continue; + + if (!resource_match(res, lim)) + continue; + if (!res->size) { /* It makes no sense to have 0-sized, fixed resources.*/ printk(BIOS_ERR, "skipping %s@%lx fixed resource, " @@ -651,10 +618,6 @@ static void constrain_resources(struct device *dev, struct constraints* limits) continue; }
- lim = resource_limit(limits, res); - if (!lim) - continue; - /* * Is it a fixed resource outside the current known region? * If so, we don't have to consider it - it will be handled @@ -684,63 +647,35 @@ static void constrain_resources(struct device *dev, struct constraints* limits) for (link = dev->link_list; link; link = link->next) { for (child = link->children; child; child = child->sibling) { if (child->enabled) - constrain_resources(child, limits); + constrain_resources(child, lim); } } }
static void avoid_fixed_resources(struct device *dev) { - struct constraints limits; struct resource *res; - struct resource *lim; + resource_t mem_limit = 0xffffffffULL;
printk(BIOS_SPEW, "%s: %s\n", __func__, dev_path(dev));
- /* Initialize constraints to maximum size. */ - 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 (res = dev->resource_list; res; res = res->next) { if ((res->flags & IORESOURCE_FIXED)) continue; - printk(BIOS_SPEW, "%s:@%s %02lx limit %08llx\n", __func__, - dev_path(dev), res->index, res->limit); - - lim = resource_limit(&limits, res); - if (!lim) - continue; - - if (res->base > lim->base) - lim->base = res->base; - if (res->limit < lim->limit) - lim->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 (res = dev->resource_list; res; res = res->next) { - if ((res->flags & IORESOURCE_FIXED)) - continue;
- lim = resource_limit(&limits, res); - if (!lim) - continue; + /* Place MEM resources one after other. */ + if ((res->flags & IORESOURCE_MEM) && (res->limit > mem_limit)) + res->limit = mem_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; + /* Look through the tree for fixed resources and update the limits. */ + constrain_resources(dev, res);
/* MEM resources need to start at the highest address manageable. */ - if (res->flags & IORESOURCE_MEM) + if (res->flags & IORESOURCE_MEM) { res->base = resource_max(res); + mem_limit = res->base - 1; + }
printk(BIOS_SPEW, "%s:@%s %02lx base %08llx limit %08llx\n", __func__, dev_path(dev), res->index, res->base, res->limit); @@ -1030,16 +965,8 @@ void dev_configure(void) for (res = child->resource_list; res; res = res->next) { if (res->flags & IORESOURCE_FIXED) continue; - if (res->flags & IORESOURCE_MEM) { - compute_resources(child->link_list, - res, IORESOURCE_TYPE_MASK, IORESOURCE_MEM); - continue; - } - if (res->flags & IORESOURCE_IO) { - compute_resources(child->link_list, - res, IORESOURCE_TYPE_MASK, IORESOURCE_IO); - continue; - } + + compute_resources(child->link_list, res); } }
@@ -1057,16 +984,8 @@ void dev_configure(void) for (res = child->resource_list; res; res = res->next) { if (res->flags & IORESOURCE_FIXED) continue; - if (res->flags & IORESOURCE_MEM) { - allocate_resources(child->link_list, - res, IORESOURCE_TYPE_MASK, IORESOURCE_MEM); - continue; - } - if (res->flags & IORESOURCE_IO) { - allocate_resources(child->link_list, - res, IORESOURCE_TYPE_MASK, IORESOURCE_IO); - continue; - } + + allocate_resources(child->link_list, res); } } assign_resources(root->link_list); diff --git a/src/device/pci_device.c b/src/device/pci_device.c index 4651258..c8e6692 100644 --- a/src/device/pci_device.c +++ b/src/device/pci_device.c @@ -447,6 +447,12 @@ void pci_domain_read_resources(struct device *dev) res->limit = 0xffffffffULL; res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + /* Initialize the system-wide memory resources constraints. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(2, 0)); + res->limit = 0xffffffffULL; + res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED; }
static void pci_set_resource(struct device *dev, struct resource *resource)