1 /* 2 * Range add and subtract 3 */ 4 #include <linux/kernel.h> 5 #include <linux/init.h> 6 #include <linux/sort.h> 7 #include <linux/string.h> 8 #include <linux/range.h> 9 10 int add_range(struct range *range, int az, int nr_range, u64 start, u64 end) 11 { 12 if (start >= end) 13 return nr_range; 14 15 /* Out of slots: */ 16 if (nr_range >= az) 17 return nr_range; 18 19 range[nr_range].start = start; 20 range[nr_range].end = end; 21 22 nr_range++; 23 24 return nr_range; 25 } 26 27 int add_range_with_merge(struct range *range, int az, int nr_range, 28 u64 start, u64 end) 29 { 30 int i; 31 32 if (start >= end) 33 return nr_range; 34 35 /* get new start/end: */ 36 for (i = 0; i < nr_range; i++) { 37 u64 common_start, common_end; 38 39 if (!range[i].end) 40 continue; 41 42 common_start = max(range[i].start, start); 43 common_end = min(range[i].end, end); 44 if (common_start > common_end) 45 continue; 46 47 /* new start/end, will add it back at last */ 48 start = min(range[i].start, start); 49 end = max(range[i].end, end); 50 51 memmove(&range[i], &range[i + 1], 52 (nr_range - (i + 1)) * sizeof(range[i])); 53 range[nr_range - 1].start = 0; 54 range[nr_range - 1].end = 0; 55 nr_range--; 56 i--; 57 } 58 59 /* Need to add it: */ 60 return add_range(range, az, nr_range, start, end); 61 } 62 63 void subtract_range(struct range *range, int az, u64 start, u64 end) 64 { 65 int i, j; 66 67 if (start >= end) 68 return; 69 70 for (j = 0; j < az; j++) { 71 if (!range[j].end) 72 continue; 73 74 if (start <= range[j].start && end >= range[j].end) { 75 range[j].start = 0; 76 range[j].end = 0; 77 continue; 78 } 79 80 if (start <= range[j].start && end < range[j].end && 81 range[j].start < end) { 82 range[j].start = end; 83 continue; 84 } 85 86 87 if (start > range[j].start && end >= range[j].end && 88 range[j].end > start) { 89 range[j].end = start; 90 continue; 91 } 92 93 if (start > range[j].start && end < range[j].end) { 94 /* Find the new spare: */ 95 for (i = 0; i < az; i++) { 96 if (range[i].end == 0) 97 break; 98 } 99 if (i < az) { 100 range[i].end = range[j].end; 101 range[i].start = end; 102 } else { 103 pr_err("%s: run out of slot in ranges\n", 104 __func__); 105 } 106 range[j].end = start; 107 continue; 108 } 109 } 110 } 111 112 static int cmp_range(const void *x1, const void *x2) 113 { 114 const struct range *r1 = x1; 115 const struct range *r2 = x2; 116 117 if (r1->start < r2->start) 118 return -1; 119 if (r1->start > r2->start) 120 return 1; 121 return 0; 122 } 123 124 int clean_sort_range(struct range *range, int az) 125 { 126 int i, j, k = az - 1, nr_range = az; 127 128 for (i = 0; i < k; i++) { 129 if (range[i].end) 130 continue; 131 for (j = k; j > i; j--) { 132 if (range[j].end) { 133 k = j; 134 break; 135 } 136 } 137 if (j == i) 138 break; 139 range[i].start = range[k].start; 140 range[i].end = range[k].end; 141 range[k].start = 0; 142 range[k].end = 0; 143 k--; 144 } 145 /* count it */ 146 for (i = 0; i < az; i++) { 147 if (!range[i].end) { 148 nr_range = i; 149 break; 150 } 151 } 152 153 /* sort them */ 154 sort(range, nr_range, sizeof(struct range), cmp_range, NULL); 155 156 return nr_range; 157 } 158 159 void sort_range(struct range *range, int nr_range) 160 { 161 /* sort them */ 162 sort(range, nr_range, sizeof(struct range), cmp_range, NULL); 163 } 164