diff options
-rw-r--r-- | src/device/resource_allocator_v4.c | 133 |
1 files changed, 69 insertions, 64 deletions
diff --git a/src/device/resource_allocator_v4.c b/src/device/resource_allocator_v4.c index 511c4505db..2f4ea124f8 100644 --- a/src/device/resource_allocator_v4.c +++ b/src/device/resource_allocator_v4.c @@ -215,14 +215,14 @@ static void compute_domain_resources(const struct device *domain) } } -static unsigned char get_alignment_by_resource_type(const struct resource *res) +static unsigned char get_alignment_by_resource_type(const unsigned long type) { - if (res->flags & IORESOURCE_MEM) + if (type & IORESOURCE_MEM) return 12; /* Page-aligned --> log2(4KiB) */ - else if (res->flags & IORESOURCE_IO) + else if (type & IORESOURCE_IO) return 0; /* No special alignment required --> log2(1) */ - die("Unexpected resource type: flags(%lu)!\n", res->flags); + die("Unexpected resource type: flags(%lu)!\n", type); } /* @@ -303,20 +303,31 @@ static void initialize_domain_mem_resource_memranges(struct memranges *ranges, * satisfy resource requests from downstream devices for allocations * above 4G. */ -static void initialize_domain_memranges(struct memranges *ranges, const struct resource *res, +static void initialize_domain_memranges(const struct device *dev, struct memranges *ranges, unsigned long memrange_type) { - unsigned char align = get_alignment_by_resource_type(res); + unsigned char align = get_alignment_by_resource_type(memrange_type); memranges_init_empty_with_alignment(ranges, NULL, 0, align); - if (is_resource_invalid(res)) - return; + struct resource *res; + for (res = dev->resource_list; res != NULL; res = res->next) { + if (is_resource_invalid(res)) + continue; + if (res->flags & IORESOURCE_FIXED) + continue; + if ((res->flags & IORESOURCE_TYPE_MASK) != memrange_type) + continue; - if (res->flags & IORESOURCE_IO) - initialize_domain_io_resource_memranges(ranges, res, memrange_type); - else - initialize_domain_mem_resource_memranges(ranges, res, memrange_type); + printk(BIOS_DEBUG, "%s %s: base: %llx size: %llx align: %d gran: %d limit: %llx\n", + dev_path(dev), resource2str(res), res->base, res->size, res->align, + res->gran, res->limit); + + if (res->flags & IORESOURCE_IO) + initialize_domain_io_resource_memranges(ranges, res, memrange_type); + else + initialize_domain_mem_resource_memranges(ranges, res, memrange_type); + } } /* @@ -335,15 +346,22 @@ static void initialize_domain_memranges(struct memranges *ranges, const struct r * downstream resources of the same type under the bridge get allocated * above 4G. */ -static void initialize_bridge_memranges(struct memranges *ranges, const struct resource *res, +static void initialize_bridge_memranges(const struct device *dev, struct memranges *ranges, unsigned long memrange_type) { - unsigned char align = get_alignment_by_resource_type(res); + unsigned char align = get_alignment_by_resource_type(memrange_type); memranges_init_empty_with_alignment(ranges, NULL, 0, align); - if (is_resource_invalid(res)) - return; + struct resource *res; + for (res = dev->resource_list; res != NULL; res = res->next) { + if (is_resource_invalid(res)) + continue; + if (res->flags & IORESOURCE_FIXED) + continue; + if ((res->flags & (IORESOURCE_TYPE_MASK | IORESOURCE_PREFETCH)) == memrange_type) + break; + } memranges_insert(ranges, res->base, res->limit - res->base + 1, memrange_type); } @@ -485,32 +503,41 @@ static void constrain_domain_resources(const struct device *domain, struct memra * windows which cannot be used for resource allocation as fixed * resources. */ -static void setup_resource_ranges(const struct device *dev, const struct resource *res, - unsigned long type, struct memranges *ranges) +static void setup_resource_ranges(const struct device *dev, unsigned long type, + struct memranges *ranges) { - printk(BIOS_DEBUG, "%s %s: base: %llx size: %llx align: %d gran: %d limit: %llx\n", - dev_path(dev), resource2str(res), res->base, res->size, res->align, - res->gran, res->limit); - if (dev->path.type == DEVICE_PATH_DOMAIN) { - initialize_domain_memranges(ranges, res, type); + initialize_domain_memranges(dev, ranges, type); constrain_domain_resources(dev, ranges, type); } else { - initialize_bridge_memranges(ranges, res, type); + initialize_bridge_memranges(dev, ranges, type); } print_resource_ranges(dev, ranges); } -static void cleanup_resource_ranges(const struct device *dev, struct memranges *ranges, - const struct resource *res) +static void print_resource_done(const struct device *dev, const struct resource *res) { - memranges_teardown(ranges); printk(BIOS_DEBUG, "%s %s: base: %llx size: %llx align: %d gran: %d limit: %llx done\n", dev_path(dev), resource2str(res), res->base, res->size, res->align, res->gran, res->limit); } +static void cleanup_domain_resource_ranges(const struct device *dev, struct memranges *ranges, + unsigned long type) +{ + memranges_teardown(ranges); + for (struct resource *res = dev->resource_list; res != NULL; res = res->next) { + if (is_resource_invalid(res)) + continue; + if (res->flags & IORESOURCE_FIXED) + continue; + if ((res->flags & IORESOURCE_TYPE_MASK) != type) + continue; + print_resource_done(dev, res); + } +} + /* * Pass 2 of the resource allocator at the bridge level loops through * all the resources for the bridge and generates a list of memory @@ -547,9 +574,10 @@ static void allocate_bridge_resources(const struct device *bridge) type_match = res->flags & type_mask; - setup_resource_ranges(bridge, res, type_match, &ranges); + setup_resource_ranges(bridge, type_match, &ranges); allocate_child_resources(bus, &ranges, type_mask, type_match); - cleanup_resource_ranges(bridge, &ranges, res); + print_resource_done(bridge, res); + memranges_teardown(&ranges); } for (child = bus->children; child; child = child->sibling) { @@ -560,22 +588,6 @@ static void allocate_bridge_resources(const struct device *bridge) } } -static const struct resource *find_domain_resource(const struct device *domain, - unsigned long type) -{ - const struct resource *res; - - for (res = domain->resource_list; res; res = res->next) { - if (res->flags & IORESOURCE_FIXED) - continue; - - if ((res->flags & IORESOURCE_TYPE_MASK) == type) - return res; - } - - return NULL; -} - /* * Pass 2 of resource allocator begins at the domain level. Every domain * has two types of resources - io and mem. For each of these resources, @@ -593,16 +605,12 @@ static void allocate_domain_resources(const struct device *domain) { struct memranges ranges; struct device *child; - const struct resource *res; /* Resource type I/O */ - res = find_domain_resource(domain, IORESOURCE_IO); - if (res) { - setup_resource_ranges(domain, res, IORESOURCE_IO, &ranges); - allocate_child_resources(domain->link_list, &ranges, IORESOURCE_TYPE_MASK, - IORESOURCE_IO); - cleanup_resource_ranges(domain, &ranges, res); - } + setup_resource_ranges(domain, IORESOURCE_IO, &ranges); + allocate_child_resources(domain->link_list, &ranges, IORESOURCE_TYPE_MASK, + IORESOURCE_IO); + cleanup_domain_resource_ranges(domain, &ranges, IORESOURCE_IO); /* * Resource type Mem: @@ -621,17 +629,14 @@ static void allocate_domain_resources(const struct device *domain) * the 4G boundary are handled separately by setting the type_mask and * type_match to allocate_child_resources() accordingly. */ - res = find_domain_resource(domain, IORESOURCE_MEM); - if (res) { - setup_resource_ranges(domain, res, IORESOURCE_MEM, &ranges); - allocate_child_resources(domain->link_list, &ranges, - IORESOURCE_TYPE_MASK | IORESOURCE_ABOVE_4G, - IORESOURCE_MEM); - allocate_child_resources(domain->link_list, &ranges, - IORESOURCE_TYPE_MASK | IORESOURCE_ABOVE_4G, - IORESOURCE_MEM | IORESOURCE_ABOVE_4G); - cleanup_resource_ranges(domain, &ranges, res); - } + setup_resource_ranges(domain, IORESOURCE_MEM, &ranges); + allocate_child_resources(domain->link_list, &ranges, + IORESOURCE_TYPE_MASK | IORESOURCE_ABOVE_4G, + IORESOURCE_MEM); + allocate_child_resources(domain->link_list, &ranges, + IORESOURCE_TYPE_MASK | IORESOURCE_ABOVE_4G, + IORESOURCE_MEM | IORESOURCE_ABOVE_4G); + cleanup_domain_resource_ranges(domain, &ranges, IORESOURCE_MEM); for (child = domain->link_list->children; child; child = child->sibling) { if (!dev_has_children(child)) |