diff options
Diffstat (limited to 'src/device/resource_allocator_common.c')
-rw-r--r-- | src/device/resource_allocator_common.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/src/device/resource_allocator_common.c b/src/device/resource_allocator_common.c new file mode 100644 index 0000000000..202318bfe6 --- /dev/null +++ b/src/device/resource_allocator_common.c @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <device/device.h> + +struct pick_largest_state { + struct resource *last; + const struct device *result_dev; + struct resource *result; + int seen_last; +}; + +static void pick_largest_resource(void *gp, struct device *dev, + struct resource *resource) +{ + struct pick_largest_state *state = gp; + struct resource *last; + + last = state->last; + + /* Be certain to pick the successor to last. */ + if (resource == last) { + state->seen_last = 1; + return; + } + if (resource->flags & IORESOURCE_FIXED) + return; /* Skip it. */ + if (last && ((last->align < resource->align) || + ((last->align == resource->align) && + (last->size < resource->size)) || + ((last->align == resource->align) && + (last->size == resource->size) && (!state->seen_last)))) { + return; + } + if (!state->result || + (state->result->align < resource->align) || + ((state->result->align == resource->align) && + (state->result->size < resource->size))) { + state->result_dev = dev; + state->result = resource; + } +} + +const struct device *largest_resource(struct bus *bus, + struct resource **result_res, + unsigned long type_mask, + unsigned long type) +{ + struct pick_largest_state state; + + state.last = *result_res; + state.result_dev = NULL; + state.result = NULL; + state.seen_last = 0; + + search_bus_resources(bus, type_mask, type, pick_largest_resource, + &state); + + *result_res = state.result; + return state.result_dev; +} |