xref: /rk3399_rockchip-uboot/lib/list_sort.c (revision 42817eb85de1d7dec399c75dbd133ea6b5351a72)
1*c068d44aSHeiko Schocher #ifndef __UBOOT__
2*c068d44aSHeiko Schocher #include <linux/kernel.h>
3*c068d44aSHeiko Schocher #include <linux/module.h>
4*c068d44aSHeiko Schocher #include <linux/slab.h>
5*c068d44aSHeiko Schocher #else
6*c068d44aSHeiko Schocher #include <linux/compat.h>
7*c068d44aSHeiko Schocher #include <common.h>
8*c068d44aSHeiko Schocher #include <malloc.h>
9*c068d44aSHeiko Schocher #endif
10*c068d44aSHeiko Schocher #include <linux/list.h>
11*c068d44aSHeiko Schocher #include <linux/list_sort.h>
12*c068d44aSHeiko Schocher 
13*c068d44aSHeiko Schocher #define MAX_LIST_LENGTH_BITS 20
14*c068d44aSHeiko Schocher 
15*c068d44aSHeiko Schocher /*
16*c068d44aSHeiko Schocher  * Returns a list organized in an intermediate format suited
17*c068d44aSHeiko Schocher  * to chaining of merge() calls: null-terminated, no reserved or
18*c068d44aSHeiko Schocher  * sentinel head node, "prev" links not maintained.
19*c068d44aSHeiko Schocher  */
merge(void * priv,int (* cmp)(void * priv,struct list_head * a,struct list_head * b),struct list_head * a,struct list_head * b)20*c068d44aSHeiko Schocher static struct list_head *merge(void *priv,
21*c068d44aSHeiko Schocher 				int (*cmp)(void *priv, struct list_head *a,
22*c068d44aSHeiko Schocher 					struct list_head *b),
23*c068d44aSHeiko Schocher 				struct list_head *a, struct list_head *b)
24*c068d44aSHeiko Schocher {
25*c068d44aSHeiko Schocher 	struct list_head head, *tail = &head;
26*c068d44aSHeiko Schocher 
27*c068d44aSHeiko Schocher 	while (a && b) {
28*c068d44aSHeiko Schocher 		/* if equal, take 'a' -- important for sort stability */
29*c068d44aSHeiko Schocher 		if ((*cmp)(priv, a, b) <= 0) {
30*c068d44aSHeiko Schocher 			tail->next = a;
31*c068d44aSHeiko Schocher 			a = a->next;
32*c068d44aSHeiko Schocher 		} else {
33*c068d44aSHeiko Schocher 			tail->next = b;
34*c068d44aSHeiko Schocher 			b = b->next;
35*c068d44aSHeiko Schocher 		}
36*c068d44aSHeiko Schocher 		tail = tail->next;
37*c068d44aSHeiko Schocher 	}
38*c068d44aSHeiko Schocher 	tail->next = a?:b;
39*c068d44aSHeiko Schocher 	return head.next;
40*c068d44aSHeiko Schocher }
41*c068d44aSHeiko Schocher 
42*c068d44aSHeiko Schocher /*
43*c068d44aSHeiko Schocher  * Combine final list merge with restoration of standard doubly-linked
44*c068d44aSHeiko Schocher  * list structure.  This approach duplicates code from merge(), but
45*c068d44aSHeiko Schocher  * runs faster than the tidier alternatives of either a separate final
46*c068d44aSHeiko Schocher  * prev-link restoration pass, or maintaining the prev links
47*c068d44aSHeiko Schocher  * throughout.
48*c068d44aSHeiko Schocher  */
merge_and_restore_back_links(void * priv,int (* cmp)(void * priv,struct list_head * a,struct list_head * b),struct list_head * head,struct list_head * a,struct list_head * b)49*c068d44aSHeiko Schocher static void merge_and_restore_back_links(void *priv,
50*c068d44aSHeiko Schocher 				int (*cmp)(void *priv, struct list_head *a,
51*c068d44aSHeiko Schocher 					struct list_head *b),
52*c068d44aSHeiko Schocher 				struct list_head *head,
53*c068d44aSHeiko Schocher 				struct list_head *a, struct list_head *b)
54*c068d44aSHeiko Schocher {
55*c068d44aSHeiko Schocher 	struct list_head *tail = head;
56*c068d44aSHeiko Schocher 
57*c068d44aSHeiko Schocher 	while (a && b) {
58*c068d44aSHeiko Schocher 		/* if equal, take 'a' -- important for sort stability */
59*c068d44aSHeiko Schocher 		if ((*cmp)(priv, a, b) <= 0) {
60*c068d44aSHeiko Schocher 			tail->next = a;
61*c068d44aSHeiko Schocher 			a->prev = tail;
62*c068d44aSHeiko Schocher 			a = a->next;
63*c068d44aSHeiko Schocher 		} else {
64*c068d44aSHeiko Schocher 			tail->next = b;
65*c068d44aSHeiko Schocher 			b->prev = tail;
66*c068d44aSHeiko Schocher 			b = b->next;
67*c068d44aSHeiko Schocher 		}
68*c068d44aSHeiko Schocher 		tail = tail->next;
69*c068d44aSHeiko Schocher 	}
70*c068d44aSHeiko Schocher 	tail->next = a ? : b;
71*c068d44aSHeiko Schocher 
72*c068d44aSHeiko Schocher 	do {
73*c068d44aSHeiko Schocher 		/*
74*c068d44aSHeiko Schocher 		 * In worst cases this loop may run many iterations.
75*c068d44aSHeiko Schocher 		 * Continue callbacks to the client even though no
76*c068d44aSHeiko Schocher 		 * element comparison is needed, so the client's cmp()
77*c068d44aSHeiko Schocher 		 * routine can invoke cond_resched() periodically.
78*c068d44aSHeiko Schocher 		 */
79*c068d44aSHeiko Schocher 		(*cmp)(priv, tail->next, tail->next);
80*c068d44aSHeiko Schocher 
81*c068d44aSHeiko Schocher 		tail->next->prev = tail;
82*c068d44aSHeiko Schocher 		tail = tail->next;
83*c068d44aSHeiko Schocher 	} while (tail->next);
84*c068d44aSHeiko Schocher 
85*c068d44aSHeiko Schocher 	tail->next = head;
86*c068d44aSHeiko Schocher 	head->prev = tail;
87*c068d44aSHeiko Schocher }
88*c068d44aSHeiko Schocher 
89*c068d44aSHeiko Schocher /**
90*c068d44aSHeiko Schocher  * list_sort - sort a list
91*c068d44aSHeiko Schocher  * @priv: private data, opaque to list_sort(), passed to @cmp
92*c068d44aSHeiko Schocher  * @head: the list to sort
93*c068d44aSHeiko Schocher  * @cmp: the elements comparison function
94*c068d44aSHeiko Schocher  *
95*c068d44aSHeiko Schocher  * This function implements "merge sort", which has O(nlog(n))
96*c068d44aSHeiko Schocher  * complexity.
97*c068d44aSHeiko Schocher  *
98*c068d44aSHeiko Schocher  * The comparison function @cmp must return a negative value if @a
99*c068d44aSHeiko Schocher  * should sort before @b, and a positive value if @a should sort after
100*c068d44aSHeiko Schocher  * @b. If @a and @b are equivalent, and their original relative
101*c068d44aSHeiko Schocher  * ordering is to be preserved, @cmp must return 0.
102*c068d44aSHeiko Schocher  */
list_sort(void * priv,struct list_head * head,int (* cmp)(void * priv,struct list_head * a,struct list_head * b))103*c068d44aSHeiko Schocher void list_sort(void *priv, struct list_head *head,
104*c068d44aSHeiko Schocher 		int (*cmp)(void *priv, struct list_head *a,
105*c068d44aSHeiko Schocher 			struct list_head *b))
106*c068d44aSHeiko Schocher {
107*c068d44aSHeiko Schocher 	struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
108*c068d44aSHeiko Schocher 						-- last slot is a sentinel */
109*c068d44aSHeiko Schocher 	int lev;  /* index into part[] */
110*c068d44aSHeiko Schocher 	int max_lev = 0;
111*c068d44aSHeiko Schocher 	struct list_head *list;
112*c068d44aSHeiko Schocher 
113*c068d44aSHeiko Schocher 	if (list_empty(head))
114*c068d44aSHeiko Schocher 		return;
115*c068d44aSHeiko Schocher 
116*c068d44aSHeiko Schocher 	memset(part, 0, sizeof(part));
117*c068d44aSHeiko Schocher 
118*c068d44aSHeiko Schocher 	head->prev->next = NULL;
119*c068d44aSHeiko Schocher 	list = head->next;
120*c068d44aSHeiko Schocher 
121*c068d44aSHeiko Schocher 	while (list) {
122*c068d44aSHeiko Schocher 		struct list_head *cur = list;
123*c068d44aSHeiko Schocher 		list = list->next;
124*c068d44aSHeiko Schocher 		cur->next = NULL;
125*c068d44aSHeiko Schocher 
126*c068d44aSHeiko Schocher 		for (lev = 0; part[lev]; lev++) {
127*c068d44aSHeiko Schocher 			cur = merge(priv, cmp, part[lev], cur);
128*c068d44aSHeiko Schocher 			part[lev] = NULL;
129*c068d44aSHeiko Schocher 		}
130*c068d44aSHeiko Schocher 		if (lev > max_lev) {
131*c068d44aSHeiko Schocher 			if (unlikely(lev >= ARRAY_SIZE(part)-1)) {
132*c068d44aSHeiko Schocher 				printk_once(KERN_DEBUG "list passed to"
133*c068d44aSHeiko Schocher 					" list_sort() too long for"
134*c068d44aSHeiko Schocher 					" efficiency\n");
135*c068d44aSHeiko Schocher 				lev--;
136*c068d44aSHeiko Schocher 			}
137*c068d44aSHeiko Schocher 			max_lev = lev;
138*c068d44aSHeiko Schocher 		}
139*c068d44aSHeiko Schocher 		part[lev] = cur;
140*c068d44aSHeiko Schocher 	}
141*c068d44aSHeiko Schocher 
142*c068d44aSHeiko Schocher 	for (lev = 0; lev < max_lev; lev++)
143*c068d44aSHeiko Schocher 		if (part[lev])
144*c068d44aSHeiko Schocher 			list = merge(priv, cmp, part[lev], list);
145*c068d44aSHeiko Schocher 
146*c068d44aSHeiko Schocher 	merge_and_restore_back_links(priv, cmp, head, part[max_lev], list);
147*c068d44aSHeiko Schocher }
148*c068d44aSHeiko Schocher EXPORT_SYMBOL(list_sort);
149*c068d44aSHeiko Schocher 
150*c068d44aSHeiko Schocher #ifdef CONFIG_TEST_LIST_SORT
151*c068d44aSHeiko Schocher 
152*c068d44aSHeiko Schocher #include <linux/random.h>
153*c068d44aSHeiko Schocher 
154*c068d44aSHeiko Schocher /*
155*c068d44aSHeiko Schocher  * The pattern of set bits in the list length determines which cases
156*c068d44aSHeiko Schocher  * are hit in list_sort().
157*c068d44aSHeiko Schocher  */
158*c068d44aSHeiko Schocher #define TEST_LIST_LEN (512+128+2) /* not including head */
159*c068d44aSHeiko Schocher 
160*c068d44aSHeiko Schocher #define TEST_POISON1 0xDEADBEEF
161*c068d44aSHeiko Schocher #define TEST_POISON2 0xA324354C
162*c068d44aSHeiko Schocher 
163*c068d44aSHeiko Schocher struct debug_el {
164*c068d44aSHeiko Schocher 	unsigned int poison1;
165*c068d44aSHeiko Schocher 	struct list_head list;
166*c068d44aSHeiko Schocher 	unsigned int poison2;
167*c068d44aSHeiko Schocher 	int value;
168*c068d44aSHeiko Schocher 	unsigned serial;
169*c068d44aSHeiko Schocher };
170*c068d44aSHeiko Schocher 
171*c068d44aSHeiko Schocher /* Array, containing pointers to all elements in the test list */
172*c068d44aSHeiko Schocher static struct debug_el **elts __initdata;
173*c068d44aSHeiko Schocher 
check(struct debug_el * ela,struct debug_el * elb)174*c068d44aSHeiko Schocher static int __init check(struct debug_el *ela, struct debug_el *elb)
175*c068d44aSHeiko Schocher {
176*c068d44aSHeiko Schocher 	if (ela->serial >= TEST_LIST_LEN) {
177*c068d44aSHeiko Schocher 		printk(KERN_ERR "list_sort_test: error: incorrect serial %d\n",
178*c068d44aSHeiko Schocher 				ela->serial);
179*c068d44aSHeiko Schocher 		return -EINVAL;
180*c068d44aSHeiko Schocher 	}
181*c068d44aSHeiko Schocher 	if (elb->serial >= TEST_LIST_LEN) {
182*c068d44aSHeiko Schocher 		printk(KERN_ERR "list_sort_test: error: incorrect serial %d\n",
183*c068d44aSHeiko Schocher 				elb->serial);
184*c068d44aSHeiko Schocher 		return -EINVAL;
185*c068d44aSHeiko Schocher 	}
186*c068d44aSHeiko Schocher 	if (elts[ela->serial] != ela || elts[elb->serial] != elb) {
187*c068d44aSHeiko Schocher 		printk(KERN_ERR "list_sort_test: error: phantom element\n");
188*c068d44aSHeiko Schocher 		return -EINVAL;
189*c068d44aSHeiko Schocher 	}
190*c068d44aSHeiko Schocher 	if (ela->poison1 != TEST_POISON1 || ela->poison2 != TEST_POISON2) {
191*c068d44aSHeiko Schocher 		printk(KERN_ERR "list_sort_test: error: bad poison: %#x/%#x\n",
192*c068d44aSHeiko Schocher 				ela->poison1, ela->poison2);
193*c068d44aSHeiko Schocher 		return -EINVAL;
194*c068d44aSHeiko Schocher 	}
195*c068d44aSHeiko Schocher 	if (elb->poison1 != TEST_POISON1 || elb->poison2 != TEST_POISON2) {
196*c068d44aSHeiko Schocher 		printk(KERN_ERR "list_sort_test: error: bad poison: %#x/%#x\n",
197*c068d44aSHeiko Schocher 				elb->poison1, elb->poison2);
198*c068d44aSHeiko Schocher 		return -EINVAL;
199*c068d44aSHeiko Schocher 	}
200*c068d44aSHeiko Schocher 	return 0;
201*c068d44aSHeiko Schocher }
202*c068d44aSHeiko Schocher 
cmp(void * priv,struct list_head * a,struct list_head * b)203*c068d44aSHeiko Schocher static int __init cmp(void *priv, struct list_head *a, struct list_head *b)
204*c068d44aSHeiko Schocher {
205*c068d44aSHeiko Schocher 	struct debug_el *ela, *elb;
206*c068d44aSHeiko Schocher 
207*c068d44aSHeiko Schocher 	ela = container_of(a, struct debug_el, list);
208*c068d44aSHeiko Schocher 	elb = container_of(b, struct debug_el, list);
209*c068d44aSHeiko Schocher 
210*c068d44aSHeiko Schocher 	check(ela, elb);
211*c068d44aSHeiko Schocher 	return ela->value - elb->value;
212*c068d44aSHeiko Schocher }
213*c068d44aSHeiko Schocher 
list_sort_test(void)214*c068d44aSHeiko Schocher static int __init list_sort_test(void)
215*c068d44aSHeiko Schocher {
216*c068d44aSHeiko Schocher 	int i, count = 1, err = -EINVAL;
217*c068d44aSHeiko Schocher 	struct debug_el *el;
218*c068d44aSHeiko Schocher 	struct list_head *cur, *tmp;
219*c068d44aSHeiko Schocher 	LIST_HEAD(head);
220*c068d44aSHeiko Schocher 
221*c068d44aSHeiko Schocher 	printk(KERN_DEBUG "list_sort_test: start testing list_sort()\n");
222*c068d44aSHeiko Schocher 
223*c068d44aSHeiko Schocher 	elts = kmalloc(sizeof(void *) * TEST_LIST_LEN, GFP_KERNEL);
224*c068d44aSHeiko Schocher 	if (!elts) {
225*c068d44aSHeiko Schocher 		printk(KERN_ERR "list_sort_test: error: cannot allocate "
226*c068d44aSHeiko Schocher 				"memory\n");
227*c068d44aSHeiko Schocher 		goto exit;
228*c068d44aSHeiko Schocher 	}
229*c068d44aSHeiko Schocher 
230*c068d44aSHeiko Schocher 	for (i = 0; i < TEST_LIST_LEN; i++) {
231*c068d44aSHeiko Schocher 		el = kmalloc(sizeof(*el), GFP_KERNEL);
232*c068d44aSHeiko Schocher 		if (!el) {
233*c068d44aSHeiko Schocher 			printk(KERN_ERR "list_sort_test: error: cannot "
234*c068d44aSHeiko Schocher 					"allocate memory\n");
235*c068d44aSHeiko Schocher 			goto exit;
236*c068d44aSHeiko Schocher 		}
237*c068d44aSHeiko Schocher 		 /* force some equivalencies */
238*c068d44aSHeiko Schocher 		el->value = prandom_u32() % (TEST_LIST_LEN / 3);
239*c068d44aSHeiko Schocher 		el->serial = i;
240*c068d44aSHeiko Schocher 		el->poison1 = TEST_POISON1;
241*c068d44aSHeiko Schocher 		el->poison2 = TEST_POISON2;
242*c068d44aSHeiko Schocher 		elts[i] = el;
243*c068d44aSHeiko Schocher 		list_add_tail(&el->list, &head);
244*c068d44aSHeiko Schocher 	}
245*c068d44aSHeiko Schocher 
246*c068d44aSHeiko Schocher 	list_sort(NULL, &head, cmp);
247*c068d44aSHeiko Schocher 
248*c068d44aSHeiko Schocher 	for (cur = head.next; cur->next != &head; cur = cur->next) {
249*c068d44aSHeiko Schocher 		struct debug_el *el1;
250*c068d44aSHeiko Schocher 		int cmp_result;
251*c068d44aSHeiko Schocher 
252*c068d44aSHeiko Schocher 		if (cur->next->prev != cur) {
253*c068d44aSHeiko Schocher 			printk(KERN_ERR "list_sort_test: error: list is "
254*c068d44aSHeiko Schocher 					"corrupted\n");
255*c068d44aSHeiko Schocher 			goto exit;
256*c068d44aSHeiko Schocher 		}
257*c068d44aSHeiko Schocher 
258*c068d44aSHeiko Schocher 		cmp_result = cmp(NULL, cur, cur->next);
259*c068d44aSHeiko Schocher 		if (cmp_result > 0) {
260*c068d44aSHeiko Schocher 			printk(KERN_ERR "list_sort_test: error: list is not "
261*c068d44aSHeiko Schocher 					"sorted\n");
262*c068d44aSHeiko Schocher 			goto exit;
263*c068d44aSHeiko Schocher 		}
264*c068d44aSHeiko Schocher 
265*c068d44aSHeiko Schocher 		el = container_of(cur, struct debug_el, list);
266*c068d44aSHeiko Schocher 		el1 = container_of(cur->next, struct debug_el, list);
267*c068d44aSHeiko Schocher 		if (cmp_result == 0 && el->serial >= el1->serial) {
268*c068d44aSHeiko Schocher 			printk(KERN_ERR "list_sort_test: error: order of "
269*c068d44aSHeiko Schocher 					"equivalent elements not preserved\n");
270*c068d44aSHeiko Schocher 			goto exit;
271*c068d44aSHeiko Schocher 		}
272*c068d44aSHeiko Schocher 
273*c068d44aSHeiko Schocher 		if (check(el, el1)) {
274*c068d44aSHeiko Schocher 			printk(KERN_ERR "list_sort_test: error: element check "
275*c068d44aSHeiko Schocher 					"failed\n");
276*c068d44aSHeiko Schocher 			goto exit;
277*c068d44aSHeiko Schocher 		}
278*c068d44aSHeiko Schocher 		count++;
279*c068d44aSHeiko Schocher 	}
280*c068d44aSHeiko Schocher 
281*c068d44aSHeiko Schocher 	if (count != TEST_LIST_LEN) {
282*c068d44aSHeiko Schocher 		printk(KERN_ERR "list_sort_test: error: bad list length %d",
283*c068d44aSHeiko Schocher 				count);
284*c068d44aSHeiko Schocher 		goto exit;
285*c068d44aSHeiko Schocher 	}
286*c068d44aSHeiko Schocher 
287*c068d44aSHeiko Schocher 	err = 0;
288*c068d44aSHeiko Schocher exit:
289*c068d44aSHeiko Schocher 	kfree(elts);
290*c068d44aSHeiko Schocher 	list_for_each_safe(cur, tmp, &head) {
291*c068d44aSHeiko Schocher 		list_del(cur);
292*c068d44aSHeiko Schocher 		kfree(container_of(cur, struct debug_el, list));
293*c068d44aSHeiko Schocher 	}
294*c068d44aSHeiko Schocher 	return err;
295*c068d44aSHeiko Schocher }
296*c068d44aSHeiko Schocher module_init(list_sort_test);
297*c068d44aSHeiko Schocher #endif /* CONFIG_TEST_LIST_SORT */
298