Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2013 Google, Inc. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 14 | */ |
| 15 | #ifndef MEMRANGE_H_ |
| 16 | #define MEMRANGE_H_ |
| 17 | |
| 18 | #include <device/resource.h> |
| 19 | |
| 20 | /* A memranges structure consists of a list of range_entry(s). The structure |
| 21 | * is exposed so that a memranges can be used on the stack if needed. */ |
| 22 | struct memranges { |
| 23 | struct range_entry *entries; |
Aaron Durbin | 1b915b8 | 2016-01-15 21:59:37 -0600 | [diff] [blame] | 24 | /* Coreboot doesn't have a free() function. Therefore, keep a cache of |
| 25 | * free'd entries. */ |
| 26 | struct range_entry *free_list; |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 27 | }; |
| 28 | |
| 29 | /* Each region within a memranges structure is represented by a |
| 30 | * range_entry structure. Use the associated range_entry_(base|end|size|tag) |
| 31 | * functions to interrogate its properties. i.e. don't rely on one's own |
| 32 | * interpretation of the fields. */ |
| 33 | struct range_entry { |
| 34 | resource_t begin; |
| 35 | resource_t end; |
| 36 | unsigned long tag; |
| 37 | struct range_entry *next; |
| 38 | }; |
| 39 | |
Aaron Durbin | e884592 | 2016-03-08 10:47:18 -0600 | [diff] [blame] | 40 | /* Initialize a range_entry with inclusive beginning address and exclusive |
| 41 | * end address along with the appropriate tag. */ |
| 42 | static inline void range_entry_init(struct range_entry *re, |
| 43 | resource_t incl_begin, resource_t excl_end, |
| 44 | unsigned long tag) |
| 45 | { |
| 46 | re->begin = incl_begin; |
| 47 | re->end = excl_end - 1; |
| 48 | re->tag = tag; |
| 49 | re->next = NULL; |
| 50 | } |
| 51 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 52 | /* Return inclusive base address of memory range. */ |
| 53 | static inline resource_t range_entry_base(const struct range_entry *r) |
| 54 | { |
| 55 | return r->begin; |
| 56 | } |
| 57 | |
| 58 | /* Return exclusive end address of memory range. */ |
| 59 | static inline resource_t range_entry_end(const struct range_entry *r) |
| 60 | { |
| 61 | return r->end + 1; |
| 62 | } |
| 63 | |
| 64 | /* Return size of of memory range. */ |
| 65 | static inline resource_t range_entry_size(const struct range_entry *r) |
| 66 | { |
| 67 | return r->end - r->begin + 1; |
| 68 | } |
| 69 | |
| 70 | static inline unsigned long range_entry_tag(const struct range_entry *r) |
| 71 | { |
| 72 | return r->tag; |
| 73 | } |
| 74 | |
Aaron Durbin | f6f6e13 | 2013-03-26 21:22:42 -0500 | [diff] [blame] | 75 | static inline void range_entry_update_tag(struct range_entry *r, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 76 | unsigned long new_tag) |
Aaron Durbin | f6f6e13 | 2013-03-26 21:22:42 -0500 | [diff] [blame] | 77 | { |
| 78 | r->tag = new_tag; |
| 79 | } |
| 80 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 81 | /* Iterate over each entry in a memranges structure. Ranges cannot |
| 82 | * be deleted while processing each entry as the list cannot be safely |
| 83 | * traversed after such an operation. |
| 84 | * r - range_entry pointer. |
| 85 | * ranges - memranges pointer */ |
| 86 | #define memranges_each_entry(r, ranges) \ |
| 87 | for (r = (ranges)->entries; r != NULL; r = r->next) |
| 88 | |
Aaron Durbin | 1b915b8 | 2016-01-15 21:59:37 -0600 | [diff] [blame] | 89 | /* Initialize memranges structure providing an optional array of range_entry |
| 90 | * to use as the free list. */ |
| 91 | void memranges_init_empty(struct memranges *ranges, struct range_entry *free, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 92 | size_t num_free); |
Furquan Shaikh | 196ee2b | 2014-07-18 10:25:54 -0700 | [diff] [blame] | 93 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 94 | /* Initialize and fill a memranges structure according to the |
| 95 | * mask and match type for all memory resources. Tag each entry with the |
| 96 | * specified type. */ |
| 97 | void memranges_init(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 98 | unsigned long mask, unsigned long match, |
| 99 | unsigned long tag); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 100 | |
| 101 | /* Remove and free all entries within the memranges structure. */ |
| 102 | void memranges_teardown(struct memranges *ranges); |
| 103 | |
| 104 | /* Add memory resources that match with the corresponding mask and match. |
| 105 | * Each entry will be tagged with the provided tag. e.g. To populate |
| 106 | * all cacheable memory resources in the range: |
| 107 | * memranges_add_resources(range, IORESOURCE_CACHEABLE, |
| 108 | * IORESROUCE_CACHEABLE, my_cacheable_tag); */ |
| 109 | void memranges_add_resources(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 110 | unsigned long mask, unsigned long match, |
| 111 | unsigned long tag); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 112 | |
Aaron Durbin | ca4f4b8 | 2014-02-08 15:41:52 -0600 | [diff] [blame] | 113 | /* Add memory resources that match with the corresponding mask and match but |
| 114 | * also provide filter as additional check. The filter will return non-zero |
| 115 | * to add the resource or zero to not add the resource. Each entry will be |
| 116 | * tagged with the provided tag. e.g. To populate all cacheable memory |
| 117 | * resources in the range with a filter: |
| 118 | * memranges_add_resources_filter(range, IORESOURCE_CACHEABLE, |
| 119 | * IORESROUCE_CACHEABLE, my_cacheable_tag, filter); */ |
| 120 | typedef int (*memrange_filter_t)(struct device *dev, struct resource *res); |
| 121 | void memranges_add_resources_filter(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 122 | unsigned long mask, unsigned long match, |
| 123 | unsigned long tag, |
| 124 | memrange_filter_t filter); |
Aaron Durbin | ca4f4b8 | 2014-02-08 15:41:52 -0600 | [diff] [blame] | 125 | |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 126 | /* Fill all address ranges up to limit (exclusive) not covered by an entry by |
| 127 | * inserting new entries with the provided tag. */ |
| 128 | void memranges_fill_holes_up_to(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 129 | resource_t limit, unsigned long tag); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 130 | |
| 131 | /* Create a hole in the range by deleting/modifying entries that overlap with |
| 132 | * the region specified by base and size. */ |
| 133 | void memranges_create_hole(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 134 | resource_t base, resource_t size); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 135 | |
| 136 | /* Insert a resource to the given memranges. All existing ranges |
| 137 | * covered by range specified by base and size will be removed before a |
| 138 | * new one is added. */ |
| 139 | void memranges_insert(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 140 | resource_t base, resource_t size, unsigned long tag); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 141 | |
Aaron Durbin | ed9307d | 2014-02-05 15:44:30 -0600 | [diff] [blame] | 142 | /* Update all entries with old_tag to new_tag. */ |
| 143 | void memranges_update_tag(struct memranges *ranges, unsigned long old_tag, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 144 | unsigned long new_tag); |
Aaron Durbin | ed9307d | 2014-02-05 15:44:30 -0600 | [diff] [blame] | 145 | |
Aaron Durbin | f6f6e13 | 2013-03-26 21:22:42 -0500 | [diff] [blame] | 146 | /* Returns next entry after the provided entry. NULL if r is last. */ |
| 147 | struct range_entry *memranges_next_entry(struct memranges *ranges, |
Lee Leahy | 708fc27 | 2017-03-07 12:18:53 -0800 | [diff] [blame] | 148 | const struct range_entry *r); |
Aaron Durbin | a05a852 | 2013-03-22 20:44:46 -0500 | [diff] [blame] | 149 | #endif /* MEMRANGE_H_ */ |