xref: /aosp_15_r20/external/coreboot/src/device/resource_allocator_common.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/device.h>
4 #include <stddef.h>
5 
6 struct pick_largest_state {
7 	struct resource *last;
8 	const struct device *result_dev;
9 	struct resource *result;
10 	int seen_last;
11 };
12 
pick_largest_resource(void * gp,struct device * dev,struct resource * resource)13 static void pick_largest_resource(void *gp, struct device *dev,
14 				  struct resource *resource)
15 {
16 	struct pick_largest_state *state = gp;
17 	struct resource *last;
18 
19 	last = state->last;
20 
21 	/* Be certain to pick the successor to last. */
22 	if (resource == last) {
23 		state->seen_last = 1;
24 		return;
25 	}
26 	if (resource->flags & IORESOURCE_FIXED)
27 		return;	/* Skip it. */
28 	if (last && ((last->align < resource->align) ||
29 		     ((last->align == resource->align) &&
30 		      (last->size < resource->size)) ||
31 		     ((last->align == resource->align) &&
32 		      (last->size == resource->size) && (!state->seen_last)))) {
33 		return;
34 	}
35 	if (!state->result ||
36 	    (state->result->align < resource->align) ||
37 	    ((state->result->align == resource->align) &&
38 	     (state->result->size < resource->size))) {
39 		state->result_dev = dev;
40 		state->result = resource;
41 	}
42 }
43 
largest_resource(struct bus * bus,struct resource ** result_res,unsigned long type_mask,unsigned long type)44 const struct device *largest_resource(struct bus *bus,
45 				      struct resource **result_res,
46 				      unsigned long type_mask,
47 				      unsigned long type)
48 {
49 	struct pick_largest_state state;
50 
51 	state.last = *result_res;
52 	state.result_dev = NULL;
53 	state.result = NULL;
54 	state.seen_last = 0;
55 
56 	search_bus_resources(bus, type_mask, type, pick_largest_resource,
57 			     &state);
58 
59 	*result_res = state.result;
60 	return state.result_dev;
61 }
62