allocator_v4: Use memranges only for toplevel
During phase 1 of the resource allocation we gather all the size
requirements. Starting from the leafs of our devicetree, we cal-
culate the requirements per bus, until we reach the resource do-
main.
However, because alignment plays a role, we can't just accumulate
the sizes of all resources on a bus. Instead, we already sort all
the resources per bus to predict their relative placement, inclu-
ding alignment gaps. Then, phase 2 has to perform the final allo-
cations with the exact same relative placement.
This patch introduces a very simple mechanism to avoid repeating
all the calculations: In phase 1, we note the relative `base` of
each resource on a bus. And after we allocated all the resources
directly below the domain in phase 2, we add the absolute `base`
of bridge resources to the relative `base` of child resources.
This saves most of the computational complexity in phase 2. How-
ever, with a shallow devicetree with most devices directly below
the domain, this won't have a measurable impact.
Example after phase 1:
  domain
    |
    `-- bridge #0
          |   res #0, base 0x000000 (relative),
          |   size 12M, align 8M
          |
          |-- device #0
          |         res #1, base 0x800000 (relative),
          |         size 4M, align 4M
          |
          `-- bridge #1
                |   res #2, base 0x000000 (relative),
                |   size 8M, align 8M
                |
                `-- device #1
                          res #3, base 0x000000 (relative),
                          size 8M, align 8M
After phase 2 allocation at the domain level (assuming res #0 got
0xa000000 assigned):
  domain
    |
    `-- bridge #0
          |   res #0, base 0xa000000 (absolute),
          |   size 12M, align 8M
          |
          |-- device #0
          |         res #1, base 0x800000 (relative),
          |         size 4M, align 4M
          |
          `-- bridge #1
                |   res #2, base 0x000000 (relative),
                |   size 8M, align 8M
                |
                `-- device #1
                          res #3, base 0x000000 (relative),
                          size 8M, align 8M
Now, all we need to do is to add the `base` of bridge resources
recursively. Starting with resources on the bus below bridge #0:
  domain
    |
    `-- bridge #0
          |   res #0, base 0xa000000 (absolute),
          |   size 12M, align 8M
          |
          |-- device #0
          |         res #1, base 0xa800000 (absolute),
          |         size 4M, align 4M
          |
          `-- bridge #1
                |   res #2, base 0xa000000 (absolute),
                |   size 8M, align 8M
                |
                `-- device #1
                          res #3, base 0x000000 (relative),
                          size 8M, align 8M
And finally for resources on the bus below bridge #1:
  domain
    |
    `-- bridge #0
          |   res #0, base 0xa000000 (absolute),
          |   size 12M, align 8M
          |
          |-- device #0
          |         res #1, base 0xa800000 (absolute),
          |         size 4M, align 4M
          |
          `-- bridge #1
                |   res #2, base 0xa000000 (absolute),
                |   size 8M, align 8M
                |
                `-- device #1
                          res #3, base 0xa000000 (absolute),
                          size 8M, align 8M
Change-Id: I70c700318a85f6760f27597730bc9c9a86dbe6b3
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/65420
Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Felix Singer <service+coreboot-gerrit@felixsinger.de>
			
			
This commit is contained in:
		
				
					committed by
					
						
						Arthur Heymans
					
				
			
			
				
	
			
			
			
						parent
						
							5226301765
						
					
				
				
					commit
					9260ea60bf
				
			@@ -49,6 +49,11 @@ static resource_t effective_limit(const struct resource *const res)
 | 
				
			|||||||
 * resource. This is required to guarantee that the upstream bridge/
 | 
					 * resource. This is required to guarantee that the upstream bridge/
 | 
				
			||||||
 * domain honors the limit and alignment requirements for this bridge
 | 
					 * domain honors the limit and alignment requirements for this bridge
 | 
				
			||||||
 * based on the tightest constraints downstream.
 | 
					 * based on the tightest constraints downstream.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Last but not least, it stores the offset inside the bridge resource
 | 
				
			||||||
 | 
					 * for each child resource in its base field. This simplifies pass 2
 | 
				
			||||||
 | 
					 * for resources behind a bridge, as we only have to add offsets to the
 | 
				
			||||||
 | 
					 * allocated base of the bridge resource.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void update_bridge_resource(const struct device *bridge, struct resource *bridge_res,
 | 
					static void update_bridge_resource(const struct device *bridge, struct resource *bridge_res,
 | 
				
			||||||
				   unsigned long type_match, int print_depth)
 | 
									   unsigned long type_match, int print_depth)
 | 
				
			||||||
@@ -89,13 +94,8 @@ static void update_bridge_resource(const struct device *bridge, struct resource
 | 
				
			|||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Propagate the resource alignment to the bridge resource. The
 | 
							 * Propagate the resource alignment to the bridge resource. The
 | 
				
			||||||
		 * condition can only be true for the first (largest) resource. For all
 | 
							 * condition can only be true for the first (largest) resource. For all
 | 
				
			||||||
		 * other children resources, alignment is taken care of by updating the
 | 
							 * other child resources, alignment is taken care of by rounding their
 | 
				
			||||||
		 * base to round up as per the child resource alignment. It is
 | 
							 * base up.
 | 
				
			||||||
		 * 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 the largest child resource is propagated up to the
 | 
					 | 
				
			||||||
		 * bridge resource, it can be guaranteed that the alignment for all
 | 
					 | 
				
			||||||
		 * resources is appropriately met.
 | 
					 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (child_res->align > bridge_res->align)
 | 
							if (child_res->align > bridge_res->align)
 | 
				
			||||||
			bridge_res->align = child_res->align;
 | 
								bridge_res->align = child_res->align;
 | 
				
			||||||
@@ -103,10 +103,8 @@ static void update_bridge_resource(const struct device *bridge, struct resource
 | 
				
			|||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Propagate the resource limit to the bridge resource. If a downstream
 | 
							 * Propagate the resource limit to the bridge resource. If a downstream
 | 
				
			||||||
		 * device has stricter requirements w.r.t. limits for any resource, that
 | 
							 * device has stricter requirements w.r.t. limits for any resource, that
 | 
				
			||||||
		 * constraint needs to be propagated back up to the downstream bridges
 | 
							 * constraint needs to be propagated back up to the bridges downstream
 | 
				
			||||||
		 * of the domain. This guarantees that the resource allocation which
 | 
							 * of the domain. This way, the whole bridge resource fulfills the limit.
 | 
				
			||||||
		 * starts at the domain level takes into account all these constraints
 | 
					 | 
				
			||||||
		 * thus working on a global view.
 | 
					 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (effective_limit(child_res) < bridge_res->limit)
 | 
							if (effective_limit(child_res) < bridge_res->limit)
 | 
				
			||||||
			bridge_res->limit = effective_limit(child_res);
 | 
								bridge_res->limit = effective_limit(child_res);
 | 
				
			||||||
@@ -117,6 +115,14 @@ static void update_bridge_resource(const struct device *bridge, struct resource
 | 
				
			|||||||
		 */
 | 
							 */
 | 
				
			||||||
		base = ALIGN_UP(base, POWER_OF_2(child_res->align));
 | 
							base = ALIGN_UP(base, POWER_OF_2(child_res->align));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Store the relative offset inside the bridge resource for later
 | 
				
			||||||
 | 
							 * consumption in allocate_bridge_resources(), and invalidate flags
 | 
				
			||||||
 | 
							 * related to the base.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							child_res->base = base;
 | 
				
			||||||
 | 
							child_res->flags &= ~(IORESOURCE_ASSIGNED | IORESOURCE_STORED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		res_printk(print_depth + 1, "%s %02lx *  [0x%llx - 0x%llx] %s\n",
 | 
							res_printk(print_depth + 1, "%s %02lx *  [0x%llx - 0x%llx] %s\n",
 | 
				
			||||||
		       dev_path(child), child_res->index, base, base + child_res->size - 1,
 | 
							       dev_path(child), child_res->index, base, base + child_res->size - 1,
 | 
				
			||||||
		       resource2str(child_res));
 | 
							       resource2str(child_res));
 | 
				
			||||||
@@ -237,48 +243,6 @@ static void print_resource_ranges(const struct device *dev, const struct memrang
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * 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)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const bool allocate_top_down =
 | 
					 | 
				
			||||||
		bus->dev->path.type == DEVICE_PATH_DOMAIN &&
 | 
					 | 
				
			||||||
		CONFIG(RESOURCE_ALLOCATION_TOP_DOWN);
 | 
					 | 
				
			||||||
	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, effective_limit(resource), resource->size,
 | 
					 | 
				
			||||||
				    resource->align, type_match, &resource->base,
 | 
					 | 
				
			||||||
				    allocate_top_down) == false) {
 | 
					 | 
				
			||||||
			printk(BIOS_ERR, "Resource didn't fit!!! ");
 | 
					 | 
				
			||||||
			printk(BIOS_DEBUG, "  %s %02lx *  size: 0x%llx limit: %llx %s\n",
 | 
					 | 
				
			||||||
			       dev_path(dev), resource->index, resource->size,
 | 
					 | 
				
			||||||
			       effective_limit(resource), resource2str(resource));
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		resource->limit = resource->base + resource->size - 1;
 | 
					 | 
				
			||||||
		resource->flags |= IORESOURCE_ASSIGNED;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		printk(BIOS_DEBUG, "  %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,
 | 
					static void update_constraints(struct memranges *ranges, const struct device *dev,
 | 
				
			||||||
			      const struct resource *res)
 | 
								      const struct resource *res)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -348,49 +312,36 @@ static void constrain_domain_resources(const struct device *domain, struct memra
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This function creates a list of memranges of given type using the
 | 
					 * This function creates a list of memranges of given type using the
 | 
				
			||||||
 * resource that is provided. If the given resource is unassigned or if
 | 
					 * resource that is provided. It applies additional constraints to
 | 
				
			||||||
 * the resource window size is 0, then it creates an empty list. This
 | 
					 * ensure that the memranges do not overlap any of the fixed resources
 | 
				
			||||||
 * results in resource allocation for that resource type failing for
 | 
					 * under the domain. The domain typically provides a memrange for the
 | 
				
			||||||
 * all downstream devices since there is nothing to allocate from.
 | 
					 * 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
 | 
				
			||||||
 * In case of domain, it applies additional constraints to ensure that
 | 
					 * fixed resources.
 | 
				
			||||||
 * 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, unsigned long type,
 | 
					static void setup_resource_ranges(const struct device *const domain,
 | 
				
			||||||
				  struct memranges *ranges)
 | 
									  const unsigned long type,
 | 
				
			||||||
 | 
									  struct memranges *const ranges)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const unsigned long type_mask = IORESOURCE_TYPE_MASK | IORESOURCE_FIXED |
 | 
						const unsigned long type_mask = IORESOURCE_TYPE_MASK | IORESOURCE_FIXED;
 | 
				
			||||||
		(dev->path.type != DEVICE_PATH_DOMAIN
 | 
					 | 
				
			||||||
		 ? IORESOURCE_PREFETCH | IORESOURCE_ASSIGNED
 | 
					 | 
				
			||||||
		 : 0);
 | 
					 | 
				
			||||||
	const unsigned long type_match = type |
 | 
					 | 
				
			||||||
		(dev->path.type != DEVICE_PATH_DOMAIN ? IORESOURCE_ASSIGNED : 0);
 | 
					 | 
				
			||||||
	const unsigned char alignment = get_alignment_by_resource_type(type);
 | 
						const unsigned char alignment = get_alignment_by_resource_type(type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memranges_init_empty_with_alignment(ranges, NULL, 0, alignment);
 | 
						memranges_init_empty_with_alignment(ranges, NULL, 0, alignment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (struct resource *res = dev->resource_list; res != NULL; res = res->next) {
 | 
						for (struct resource *res = domain->resource_list; res != NULL; res = res->next) {
 | 
				
			||||||
		if ((res->flags & type_mask) != type_match)
 | 
							if ((res->flags & type_mask) != type)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printk(BIOS_DEBUG, "%s %s: base: %llx size: %llx align: %u gran: %u limit: %llx\n",
 | 
							printk(BIOS_DEBUG, "%s %s: base: %llx size: %llx align: %u gran: %u limit: %llx\n",
 | 
				
			||||||
		       dev_path(dev), resource2str(res), res->base, res->size, res->align,
 | 
							       dev_path(domain), resource2str(res), res->base, res->size, res->align,
 | 
				
			||||||
		       res->gran, res->limit);
 | 
							       res->gran, res->limit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		memranges_insert(ranges, res->base, res->limit - res->base + 1, type);
 | 
							memranges_insert(ranges, res->base, res->limit - res->base + 1, type);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (dev->path.type != DEVICE_PATH_DOMAIN)
 | 
					 | 
				
			||||||
			break; /* only one resource per type for bridges */
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev->path.type == DEVICE_PATH_DOMAIN)
 | 
						constrain_domain_resources(domain, ranges, type);
 | 
				
			||||||
		constrain_domain_resources(dev, ranges, type);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	print_resource_ranges(dev, ranges);
 | 
						print_resource_ranges(domain, ranges);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_resource_done(const struct device *dev, const struct resource *res)
 | 
					static void print_resource_done(const struct device *dev, const struct resource *res)
 | 
				
			||||||
@@ -413,49 +364,104 @@ static void cleanup_domain_resource_ranges(const struct device *dev, struct memr
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void assign_resource(struct resource *const res, const resource_t base,
 | 
				
			||||||
 | 
								    const struct device *const dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						res->base = base;
 | 
				
			||||||
 | 
						res->limit = res->base + res->size - 1;
 | 
				
			||||||
 | 
						res->flags |= IORESOURCE_ASSIGNED;
 | 
				
			||||||
 | 
						res->flags &= ~IORESOURCE_STORED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printk(BIOS_DEBUG, "  %s %02lx *  [0x%llx - 0x%llx] limit: %llx %s\n",
 | 
				
			||||||
 | 
						       dev_path(dev), res->index, res->base, res->limit, res->limit, resource2str(res));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is where the actual allocation of resources happens during
 | 
				
			||||||
 | 
					 * pass 2. We construct a list of memory ranges corresponding to the
 | 
				
			||||||
 | 
					 * resource of a given type, then look for the biggest unallocated
 | 
				
			||||||
 | 
					 * resource on the downstream bus. This continues in a descending order
 | 
				
			||||||
 | 
					 * until all resources of a given type have space allocated within the
 | 
				
			||||||
 | 
					 * domain's resource window.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void allocate_toplevel_resources(const struct device *const domain,
 | 
				
			||||||
 | 
										const unsigned long type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const unsigned long type_mask = IORESOURCE_TYPE_MASK;
 | 
				
			||||||
 | 
						struct resource *res = NULL;
 | 
				
			||||||
 | 
						const struct device *dev;
 | 
				
			||||||
 | 
						struct memranges ranges;
 | 
				
			||||||
 | 
						resource_t base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dev_has_children(domain))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_resource_ranges(domain, type, &ranges);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((dev = largest_resource(domain->link_list, &res, type_mask, type))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!res->size)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!memranges_steal(&ranges, res->limit, res->size, res->align, type, &base,
 | 
				
			||||||
 | 
									     CONFIG(RESOURCE_ALLOCATION_TOP_DOWN))) {
 | 
				
			||||||
 | 
								printk(BIOS_ERR, "Resource didn't fit!!! ");
 | 
				
			||||||
 | 
								printk(BIOS_DEBUG, "  %s %02lx *  size: 0x%llx limit: %llx %s\n",
 | 
				
			||||||
 | 
								       dev_path(dev), res->index, res->size,
 | 
				
			||||||
 | 
								       res->limit, resource2str(res));
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							assign_resource(res, base, dev);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cleanup_domain_resource_ranges(domain, &ranges, type);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Pass 2 of the resource allocator at the bridge level loops through
 | 
					 * Pass 2 of the resource allocator at the bridge level loops through
 | 
				
			||||||
 * all the resources for the bridge and generates a list of memory
 | 
					 * all the resources for the bridge and assigns all the base addresses
 | 
				
			||||||
 * ranges similar to that at the domain level. However, there is no need
 | 
					 * of its children's resources of the same type. update_bridge_resource()
 | 
				
			||||||
 * to apply any additional constraints since the window allocated to the
 | 
					 * of pass 1 pre-calculated the offsets of these bases inside the bridge
 | 
				
			||||||
 * bridge is guaranteed to be non-overlapping by the allocator at domain
 | 
					 * resource. Now that the bridge resource is allocated, all we have to
 | 
				
			||||||
 * level.
 | 
					 * do is to add its final base to these offsets.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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
 | 
					 * Once allocation at the current bridge is complete, resource allocator
 | 
				
			||||||
 * continues walking down the downstream bridges until it hits the leaf
 | 
					 * continues walking down the downstream bridges until it hits the leaf
 | 
				
			||||||
 * devices.
 | 
					 * devices.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					static void assign_resource_cb(void *param, struct device *dev, struct resource *res)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* We have to filter the same resources as update_bridge_resource(). */
 | 
				
			||||||
 | 
						if (!res->size || !res->limit)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assign_resource(res, *(const resource_t *)param + res->base, dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
static void allocate_bridge_resources(const struct device *bridge)
 | 
					static void allocate_bridge_resources(const struct device *bridge)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct memranges ranges;
 | 
						const unsigned long type_mask =
 | 
				
			||||||
	const struct resource *res;
 | 
							IORESOURCE_TYPE_MASK | IORESOURCE_PREFETCH | IORESOURCE_FIXED;
 | 
				
			||||||
	struct bus *bus = bridge->link_list;
 | 
						struct bus *const bus = bridge->link_list;
 | 
				
			||||||
	unsigned long type_match;
 | 
						struct resource *res;
 | 
				
			||||||
	struct device *child;
 | 
						struct device *child;
 | 
				
			||||||
	const unsigned long type_mask = IORESOURCE_TYPE_MASK | IORESOURCE_PREFETCH;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (res = bridge->resource_list; res; res = res->next) {
 | 
						for (res = bridge->resource_list; res != NULL; res = res->next) {
 | 
				
			||||||
		if (!res->size)
 | 
							if (!res->size)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!(res->flags & IORESOURCE_BRIDGE))
 | 
							if (!(res->flags & IORESOURCE_BRIDGE))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		type_match = res->flags & type_mask;
 | 
							if (!(res->flags & IORESOURCE_ASSIGNED))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		setup_resource_ranges(bridge, type_match, &ranges);
 | 
							/* Run assign_resource_cb() for all downstream resources of the same type. */
 | 
				
			||||||
		allocate_child_resources(bus, &ranges, type_mask, type_match);
 | 
							search_bus_resources(bus, type_mask, res->flags & type_mask,
 | 
				
			||||||
		print_resource_done(bridge, res);
 | 
									     assign_resource_cb, &res->base);
 | 
				
			||||||
		memranges_teardown(&ranges);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (child = bus->children; child; child = child->sibling) {
 | 
						for (child = bus->children; child != NULL; child = child->sibling) {
 | 
				
			||||||
		if (!dev_has_children(child))
 | 
							if (!dev_has_children(child))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -473,19 +479,13 @@ static void allocate_bridge_resources(const struct device *bridge)
 | 
				
			|||||||
 * resource requirements of the downstream devices.
 | 
					 * resource requirements of the downstream devices.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Once resources are allocated to all downstream devices of the domain,
 | 
					 * Once resources are allocated to all downstream devices of the domain,
 | 
				
			||||||
 * it walks down each downstream bridge to continue the same process
 | 
					 * it walks down each downstream bridge to finish resource assignment
 | 
				
			||||||
 * until resources are allocated to all devices under the domain.
 | 
					 * of its children resources within its own window.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void allocate_domain_resources(const struct device *domain)
 | 
					static void allocate_domain_resources(const struct device *domain)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct memranges ranges;
 | 
					 | 
				
			||||||
	struct device *child;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Resource type I/O */
 | 
						/* Resource type I/O */
 | 
				
			||||||
	setup_resource_ranges(domain, IORESOURCE_IO, &ranges);
 | 
						allocate_toplevel_resources(domain, IORESOURCE_IO);
 | 
				
			||||||
	allocate_child_resources(domain->link_list, &ranges, IORESOURCE_TYPE_MASK,
 | 
					 | 
				
			||||||
				 IORESOURCE_IO);
 | 
					 | 
				
			||||||
	cleanup_domain_resource_ranges(domain, &ranges, IORESOURCE_IO);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Resource type Mem:
 | 
						 * Resource type Mem:
 | 
				
			||||||
@@ -494,11 +494,9 @@ static void allocate_domain_resources(const struct device *domain)
 | 
				
			|||||||
	 * together when finding the best fit based on the biggest resource
 | 
						 * together when finding the best fit based on the biggest resource
 | 
				
			||||||
	 * requirement.
 | 
						 * requirement.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	setup_resource_ranges(domain, IORESOURCE_MEM, &ranges);
 | 
						allocate_toplevel_resources(domain, IORESOURCE_MEM);
 | 
				
			||||||
	allocate_child_resources(domain->link_list, &ranges,
 | 
					 | 
				
			||||||
				 IORESOURCE_TYPE_MASK, IORESOURCE_MEM);
 | 
					 | 
				
			||||||
	cleanup_domain_resource_ranges(domain, &ranges, IORESOURCE_MEM);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct device *child;
 | 
				
			||||||
	for (child = domain->link_list->children; child; child = child->sibling) {
 | 
						for (child = domain->link_list->children; child; child = child->sibling) {
 | 
				
			||||||
		if (!dev_has_children(child))
 | 
							if (!dev_has_children(child))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
@@ -537,12 +535,12 @@ static void allocate_domain_resources(const struct device *domain)
 | 
				
			|||||||
 * resource allocation for all immediate downstream devices is complete
 | 
					 * resource allocation for all immediate downstream devices is complete
 | 
				
			||||||
 * at the domain level, the resource allocator walks down the subtree
 | 
					 * at the domain level, the resource allocator walks down the subtree
 | 
				
			||||||
 * for each downstream bridge to continue the allocation process at the
 | 
					 * for each downstream bridge to continue the allocation process at the
 | 
				
			||||||
 * bridge level. Since bridges have separate windows for i/o, mem and
 | 
					 * bridge level. Since bridges have either their whole window allocated
 | 
				
			||||||
 * prefmem, best fit algorithm at bridge level looks for the biggest
 | 
					 * or nothing, we only need to place downstream resources inside these
 | 
				
			||||||
 * requirement considering prefmem resources separately from non-prefmem
 | 
					 * windows by re-using offsets that were pre-calculated in pass 1. This
 | 
				
			||||||
 * resources. This continues until resource allocation is performed for
 | 
					 * continues until resource allocation is realized for all downstream
 | 
				
			||||||
 * all downstream bridges in the domain sub-tree. This is referred to as
 | 
					 * bridges in the domain sub-tree. This is referred to as pass 2 of the
 | 
				
			||||||
 * pass 2 of the resource allocator.
 | 
					 * resource allocator.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Some rules that are followed by the resource allocator:
 | 
					 * Some rules that are followed by the resource allocator:
 | 
				
			||||||
 *  - Allocate resource locations for every device as long as
 | 
					 *  - Allocate resource locations for every device as long as
 | 
				
			||||||
@@ -566,8 +564,8 @@ void allocate_resources(const struct device *root)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		post_log_path(child);
 | 
							post_log_path(child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Pass 1 - Gather requirements. */
 | 
							/* Pass 1 - Relative placement. */
 | 
				
			||||||
		printk(BIOS_INFO, "=== Resource allocator: %s - Pass 1 (gathering requirements) ===\n",
 | 
							printk(BIOS_INFO, "=== Resource allocator: %s - Pass 1 (relative placement) ===\n",
 | 
				
			||||||
		       dev_path(child));
 | 
							       dev_path(child));
 | 
				
			||||||
		compute_domain_resources(child);
 | 
							compute_domain_resources(child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user