Angel Pons | 32859fc | 2020-04-02 23:48:27 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | /* This file is part of the coreboot project. */ |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 3 | #ifndef MEMRANGE_H_ |
| 4 | #define MEMRANGE_H_ |
| 5 | |
| 6 | #include <device/resource.h> |
Furquan Shaikh | 9c6274c | 2020-03-11 19:06:24 -0700 | [diff] [blame] | 7 | #include <stdbool.h> |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 8 | |
| 9 | /* A memranges structure consists of a list of range_entry(s). The structure |
| 10 | * is exposed so that a memranges can be used on the stack if needed. */ |
| 11 | struct memranges { |
| 12 | struct range_entry *entries; |
Martin Roth | e18e642 | 2017-06-03 20:03:18 -0600 | [diff] [blame] | 13 | /* coreboot doesn't have a free() function. Therefore, keep a cache of |
Aaron Durbin | 1b915b8 | 2016-01-15 21:59:37 -0600 | [diff] [blame] | 14 | * free'd entries. */ |
| 15 | struct range_entry *free_list; |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 16 | /* Alignment(log 2) for base and end addresses of the range. */ |
| 17 | unsigned char align; |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 18 | }; |
| 19 | |
| 20 | /* Each region within a memranges structure is represented by a |
| 21 | * range_entry structure. Use the associated range_entry_(base|end|size|tag) |
| 22 | * functions to interrogate its properties. i.e. don't rely on one's own |
| 23 | * interpretation of the fields. */ |
| 24 | struct range_entry { |
| 25 | resource_t begin; |
| 26 | resource_t end; |
| 27 | unsigned long tag; |
| 28 | struct range_entry *next; |
| 29 | }; |
| 30 | |
Aaron Durbin | e884592 | 2016-03-08 10:47:18 -0600 | [diff] [blame] | 31 | /* Initialize a range_entry with inclusive beginning address and exclusive |
| 32 | * end address along with the appropriate tag. */ |
| 33 | static inline void range_entry_init(struct range_entry *re, |
| 34 | resource_t incl_begin, resource_t excl_end, |
| 35 | unsigned long tag) |
| 36 | { |
| 37 | re->begin = incl_begin; |
| 38 | re->end = excl_end - 1; |
| 39 | re->tag = tag; |
| 40 | re->next = NULL; |
| 41 | } |
| 42 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 43 | /* Return inclusive base address of memory range. */ |
| 44 | static inline resource_t range_entry_base(const struct range_entry *r) |
| 45 | { |
| 46 | return r->begin; |
| 47 | } |
| 48 | |
| 49 | /* Return exclusive end address of memory range. */ |
| 50 | static inline resource_t range_entry_end(const struct range_entry *r) |
| 51 | { |
| 52 | return r->end + 1; |
| 53 | } |
| 54 | |
| 55 | /* Return size of of memory range. */ |
| 56 | static inline resource_t range_entry_size(const struct range_entry *r) |
| 57 | { |
| 58 | return r->end - r->begin + 1; |
| 59 | } |
| 60 | |
| 61 | static inline unsigned long range_entry_tag(const struct range_entry *r) |
| 62 | { |
| 63 | return r->tag; |
| 64 | } |
| 65 | |
Aaron Durbin | f6f6e13 | 2013-03-26 21:22:42 -0500 | [diff] [blame] | 66 | static inline void range_entry_update_tag(struct range_entry *r, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 67 | unsigned long new_tag) |
Aaron Durbin | f6f6e13 | 2013-03-26 21:22:42 -0500 | [diff] [blame] | 68 | { |
| 69 | r->tag = new_tag; |
| 70 | } |
| 71 | |
Furquan Shaikh | 2190a63 | 2020-03-12 16:43:49 -0700 | [diff] [blame] | 72 | static inline bool memranges_is_empty(struct memranges *ranges) |
| 73 | { |
| 74 | return ranges->entries == NULL; |
| 75 | } |
| 76 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 77 | /* Iterate over each entry in a memranges structure. Ranges cannot |
| 78 | * be deleted while processing each entry as the list cannot be safely |
| 79 | * traversed after such an operation. |
| 80 | * r - range_entry pointer. |
| 81 | * ranges - memranges pointer */ |
| 82 | #define memranges_each_entry(r, ranges) \ |
| 83 | for (r = (ranges)->entries; r != NULL; r = r->next) |
| 84 | |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 85 | |
Aaron Durbin | 1b915b8 | 2016-01-15 21:59:37 -0600 | [diff] [blame] | 86 | /* Initialize memranges structure providing an optional array of range_entry |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 87 | * to use as the free list. Additionally, it accepts an align parameter that |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 88 | * represents the required alignment(log 2) of addresses. */ |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 89 | void memranges_init_empty_with_alignment(struct memranges *ranges, |
| 90 | struct range_entry *free, |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 91 | size_t num_free, unsigned char align); |
Furquan Shaikh | 196ee2b | 2014-07-18 10:25:54 -0700 | [diff] [blame] | 92 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 93 | /* Initialize and fill a memranges structure according to the |
| 94 | * mask and match type for all memory resources. Tag each entry with the |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 95 | * specified type. Additionally, it accepts an align parameter that |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 96 | * represents the required alignment(log 2) of addresses. */ |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 97 | void memranges_init_with_alignment(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 98 | unsigned long mask, unsigned long match, |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 99 | unsigned long tag, unsigned char align); |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 100 | |
| 101 | /* Initialize memranges structure providing an optional array of range_entry |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 102 | * to use as the free list. Addresses are default aligned to 4KiB(2^12). */ |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 103 | #define memranges_init_empty(__ranges, __free, __num_free) \ |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 104 | memranges_init_empty_with_alignment(__ranges, __free, __num_free, 12); |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 105 | |
| 106 | /* Initialize and fill a memranges structure according to the |
| 107 | * mask and match type for all memory resources. Tag each entry with the |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 108 | * specified type. Addresses are default aligned to 4KiB(2^12). */ |
Furquan Shaikh | 1429092 | 2020-03-11 14:35:35 -0700 | [diff] [blame] | 109 | #define memranges_init(__ranges, __mask, __match, __tag) \ |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 110 | memranges_init_with_alignment(__ranges, __mask, __match, __tag, 12); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 111 | |
Patrick Rudolph | d67a4bd | 2018-04-10 09:31:10 +0200 | [diff] [blame] | 112 | /* Clone a memrange. The new memrange has the same entries as the old one. */ |
| 113 | void memranges_clone(struct memranges *newranges, struct memranges *oldranges); |
| 114 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 115 | /* Remove and free all entries within the memranges structure. */ |
| 116 | void memranges_teardown(struct memranges *ranges); |
| 117 | |
| 118 | /* Add memory resources that match with the corresponding mask and match. |
| 119 | * Each entry will be tagged with the provided tag. e.g. To populate |
| 120 | * all cacheable memory resources in the range: |
| 121 | * memranges_add_resources(range, IORESOURCE_CACHEABLE, |
| 122 | * IORESROUCE_CACHEABLE, my_cacheable_tag); */ |
| 123 | void memranges_add_resources(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 124 | unsigned long mask, unsigned long match, |
| 125 | unsigned long tag); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 126 | |
Aaron Durbin | ca4f4b8 | 2014-02-08 15:41:52 -0600 | [diff] [blame] | 127 | /* Add memory resources that match with the corresponding mask and match but |
| 128 | * also provide filter as additional check. The filter will return non-zero |
| 129 | * to add the resource or zero to not add the resource. Each entry will be |
| 130 | * tagged with the provided tag. e.g. To populate all cacheable memory |
| 131 | * resources in the range with a filter: |
| 132 | * memranges_add_resources_filter(range, IORESOURCE_CACHEABLE, |
| 133 | * IORESROUCE_CACHEABLE, my_cacheable_tag, filter); */ |
| 134 | typedef int (*memrange_filter_t)(struct device *dev, struct resource *res); |
| 135 | void memranges_add_resources_filter(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 136 | unsigned long mask, unsigned long match, |
| 137 | unsigned long tag, |
| 138 | memrange_filter_t filter); |
Aaron Durbin | ca4f4b8 | 2014-02-08 15:41:52 -0600 | [diff] [blame] | 139 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 140 | /* Fill all address ranges up to limit (exclusive) not covered by an entry by |
| 141 | * inserting new entries with the provided tag. */ |
| 142 | void memranges_fill_holes_up_to(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 143 | resource_t limit, unsigned long tag); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 144 | |
| 145 | /* Create a hole in the range by deleting/modifying entries that overlap with |
| 146 | * the region specified by base and size. */ |
| 147 | void memranges_create_hole(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 148 | resource_t base, resource_t size); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 149 | |
| 150 | /* Insert a resource to the given memranges. All existing ranges |
| 151 | * covered by range specified by base and size will be removed before a |
| 152 | * new one is added. */ |
| 153 | void memranges_insert(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 154 | resource_t base, resource_t size, unsigned long tag); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 155 | |
Aaron Durbin | ed9307d | 2014-02-05 15:44:30 -0600 | [diff] [blame] | 156 | /* Update all entries with old_tag to new_tag. */ |
| 157 | void memranges_update_tag(struct memranges *ranges, unsigned long old_tag, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 158 | unsigned long new_tag); |
Aaron Durbin | ed9307d | 2014-02-05 15:44:30 -0600 | [diff] [blame] | 159 | |
Aaron Durbin | f6f6e13 | 2013-03-26 21:22:42 -0500 | [diff] [blame] | 160 | /* Returns next entry after the provided entry. NULL if r is last. */ |
| 161 | struct range_entry *memranges_next_entry(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 162 | const struct range_entry *r); |
Furquan Shaikh | 9c6274c | 2020-03-11 19:06:24 -0700 | [diff] [blame] | 163 | |
| 164 | /* Steals memory from the available list in given ranges as per the constraints: |
| 165 | * limit = Upper bound for the memory range to steal. |
| 166 | * size = Requested size for the stolen memory. |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 167 | * align = Required alignment(log 2) for the starting address of the stolen memory. |
Furquan Shaikh | 9c6274c | 2020-03-11 19:06:24 -0700 | [diff] [blame] | 168 | * tag = Use a range that matches the given tag. |
| 169 | * |
| 170 | * If the constraints can be satisfied, this function creates a hole in the memrange, |
| 171 | * writes the base address of that hole to stolen_base and returns true. Otherwise it returns |
| 172 | * false. */ |
Furquan Shaikh | 1908340 | 2020-03-24 14:56:38 -0700 | [diff] [blame] | 173 | bool memranges_steal(struct memranges *ranges, resource_t limit, resource_t size, |
| 174 | unsigned char align, unsigned long tag, resource_t *stolen_base); |
Furquan Shaikh | 9c6274c | 2020-03-11 19:06:24 -0700 | [diff] [blame] | 175 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 176 | #endif /* MEMRANGE_H_ */ |