device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
|
|
|
|
#include <console/console.h>
|
|
|
|
#include <device/device.h>
|
|
|
|
#include <memrange.h>
|
|
|
|
#include <post.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Round a number up to an alignment.
|
|
|
|
*
|
|
|
|
* @param val The starting value.
|
|
|
|
* @param pow Alignment as a power of two.
|
|
|
|
* @return Rounded up number.
|
|
|
|
*/
|
|
|
|
static resource_t round(resource_t val, unsigned long pow)
|
|
|
|
{
|
|
|
|
return ALIGN_UP(val, POWER_OF_2(pow));
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *resource2str(const struct resource *res)
|
|
|
|
{
|
|
|
|
if (res->flags & IORESOURCE_IO)
|
|
|
|
return "io";
|
|
|
|
if (res->flags & IORESOURCE_PREFETCH)
|
|
|
|
return "prefmem";
|
|
|
|
if (res->flags & IORESOURCE_MEM)
|
|
|
|
return "mem";
|
|
|
|
return "undefined";
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool dev_has_children(const struct device *dev)
|
|
|
|
{
|
|
|
|
const struct bus *bus = dev->link_list;
|
|
|
|
return bus && bus->children;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* During pass 1, once all the requirements for downstream devices of a bridge are gathered,
|
|
|
|
* this function calculates the overall resource requirement for the bridge. It starts by
|
|
|
|
* picking the largest resource requirement downstream for the given resource type and works by
|
|
|
|
* adding requirements in descending order.
|
|
|
|
*
|
|
|
|
* Additionally, it takes alignment and limits of the downstream devices into consideration and
|
|
|
|
* ensures that they get propagated to the bridge resource. This is required to guarantee that
|
|
|
|
* the upstream bridge/domain honors the limit and alignment requirements for this bridge based
|
|
|
|
* on the tightest constraints downstream.
|
|
|
|
*/
|
|
|
|
static void update_bridge_resource(const struct device *bridge, struct resource *bridge_res,
|
|
|
|
unsigned long type_match)
|
|
|
|
{
|
|
|
|
const struct device *child;
|
|
|
|
struct resource *child_res;
|
|
|
|
resource_t base;
|
|
|
|
bool first_child_res = true;
|
|
|
|
const unsigned long type_mask = IORESOURCE_TYPE_MASK | IORESOURCE_PREFETCH;
|
|
|
|
struct bus *bus = bridge->link_list;
|
|
|
|
|
|
|
|
child_res = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* `base` keeps track of where the next allocation for child resource can take place
|
|
|
|
* from within the bridge resource window. Since the bridge resource window allocation
|
|
|
|
* is not performed yet, it can start at 0. Base gets updated every time a resource
|
|
|
|
* requirement is accounted for in the loop below. After scanning all these resources,
|
|
|
|
* base will indicate the total size requirement for the current bridge resource
|
|
|
|
* window.
|
|
|
|
*/
|
|
|
|
base = 0;
|
|
|
|
|
|
|
|
printk(BIOS_SPEW, "%s %s: size: %llx align: %d gran: %d limit: %llx\n",
|
|
|
|
dev_path(bridge), resource2str(bridge_res), bridge_res->size,
|
|
|
|
bridge_res->align, bridge_res->gran, bridge_res->limit);
|
|
|
|
|
|
|
|
while ((child = largest_resource(bus, &child_res, type_mask, type_match))) {
|
|
|
|
|
|
|
|
/* Size 0 resources can be skipped. */
|
|
|
|
if (!child_res->size)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Propagate the resource alignment to the bridge resource if this is the first
|
|
|
|
* child resource with non-zero size being considered. For all other children
|
|
|
|
* resources, alignment is taken care of by updating the base to round up as per
|
|
|
|
* the child resource alignment. It is guaranteed that pass 2 follows the exact
|
|
|
|
* same method of picking the resource for allocation using
|
|
|
|
* largest_resource(). Thus, as long as the alignment for first child resource
|
|
|
|
* is propagated up to the bridge resource, it can be guaranteed that the
|
|
|
|
* alignment for all resources is appropriately met.
|
|
|
|
*/
|
|
|
|
if (first_child_res && (child_res->align > bridge_res->align))
|
|
|
|
bridge_res->align = child_res->align;
|
|
|
|
|
|
|
|
first_child_res = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Propagate the resource limit to the bridge resource only if child resource
|
|
|
|
* limit is non-zero. If a downstream device has stricter requirements
|
|
|
|
* w.r.t. limits for any resource, that constraint needs to be propagated back
|
|
|
|
* up to the downstream bridges of the domain. This guarantees that the resource
|
|
|
|
* allocation which starts at the domain level takes into account all these
|
|
|
|
* constraints thus working on a global view.
|
|
|
|
*/
|
|
|
|
if (child_res->limit && (child_res->limit < bridge_res->limit))
|
|
|
|
bridge_res->limit = child_res->limit;
|
|
|
|
|
2020-05-16 02:33:52 +02:00
|
|
|
/*
|
|
|
|
* Propagate the downstream resource request to allocate above 4G boundary to
|
|
|
|
* upstream bridge resource. This ensures that during pass 2, the resource
|
|
|
|
* allocator at domain level has a global view of all the downstream device
|
|
|
|
* requirements and thus address space is allocated as per updated flags in the
|
|
|
|
* bridge resource.
|
|
|
|
*
|
|
|
|
* Since the bridge resource is a single window, all the downstream resources of
|
|
|
|
* this bridge resource will be allocated space above 4G boundary.
|
|
|
|
*/
|
|
|
|
if (child_res->flags & IORESOURCE_ABOVE_4G)
|
|
|
|
bridge_res->flags |= IORESOURCE_ABOVE_4G;
|
|
|
|
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
/*
|
|
|
|
* Alignment value of 0 means that the child resource has no alignment
|
|
|
|
* requirements and so the base value remains unchanged here.
|
|
|
|
*/
|
|
|
|
base = round(base, child_res->align);
|
|
|
|
|
|
|
|
printk(BIOS_SPEW, "%s %02lx * [0x%llx - 0x%llx] %s\n",
|
|
|
|
dev_path(child), child_res->index, base, base + child_res->size - 1,
|
|
|
|
resource2str(child_res));
|
|
|
|
|
|
|
|
base += child_res->size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* After all downstream device resources are scanned, `base` represents the total size
|
|
|
|
* requirement for the current bridge resource window. This size needs to be rounded up
|
|
|
|
* to the granularity requirement of the bridge to ensure that the upstream
|
|
|
|
* bridge/domain allocates big enough window.
|
|
|
|
*/
|
|
|
|
bridge_res->size = round(base, bridge_res->gran);
|
|
|
|
|
|
|
|
printk(BIOS_SPEW, "%s %s: size: %llx align: %d gran: %d limit: %llx done\n",
|
|
|
|
dev_path(bridge), resource2str(bridge_res), bridge_res->size,
|
|
|
|
bridge_res->align, bridge_res->gran, bridge_res->limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* During pass 1, resource allocator at bridge level gathers requirements from downstream
|
|
|
|
* devices and updates its own resource windows for the provided resource type.
|
|
|
|
*/
|
|
|
|
static void compute_bridge_resources(const struct device *bridge, unsigned long type_match)
|
|
|
|
{
|
|
|
|
const struct device *child;
|
|
|
|
struct resource *res;
|
|
|
|
struct bus *bus = bridge->link_list;
|
|
|
|
const unsigned long type_mask = IORESOURCE_TYPE_MASK | IORESOURCE_PREFETCH;
|
|
|
|
|
|
|
|
for (res = bridge->resource_list; res; res = res->next) {
|
|
|
|
if (!(res->flags & IORESOURCE_BRIDGE))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((res->flags & type_mask) != type_match)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure that the resource requirements for all downstream bridges are
|
|
|
|
* gathered before updating the window for current bridge resource.
|
|
|
|
*/
|
|
|
|
for (child = bus->children; child; child = child->sibling) {
|
|
|
|
if (!dev_has_children(child))
|
|
|
|
continue;
|
|
|
|
compute_bridge_resources(child, type_match);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update the window for current bridge resource now that all downstream
|
|
|
|
* requirements are gathered.
|
|
|
|
*/
|
|
|
|
update_bridge_resource(bridge, res, type_match);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* During pass 1, resource allocator walks down the entire sub-tree of a domain. It gathers
|
|
|
|
* resource requirements for every downstream bridge by looking at the resource requests of its
|
|
|
|
* children. Thus, the requirement gathering begins at the leaf devices and is propagated back
|
|
|
|
* up to the downstream bridges of the domain.
|
|
|
|
*
|
|
|
|
* At domain level, it identifies every downstream bridge and walks down that bridge to gather
|
|
|
|
* requirements for each resource type i.e. i/o, mem and prefmem. Since bridges have separate
|
|
|
|
* windows for mem and prefmem, requirements for each need to be collected separately.
|
|
|
|
*
|
|
|
|
* Domain resource windows are fixed ranges and hence requirement gathering does not result in
|
|
|
|
* any changes to these fixed ranges.
|
|
|
|
*/
|
|
|
|
static void compute_domain_resources(const struct device *domain)
|
|
|
|
{
|
|
|
|
const struct device *child;
|
|
|
|
|
|
|
|
if (domain->link_list == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (child = domain->link_list->children; child; child = child->sibling) {
|
|
|
|
|
|
|
|
/* Skip if this is not a bridge or has no children under it. */
|
|
|
|
if (!dev_has_children(child))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
compute_bridge_resources(child, IORESOURCE_IO);
|
|
|
|
compute_bridge_resources(child, IORESOURCE_MEM);
|
|
|
|
compute_bridge_resources(child, IORESOURCE_MEM | IORESOURCE_PREFETCH);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char get_alignment_by_resource_type(const struct resource *res)
|
|
|
|
{
|
|
|
|
if (res->flags & IORESOURCE_MEM)
|
|
|
|
return 12; /* Page-aligned --> log2(4KiB) */
|
|
|
|
else if (res->flags & IORESOURCE_IO)
|
|
|
|
return 0; /* No special alignment required --> log2(1) */
|
|
|
|
|
|
|
|
die("Unexpected resource type: flags(%d)!\n", res->flags);
|
|
|
|
}
|
|
|
|
|
2020-05-16 02:33:52 +02:00
|
|
|
/*
|
|
|
|
* If the resource is NULL or if the resource is not assigned, then it cannot be used for
|
|
|
|
* allocation for downstream devices.
|
|
|
|
*/
|
|
|
|
static bool is_resource_invalid(const struct resource *res)
|
|
|
|
{
|
|
|
|
return (res == NULL) || !(res->flags & IORESOURCE_ASSIGNED);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void initialize_domain_io_resource_memranges(struct memranges *ranges,
|
|
|
|
const struct resource *res,
|
|
|
|
unsigned long memrange_type)
|
|
|
|
{
|
|
|
|
memranges_insert(ranges, res->base, res->limit - res->base + 1, memrange_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void initialize_domain_mem_resource_memranges(struct memranges *ranges,
|
|
|
|
const struct resource *res,
|
|
|
|
unsigned long memrange_type)
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
{
|
|
|
|
resource_t res_base;
|
|
|
|
resource_t res_limit;
|
2020-05-16 02:33:52 +02:00
|
|
|
|
|
|
|
const resource_t limit_4g = 0xffffffff;
|
|
|
|
|
|
|
|
res_base = res->base;
|
|
|
|
res_limit = res->limit;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Split the resource into two separate ranges if it crosses the 4G boundary. Memrange
|
|
|
|
* type is set differently to ensure that memrange does not merge these two ranges. For
|
|
|
|
* the range above 4G boundary, given memrange type is ORed with IORESOURCE_ABOVE_4G.
|
|
|
|
*/
|
|
|
|
if (res_base <= limit_4g) {
|
|
|
|
|
|
|
|
resource_t range_limit;
|
|
|
|
|
|
|
|
/* Clip the resource limit at 4G boundary if necessary. */
|
|
|
|
range_limit = MIN(res_limit, limit_4g);
|
|
|
|
memranges_insert(ranges, res_base, range_limit - res_base + 1, memrange_type);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the resource lies completely below the 4G boundary, nothing more needs to
|
|
|
|
* be done.
|
|
|
|
*/
|
|
|
|
if (res_limit <= limit_4g)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the resource window crosses the 4G boundary, then update res_base to add
|
|
|
|
* another entry for the range above the boundary.
|
|
|
|
*/
|
|
|
|
res_base = limit_4g + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res_base > res_limit)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If resource lies completely above the 4G boundary or if the resource was clipped to
|
|
|
|
* add two separate ranges, the range above 4G boundary has the resource flag
|
|
|
|
* IORESOURCE_ABOVE_4G set. This allows domain to handle any downstream requests for
|
|
|
|
* resource allocation above 4G differently.
|
|
|
|
*/
|
|
|
|
memranges_insert(ranges, res_base, res_limit - res_base + 1,
|
|
|
|
memrange_type | IORESOURCE_ABOVE_4G);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function initializes memranges for domain device. If the resource crosses 4G boundary,
|
|
|
|
* then this function splits it into two ranges -- one for the window below 4G and the other for
|
|
|
|
* the window above 4G. The latter range has IORESOURCE_ABOVE_4G flag set to satisfy resource
|
|
|
|
* requests from downstream devices for allocations above 4G.
|
|
|
|
*/
|
|
|
|
static void initialize_domain_memranges(struct memranges *ranges, const struct resource *res,
|
|
|
|
unsigned long memrange_type)
|
|
|
|
{
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
unsigned char align = get_alignment_by_resource_type(res);
|
|
|
|
|
|
|
|
memranges_init_empty_with_alignment(ranges, NULL, 0, align);
|
|
|
|
|
2020-05-16 02:33:52 +02:00
|
|
|
if (is_resource_invalid(res))
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
return;
|
|
|
|
|
2020-05-16 02:33:52 +02:00
|
|
|
if (res->flags & IORESOURCE_IO)
|
|
|
|
initialize_domain_io_resource_memranges(ranges, res, memrange_type);
|
|
|
|
else
|
|
|
|
initialize_domain_mem_resource_memranges(ranges, res, memrange_type);
|
|
|
|
}
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
|
2020-05-16 02:33:52 +02:00
|
|
|
/*
|
|
|
|
* This function initializes memranges for bridge device. Unlike domain, bridge does not need to
|
|
|
|
* care about resource window crossing 4G boundary. This is handled by the resource allocator at
|
|
|
|
* domain level to ensure that all downstream bridges are allocated space either above or below
|
|
|
|
* 4G boundary as per the state of IORESOURCE_ABOVE_4G for the respective bridge resource.
|
|
|
|
*
|
|
|
|
* So, this function creates a single range of the entire resource window available for the
|
|
|
|
* bridge resource. Thus all downstream resources of the bridge for the given resource type get
|
|
|
|
* allocated space from the same window. If there is any downstream resource of the bridge which
|
|
|
|
* requests allocation above 4G, then all other 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,
|
|
|
|
unsigned long memrange_type)
|
|
|
|
{
|
|
|
|
unsigned char align = get_alignment_by_resource_type(res);
|
|
|
|
|
|
|
|
memranges_init_empty_with_alignment(ranges, NULL, 0, align);
|
|
|
|
|
|
|
|
if (is_resource_invalid(res))
|
|
|
|
return;
|
|
|
|
|
|
|
|
memranges_insert(ranges, res->base, res->limit - res->base + 1, memrange_type);
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void print_resource_ranges(const struct memranges *ranges)
|
|
|
|
{
|
|
|
|
const struct range_entry *r;
|
|
|
|
|
|
|
|
printk(BIOS_INFO, "Resource ranges:\n");
|
|
|
|
|
|
|
|
if (memranges_is_empty(ranges))
|
|
|
|
printk(BIOS_INFO, "EMPTY!!\n");
|
|
|
|
|
|
|
|
memranges_each_entry(r, ranges) {
|
|
|
|
printk(BIOS_INFO, "Base: %llx, Size: %llx, Tag: %lx\n",
|
|
|
|
range_entry_base(r), range_entry_size(r), range_entry_tag(r));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is where the actual allocation of resources happens during pass 2. Given the list of
|
|
|
|
* memory ranges corresponding to the resource of given type, it finds the biggest unallocated
|
|
|
|
* resource using the type mask on the downstream bus. This continues in a descending
|
|
|
|
* order until all resources of given type are allocated address space within the current
|
|
|
|
* resource window.
|
|
|
|
*/
|
|
|
|
static void allocate_child_resources(struct bus *bus, struct memranges *ranges,
|
|
|
|
unsigned long type_mask, unsigned long type_match)
|
|
|
|
{
|
|
|
|
struct resource *resource = NULL;
|
|
|
|
const struct device *dev;
|
|
|
|
|
|
|
|
while ((dev = largest_resource(bus, &resource, type_mask, type_match))) {
|
|
|
|
|
|
|
|
if (!resource->size)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (memranges_steal(ranges, resource->limit, resource->size, resource->align,
|
|
|
|
type_match, &resource->base) == false) {
|
|
|
|
printk(BIOS_ERR, "ERROR: Resource didn't fit!!! ");
|
|
|
|
printk(BIOS_SPEW, "%s %02lx * size: 0x%llx limit: %llx %s\n",
|
|
|
|
dev_path(dev), resource->index,
|
|
|
|
resource->size, resource->limit, resource2str(resource));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
resource->limit = resource->base + resource->size - 1;
|
|
|
|
resource->flags |= IORESOURCE_ASSIGNED;
|
|
|
|
|
|
|
|
printk(BIOS_SPEW, "%s %02lx * [0x%llx - 0x%llx] limit: %llx %s\n",
|
|
|
|
dev_path(dev), resource->index, resource->base,
|
|
|
|
resource->size ? resource->base + resource->size - 1 :
|
|
|
|
resource->base, resource->limit, resource2str(resource));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_constraints(struct memranges *ranges, const struct device *dev,
|
|
|
|
const struct resource *res)
|
|
|
|
{
|
|
|
|
if (!res->size)
|
|
|
|
return;
|
|
|
|
|
|
|
|
printk(BIOS_SPEW, "%s: %s %02lx base %08llx limit %08llx %s (fixed)\n",
|
|
|
|
__func__, dev_path(dev), res->index, res->base,
|
|
|
|
res->base + res->size - 1, resource2str(res));
|
|
|
|
|
|
|
|
memranges_create_hole(ranges, res->base, res->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan the entire tree to identify any fixed resources allocated by any device to
|
|
|
|
* ensure that the address map for domain resources are appropriately updated.
|
|
|
|
*
|
|
|
|
* Domains can typically provide memrange for entire address space. So, this function
|
|
|
|
* punches holes in the address space for all fixed resources that are already
|
|
|
|
* defined. Both IO and normal memory resources are added as fixed. Both need to be
|
|
|
|
* removed from address space where dynamic resource allocations are sourced.
|
|
|
|
*/
|
|
|
|
static void avoid_fixed_resources(struct memranges *ranges, const struct device *dev,
|
|
|
|
unsigned long mask_match)
|
|
|
|
{
|
|
|
|
const struct resource *res;
|
|
|
|
const struct device *child;
|
|
|
|
const struct bus *bus;
|
|
|
|
|
|
|
|
for (res = dev->resource_list; res != NULL; res = res->next) {
|
|
|
|
if ((res->flags & mask_match) != mask_match)
|
|
|
|
continue;
|
|
|
|
update_constraints(ranges, dev, res);
|
|
|
|
}
|
|
|
|
|
|
|
|
bus = dev->link_list;
|
|
|
|
if (bus == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (child = bus->children; child != NULL; child = child->sibling)
|
|
|
|
avoid_fixed_resources(ranges, child, mask_match);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void constrain_domain_resources(const struct device *domain, struct memranges *ranges,
|
|
|
|
unsigned long type)
|
|
|
|
{
|
|
|
|
unsigned long mask_match = type | IORESOURCE_FIXED;
|
|
|
|
|
|
|
|
if (type == IORESOURCE_IO) {
|
|
|
|
/*
|
|
|
|
* Don't allow allocations in the VGA I/O range. PCI has special cases for
|
|
|
|
* that.
|
|
|
|
*/
|
2020-05-26 21:04:35 +02:00
|
|
|
memranges_create_hole(ranges, 0x3b0, 0x3df - 0x3b0 + 1);
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Resource allocator no longer supports the legacy behavior where I/O resource
|
|
|
|
* allocation is guaranteed to avoid aliases over legacy PCI expansion card
|
|
|
|
* addresses.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
avoid_fixed_resources(ranges, domain, mask_match);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function creates a list of memranges of given type using the resource that is
|
|
|
|
* provided. If the given resource is NULL or if the resource window size is 0, then it creates
|
|
|
|
* an empty list. This results in resource allocation for that resource type failing for all
|
|
|
|
* downstream devices since there is nothing to allocate from.
|
|
|
|
*
|
|
|
|
* In case of domain, it applies additional constraints to ensure that the memranges do not
|
|
|
|
* overlap any of the fixed resources under that domain. Domain typically seems to provide
|
|
|
|
* memrange for entire address space. Thus, it is up to the chipset to add DRAM and all other
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
printk(BIOS_SPEW, "%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);
|
|
|
|
|
2020-05-16 02:33:52 +02:00
|
|
|
if (dev->path.type == DEVICE_PATH_DOMAIN) {
|
|
|
|
initialize_domain_memranges(ranges, res, type);
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
constrain_domain_resources(dev, ranges, type);
|
2020-05-16 02:33:52 +02:00
|
|
|
} else {
|
|
|
|
initialize_bridge_memranges(ranges, res, type);
|
|
|
|
}
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
|
|
|
|
print_resource_ranges(ranges);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cleanup_resource_ranges(const struct device *dev, struct memranges *ranges,
|
|
|
|
const struct resource *res)
|
|
|
|
{
|
|
|
|
memranges_teardown(ranges);
|
|
|
|
printk(BIOS_SPEW, "%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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pass 2 of resource allocator at the bridge level loops through all the resources for the
|
|
|
|
* bridge and generates a list of memory ranges similar to that at the domain level. However,
|
|
|
|
* there is no need to apply any additional constraints since the window allocated to the bridge
|
|
|
|
* is guaranteed to be non-overlapping by the allocator at domain level.
|
|
|
|
*
|
|
|
|
* Allocation at the bridge level works the same as at domain level (starts with the biggest
|
|
|
|
* resource requirement from downstream devices and continues in descending order). One major
|
|
|
|
* difference at the bridge level is that it considers prefmem resources separately from mem
|
|
|
|
* resources.
|
|
|
|
*
|
|
|
|
* Once allocation at the current bridge is complete, resource allocator continues walking down
|
|
|
|
* the downstream bridges until it hits the leaf devices.
|
|
|
|
*/
|
|
|
|
static void allocate_bridge_resources(const struct device *bridge)
|
|
|
|
{
|
|
|
|
struct memranges ranges;
|
|
|
|
const struct resource *res;
|
|
|
|
struct bus *bus = bridge->link_list;
|
|
|
|
unsigned long type_match;
|
|
|
|
struct device *child;
|
|
|
|
const unsigned long type_mask = IORESOURCE_TYPE_MASK | IORESOURCE_PREFETCH;
|
|
|
|
|
|
|
|
for (res = bridge->resource_list; res; res = res->next) {
|
|
|
|
if (!res->size)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(res->flags & IORESOURCE_BRIDGE))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
type_match = res->flags & type_mask;
|
|
|
|
|
|
|
|
setup_resource_ranges(bridge, res, type_match, &ranges);
|
|
|
|
allocate_child_resources(bus, &ranges, type_mask, type_match);
|
|
|
|
cleanup_resource_ranges(bridge, &ranges, res);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (child = bus->children; child; child = child->sibling) {
|
|
|
|
if (!dev_has_children(child))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
allocate_bridge_resources(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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, this function creates a list of memory
|
|
|
|
* ranges that can be used for downstream resource allocation. This list is constrained to
|
|
|
|
* remove any fixed resources in the domain sub-tree of the given resource type. It then uses
|
|
|
|
* the memory ranges to apply best fit on the resource requirements of the downstream devices.
|
|
|
|
*
|
|
|
|
* Once resources are allocated to all downstream devices of the domain, it walks down each
|
|
|
|
* downstream bridge to continue the same process until resources are allocated to all devices
|
|
|
|
* under the domain.
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Resource type Mem:
|
|
|
|
* Domain does not distinguish between mem and prefmem resources. Thus, the resource
|
|
|
|
* allocation at domain level considers mem and prefmem together when finding the best
|
|
|
|
* fit based on the biggest resource requirement.
|
2020-05-16 02:33:52 +02:00
|
|
|
*
|
|
|
|
* However, resource requests for allocation above 4G boundary need to be handled
|
|
|
|
* separately if the domain resource window crosses this boundary. There is a single
|
|
|
|
* window for resource of type IORESOURCE_MEM. When creating memranges, this resource
|
|
|
|
* is split into two separate ranges -- one for the window below 4G boundary and other
|
|
|
|
* for the window above 4G boundary (with IORESOURCE_ABOVE_4G flag set). Thus, when
|
|
|
|
* allocating child resources, requests for below and above the 4G boundary are handled
|
|
|
|
* separately by setting the type_mask and type_match to allocate_child_resources()
|
|
|
|
* accordingly.
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
*/
|
|
|
|
res = find_domain_resource(domain, IORESOURCE_MEM);
|
|
|
|
if (res) {
|
|
|
|
setup_resource_ranges(domain, res, IORESOURCE_MEM, &ranges);
|
2020-05-16 02:33:52 +02:00
|
|
|
allocate_child_resources(domain->link_list, &ranges,
|
|
|
|
IORESOURCE_TYPE_MASK | IORESOURCE_ABOVE_4G,
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
IORESOURCE_MEM);
|
2020-05-16 02:33:52 +02:00
|
|
|
allocate_child_resources(domain->link_list, &ranges,
|
|
|
|
IORESOURCE_TYPE_MASK | IORESOURCE_ABOVE_4G,
|
|
|
|
IORESOURCE_MEM | IORESOURCE_ABOVE_4G);
|
device: Add support for resource allocator v4
This change adds back support for the resource allocator using
multiple ranges as originally landed in CB:39486(commit hash 3b02006)
and reverted in CB:41413(commit hash 6186cbc). The new resource
allocator can be selected by Kconfig option RESOURCE_ALLOCATOR_V4. It
was identified that there are some AMD chipsets in the tree that do
not really work well with the dynamic resource allocation. Until these
chipsets are fixed, old (v3) and new (v4) of the resource allocator
need to live side-by-side in the tree. There were some other chipsets
in the tree which originally demonstrated problems with the new
resource allocator, but have been since fixed in the tree.
This change picks up the same additions as performed in CB:39486 along
with the following changes:
1. Changes to avoid fixed resources in the entire tree. Use of
search_bus_resources() is replaced with a walk of the entire tree
in avoid_fixed_resources(). This is required to ensure that all fixed
resources added to any device (including domain) are taken into
consideration to avoid overlap during dynamic resource allocation.
2. Changes to set up alignment for memranges when initializing
them. This is done to ensure that the right granularity is used for
IORESOURCE_IO(no special alignment) and IORESOURCE_MEM(4KiB) resource
requests.
3. mark_resource_invalid() is dropped as the resource no longer needs
to be marked in any special way if allocation is not being
done. Instead setting of IORESOURCE_ASSIGNED flag is skipped in this
case.
4. initialize_memranges() is updated to check IORESOURCE_ASSIGNED
instead of base == limit.
Original commit message:
This change updates the resource allocator in coreboot to allow using
multiple ranges for resource allocation rather than restricting
available window to a single base/limit pair. This is done in
preparation to allow 64-bit resource allocation.
Following changes are made as part of this:
a) Resource allocator still makes 2 passes at the entire tree. The
first pass is to gather the resource requirements of each device
under each domain. It walks recursively in DFS fashion to gather the
requirements of the leaf devices and propagates this back up to the
downstream bridges of the domain. Domain is special in the sense that
it has fixed resource ranges. Hence, the resource requirements from
the downstream devices have no effect on the domain resource
windows. This results in domain resource limits being unmodified after
the first pass.
b) Once the requirements for all the devices under the domain are
gathered, resource allocator walks a second time to allocate resources
to downstream devices as per the requirements. Here, instead of
maintaining a single window for allocating resources, it creates a
list of memranges starting with the resource window at domain and then
applying constraints to create holes for any fixed resources. This
ensures that there is no overlap with fixed resources under the
domain.
c) Domain does not differentiate between mem and prefmem. Since they
are allocated space from the same resource window at the domain level,
it considers all resource requests from downstream devices of the
domain independent of the prefetch type.
d) Once resource allocation is done at the domain level, resource
allocator walks down the downstream bridges and continues the same
process until it reaches the leaves. Bridges have separate windows for
mem and prefmem. Hence, unlike domain, the resource allocator at
bridge level ensures that downstream requirements are satisfied by
taking prefetch type into consideration.
e) This whole 2-pass process is performed for every domain in the
system under the assumption that domains do not have overlapping
address spaces.
Noticeable differences from previous resource allocator:
a) Changes in print logs observed due to flows being slightly
different.
b) Base, limit and size of domain resources are no longer updated
based on downstream requirements.
c) Memranges are used instead of a single base/limit pair for
determining resource allocation.
d) Previously, if a resource request did not fit in the available
base/limit window, then the resource would be allocated over DRAM or
any other address space defeating the principle of "no overlap". With
this change, any time a resource cannot fit in the available ranges,
it complains and ensures that the resource is effectively disabled by
setting base same as the limit.
e) Resource allocator no longer looks at multiple links to determine
the right bus for a resource. None of the current boards have multiple
buses under any downstream device of the domain. The only device with
multiple links seems to be the cpu cluster device for some AMD
platforms.
Change-Id: Ide4d98528197bb03850a8fb4d73c41cd2c0195aa
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-16 01:04:28 +02:00
|
|
|
cleanup_resource_ranges(domain, &ranges, res);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (child = domain->link_list->children; child; child = child->sibling) {
|
|
|
|
if (!dev_has_children(child))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Continue allocation for all downstream bridges. */
|
|
|
|
allocate_bridge_resources(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function forms the guts of the resource allocator. It walks through the entire device
|
|
|
|
* tree for each domain two times.
|
|
|
|
*
|
|
|
|
* Every domain has a fixed set of ranges. These ranges cannot be relaxed based on the
|
|
|
|
* requirements of the downstream devices. They represent the available windows from which
|
|
|
|
* resources can be allocated to the different devices under the domain.
|
|
|
|
*
|
|
|
|
* In order to identify the requirements of downstream devices, resource allocator walks in a
|
|
|
|
* DFS fashion. It gathers the requirements from leaf devices and propagates those back up
|
|
|
|
* to their upstream bridges until the requirements for all the downstream devices of the domain
|
|
|
|
* are gathered. This is referred to as pass 1 of resource allocator.
|
|
|
|
*
|
|
|
|
* Once the requirements for all the devices under the domain are gathered, resource allocator
|
|
|
|
* walks a second time to allocate resources to downstream devices as per the
|
|
|
|
* requirements. It always picks the biggest resource request as per the type (i/o and mem) to
|
|
|
|
* allocate space from its fixed window to the immediate downstream device of the domain. In
|
|
|
|
* order to accomplish best fit for the resources, a list of ranges is maintained by each
|
|
|
|
* resource type (i/o and mem). Domain does not differentiate between mem and prefmem. Since
|
|
|
|
* they are allocated space from the same window, the resource allocator at the domain level
|
|
|
|
* ensures that the biggest requirement is selected indepedent of the prefetch type. Once the
|
|
|
|
* resource allocation for all immediate downstream devices is complete at the domain level,
|
|
|
|
* resource allocator walks down the subtree for each downstream bridge to continue the
|
|
|
|
* allocation process at the bridge level. Since bridges have separate windows for i/o, mem and
|
|
|
|
* prefmem, best fit algorithm at bridge level looks for the biggest requirement considering
|
|
|
|
* prefmem resources separately from non-prefmem resources. This continues until resource
|
|
|
|
* allocation is performed for all downstream bridges in the domain sub-tree. This is referred
|
|
|
|
* to as pass 2 of resource allocator.
|
|
|
|
*
|
|
|
|
* Some rules that are followed by the resource allocator:
|
|
|
|
* - Allocate resource locations for every device as long as the requirements can be satisfied.
|
|
|
|
* - If a resource cannot be allocated any address space, then that resource needs to be
|
|
|
|
* properly updated to ensure that it does not incorrectly overlap some address space reserved
|
|
|
|
* for a different purpose.
|
|
|
|
* - Don't overlap with resources in fixed locations.
|
|
|
|
* - Don't overlap and follow the rules of bridges -- downstream devices of bridges should use
|
|
|
|
* parts of the address space allocated to the bridge.
|
|
|
|
*/
|
|
|
|
void allocate_resources(const struct device *root)
|
|
|
|
{
|
|
|
|
const struct device *child;
|
|
|
|
|
|
|
|
if ((root == NULL) || (root->link_list == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (child = root->link_list->children; child; child = child->sibling) {
|
|
|
|
|
|
|
|
if (child->path.type != DEVICE_PATH_DOMAIN)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
post_log_path(child);
|
|
|
|
|
|
|
|
/* Pass 1 - Gather requirements. */
|
|
|
|
printk(BIOS_INFO, "Resource allocator: %s - Pass 1 (gathering requirements)\n",
|
|
|
|
dev_path(child));
|
|
|
|
compute_domain_resources(child);
|
|
|
|
|
|
|
|
/* Pass 2 - Allocate resources as per gathered requirements. */
|
|
|
|
printk(BIOS_INFO, "Resource allocator: %s - Pass 2 (allocating resources)\n",
|
|
|
|
dev_path(child));
|
|
|
|
allocate_domain_resources(child);
|
|
|
|
}
|
|
|
|
}
|