1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
227811d8cSYinghai Lu /*
327811d8cSYinghai Lu * Range add and subtract
427811d8cSYinghai Lu */
527811d8cSYinghai Lu #include <linux/init.h>
6*b296a6d5SAndy Shevchenko #include <linux/minmax.h>
7*b296a6d5SAndy Shevchenko #include <linux/printk.h>
827811d8cSYinghai Lu #include <linux/sort.h>
905418815SYinghai Lu #include <linux/string.h>
1027811d8cSYinghai Lu #include <linux/range.h>
1127811d8cSYinghai Lu
add_range(struct range * range,int az,int nr_range,u64 start,u64 end)1227811d8cSYinghai Lu int add_range(struct range *range, int az, int nr_range, u64 start, u64 end)
1327811d8cSYinghai Lu {
14e9a0064aSYinghai Lu if (start >= end)
1527811d8cSYinghai Lu return nr_range;
1627811d8cSYinghai Lu
1727811d8cSYinghai Lu /* Out of slots: */
1827811d8cSYinghai Lu if (nr_range >= az)
1927811d8cSYinghai Lu return nr_range;
2027811d8cSYinghai Lu
2127811d8cSYinghai Lu range[nr_range].start = start;
2227811d8cSYinghai Lu range[nr_range].end = end;
2327811d8cSYinghai Lu
2427811d8cSYinghai Lu nr_range++;
2527811d8cSYinghai Lu
2627811d8cSYinghai Lu return nr_range;
2727811d8cSYinghai Lu }
2827811d8cSYinghai Lu
add_range_with_merge(struct range * range,int az,int nr_range,u64 start,u64 end)2927811d8cSYinghai Lu int add_range_with_merge(struct range *range, int az, int nr_range,
3027811d8cSYinghai Lu u64 start, u64 end)
3127811d8cSYinghai Lu {
3227811d8cSYinghai Lu int i;
3327811d8cSYinghai Lu
34e9a0064aSYinghai Lu if (start >= end)
3527811d8cSYinghai Lu return nr_range;
3627811d8cSYinghai Lu
3705418815SYinghai Lu /* get new start/end: */
3827811d8cSYinghai Lu for (i = 0; i < nr_range; i++) {
3927811d8cSYinghai Lu u64 common_start, common_end;
4027811d8cSYinghai Lu
4127811d8cSYinghai Lu if (!range[i].end)
4227811d8cSYinghai Lu continue;
4327811d8cSYinghai Lu
4427811d8cSYinghai Lu common_start = max(range[i].start, start);
4527811d8cSYinghai Lu common_end = min(range[i].end, end);
46e9a0064aSYinghai Lu if (common_start > common_end)
4727811d8cSYinghai Lu continue;
4827811d8cSYinghai Lu
4905418815SYinghai Lu /* new start/end, will add it back at last */
5005418815SYinghai Lu start = min(range[i].start, start);
5105418815SYinghai Lu end = max(range[i].end, end);
5227811d8cSYinghai Lu
5305418815SYinghai Lu memmove(&range[i], &range[i + 1],
5405418815SYinghai Lu (nr_range - (i + 1)) * sizeof(range[i]));
5505418815SYinghai Lu range[nr_range - 1].start = 0;
5605418815SYinghai Lu range[nr_range - 1].end = 0;
5705418815SYinghai Lu nr_range--;
5805418815SYinghai Lu i--;
5927811d8cSYinghai Lu }
6027811d8cSYinghai Lu
6127811d8cSYinghai Lu /* Need to add it: */
6227811d8cSYinghai Lu return add_range(range, az, nr_range, start, end);
6327811d8cSYinghai Lu }
6427811d8cSYinghai Lu
subtract_range(struct range * range,int az,u64 start,u64 end)6527811d8cSYinghai Lu void subtract_range(struct range *range, int az, u64 start, u64 end)
6627811d8cSYinghai Lu {
6727811d8cSYinghai Lu int i, j;
6827811d8cSYinghai Lu
69e9a0064aSYinghai Lu if (start >= end)
7027811d8cSYinghai Lu return;
7127811d8cSYinghai Lu
7227811d8cSYinghai Lu for (j = 0; j < az; j++) {
7327811d8cSYinghai Lu if (!range[j].end)
7427811d8cSYinghai Lu continue;
7527811d8cSYinghai Lu
7627811d8cSYinghai Lu if (start <= range[j].start && end >= range[j].end) {
7727811d8cSYinghai Lu range[j].start = 0;
7827811d8cSYinghai Lu range[j].end = 0;
7927811d8cSYinghai Lu continue;
8027811d8cSYinghai Lu }
8127811d8cSYinghai Lu
8227811d8cSYinghai Lu if (start <= range[j].start && end < range[j].end &&
83e9a0064aSYinghai Lu range[j].start < end) {
84e9a0064aSYinghai Lu range[j].start = end;
8527811d8cSYinghai Lu continue;
8627811d8cSYinghai Lu }
8727811d8cSYinghai Lu
8827811d8cSYinghai Lu
8927811d8cSYinghai Lu if (start > range[j].start && end >= range[j].end &&
90e9a0064aSYinghai Lu range[j].end > start) {
91e9a0064aSYinghai Lu range[j].end = start;
9227811d8cSYinghai Lu continue;
9327811d8cSYinghai Lu }
9427811d8cSYinghai Lu
9527811d8cSYinghai Lu if (start > range[j].start && end < range[j].end) {
9627811d8cSYinghai Lu /* Find the new spare: */
9727811d8cSYinghai Lu for (i = 0; i < az; i++) {
9827811d8cSYinghai Lu if (range[i].end == 0)
9927811d8cSYinghai Lu break;
10027811d8cSYinghai Lu }
10127811d8cSYinghai Lu if (i < az) {
10227811d8cSYinghai Lu range[i].end = range[j].end;
103e9a0064aSYinghai Lu range[i].start = end;
10427811d8cSYinghai Lu } else {
1057fba2c27SLin Feng pr_err("%s: run out of slot in ranges\n",
1067fba2c27SLin Feng __func__);
10727811d8cSYinghai Lu }
108e9a0064aSYinghai Lu range[j].end = start;
10927811d8cSYinghai Lu continue;
11027811d8cSYinghai Lu }
11127811d8cSYinghai Lu }
11227811d8cSYinghai Lu }
11327811d8cSYinghai Lu
cmp_range(const void * x1,const void * x2)11427811d8cSYinghai Lu static int cmp_range(const void *x1, const void *x2)
11527811d8cSYinghai Lu {
11627811d8cSYinghai Lu const struct range *r1 = x1;
11727811d8cSYinghai Lu const struct range *r2 = x2;
11827811d8cSYinghai Lu
119fc7f0dd3SLouis Langholtz if (r1->start < r2->start)
120fc7f0dd3SLouis Langholtz return -1;
121fc7f0dd3SLouis Langholtz if (r1->start > r2->start)
122fc7f0dd3SLouis Langholtz return 1;
123fc7f0dd3SLouis Langholtz return 0;
12427811d8cSYinghai Lu }
12527811d8cSYinghai Lu
clean_sort_range(struct range * range,int az)12627811d8cSYinghai Lu int clean_sort_range(struct range *range, int az)
12727811d8cSYinghai Lu {
128834b4038SAlexey Khoroshilov int i, j, k = az - 1, nr_range = az;
12927811d8cSYinghai Lu
13027811d8cSYinghai Lu for (i = 0; i < k; i++) {
13127811d8cSYinghai Lu if (range[i].end)
13227811d8cSYinghai Lu continue;
13327811d8cSYinghai Lu for (j = k; j > i; j--) {
13427811d8cSYinghai Lu if (range[j].end) {
13527811d8cSYinghai Lu k = j;
13627811d8cSYinghai Lu break;
13727811d8cSYinghai Lu }
13827811d8cSYinghai Lu }
13927811d8cSYinghai Lu if (j == i)
14027811d8cSYinghai Lu break;
14127811d8cSYinghai Lu range[i].start = range[k].start;
14227811d8cSYinghai Lu range[i].end = range[k].end;
14327811d8cSYinghai Lu range[k].start = 0;
14427811d8cSYinghai Lu range[k].end = 0;
14527811d8cSYinghai Lu k--;
14627811d8cSYinghai Lu }
14727811d8cSYinghai Lu /* count it */
14827811d8cSYinghai Lu for (i = 0; i < az; i++) {
14927811d8cSYinghai Lu if (!range[i].end) {
15027811d8cSYinghai Lu nr_range = i;
15127811d8cSYinghai Lu break;
15227811d8cSYinghai Lu }
15327811d8cSYinghai Lu }
15427811d8cSYinghai Lu
15527811d8cSYinghai Lu /* sort them */
15627811d8cSYinghai Lu sort(range, nr_range, sizeof(struct range), cmp_range, NULL);
15727811d8cSYinghai Lu
15827811d8cSYinghai Lu return nr_range;
15927811d8cSYinghai Lu }
16027811d8cSYinghai Lu
sort_range(struct range * range,int nr_range)16127811d8cSYinghai Lu void sort_range(struct range *range, int nr_range)
16227811d8cSYinghai Lu {
16327811d8cSYinghai Lu /* sort them */
16427811d8cSYinghai Lu sort(range, nr_range, sizeof(struct range), cmp_range, NULL);
16527811d8cSYinghai Lu }
166