1/*
2 * Copyright (c) 2010-2010 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 2.0 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#ifdef KERNEL
24
25#include <IOKit/pci/IOPCIPrivate.h>
26#include <IOKit/pci/IOPCIConfigurator.h>
27
28#else
29
30/*
31cc IOPCIRange.cpp -o /tmp/pcirange -Wall -framework IOKit -framework CoreFoundation -arch i386 -g -lstdc++
32*/
33
34#include <assert.h>
35#include <CoreFoundation/CoreFoundation.h>
36#include <IOKit/IOKitLib.h>
37#include <IOKit/IOKitKeys.h>
38
39#include "IOKit/pci/IOPCIConfigurator.h"
40#define panic(x) printf(x)
41#define kprintf(fmt, args...)  printf(fmt, ## args)
42
43#endif
44
45IOPCIScalar IOPCIScalarAlign(IOPCIScalar num, IOPCIScalar alignment)
46{
47    return (num + (alignment - 1) & ~(alignment - 1));
48}
49
50IOPCIScalar IOPCIScalarTrunc(IOPCIScalar num, IOPCIScalar alignment)
51{
52    return (num & ~(alignment - 1));
53}
54
55IOPCIRange * IOPCIRangeAlloc(void)
56{
57#ifdef KERNEL
58    return (IONew(IOPCIRange, 1));
59#else
60    return ((IOPCIRange *) malloc(sizeof(IOPCIRange)));
61#endif
62}
63
64void IOPCIRangeFree(IOPCIRange * range)
65{
66//  memset(range, 0xBB, sizeof(*range));
67#ifdef KERNEL
68    IODelete(range, IOPCIRange, 1);
69#else
70    free(range);
71#endif
72}
73
74void IOPCIRangeInit(IOPCIRange * range, uint32_t type,
75                    IOPCIScalar start, IOPCIScalar size, IOPCIScalar alignment)
76{
77    bzero(range, sizeof(*range));
78    range->type         = type;
79    range->start        = start;
80//    range->size         = 0;
81    range->proposedSize = size;
82    range->totalSize    = size;
83    range->end          = start;
84//    range->zero         = 0;
85    range->alignment    = alignment ? alignment : size;
86//    range->minAddress   = 0;
87    range->maxAddress   = 0xFFFFFFFF;
88    range->allocations  = (IOPCIRange *) &range->end;
89}
90
91void IOPCIRangeInitAlloc(IOPCIRange * range, uint32_t type,
92                         IOPCIScalar start, IOPCIScalar size, IOPCIScalar alignment)
93{
94    IOPCIRangeInit(range, type, start, size, alignment);
95    range->size = range->proposedSize;
96    range->end  = range->start + range->size;
97}
98
99bool IOPCIRangeListAddRange(IOPCIRange ** rangeList,
100                            uint32_t type,
101                            IOPCIScalar start,
102                            IOPCIScalar size,
103                            IOPCIScalar alignment)
104{
105    IOPCIRange *  range;
106    IOPCIRange *  nextRange;
107    IOPCIRange ** prev;
108    IOPCIScalar   end;
109    bool          result = true;
110    bool          alloc  = true;
111
112    end = start + size;
113    for (prev = rangeList; (range = *prev); prev = &range->next)
114    {
115        if (((start >= range->start) && (start < range->end))
116         || ((end > range->start) && (end <= range->end))
117         || ((start < range->start) && (end > range->end)))
118        {
119            range = NULL;
120            result = false;
121            break;
122        }
123        if (end == range->start)
124        {
125            range->start        = start;
126            range->size         = range->end - range->start;
127            range->proposedSize = range->size;
128            alloc = false;
129            break;
130        }
131        if (start == range->end)
132        {
133            if ((nextRange = range->next) && (nextRange->start == end))
134            {
135                if (nextRange->allocations != (IOPCIRange *) &nextRange->end)
136                    assert(false);
137                end = nextRange->end;
138                range->next = nextRange->next;
139                IOPCIRangeFree(nextRange);
140            }
141            range->end          = end;
142            range->size         = end - range->start;
143            range->proposedSize = range->size;
144            alloc = false;
145            break;
146        }
147        if (range->start > end)
148        {
149            alloc = true;
150            break;
151        }
152    }
153
154    if (result && alloc)
155    {
156        nextRange = IOPCIRangeAlloc();
157        IOPCIRangeInitAlloc(nextRange, type, start, size, alignment);
158        nextRange->next = range;
159        *prev = nextRange;
160    }
161
162    return (result);
163}
164
165IOPCIScalar IOPCIRangeListCollapse(IOPCIRange * headRange, IOPCIScalar alignment)
166{
167    IOPCIScalar total = 0;
168
169    while (headRange)
170    {
171        total += IOPCIRangeCollapse(headRange, alignment);
172        headRange = headRange->next;
173    }
174
175    return (total);
176}
177
178IOPCIScalar IOPCIRangeCollapse(IOPCIRange * headRange, IOPCIScalar alignment)
179{
180    IOPCIScalar   start, end, saving;
181    IOPCIRange *  range;
182
183    start  = 0;
184    end    = 0;
185    saving = headRange->size;
186    range  = headRange->allocations;
187    do
188    {
189        // keep walking down the list
190        if (!range->size)
191            break;
192        if (!start)
193            start = range->start;
194        end = range->end;
195        range = range->nextSubRange;
196    }
197    while(true);
198
199    start = IOPCIScalarTrunc(start, alignment);
200    end   = IOPCIScalarAlign(end,   alignment);
201
202	if (!start) headRange->proposedSize = 0;
203	else
204	{
205		headRange->start        = start;
206		headRange->end          = end;
207		headRange->size         =
208		headRange->proposedSize = end - start;
209		if (headRange->size > headRange->totalSize)
210		{
211			headRange->extendSize = headRange->size - headRange->totalSize;
212		}
213		else
214        {
215            headRange->extendSize = 0;
216        }
217	}
218	if (saving < headRange->proposedSize) panic("IOPCIRangeCollapse");
219    saving -= headRange->proposedSize;
220
221    return (saving);
222}
223
224IOPCIScalar IOPCIRangeListLastFree(IOPCIRange * headRange, IOPCIScalar align)
225{
226	IOPCIRange * next;
227	next = headRange;
228    while (next)
229    {
230		headRange = next;
231        next = next->next;
232    }
233	return (IOPCIRangeLastFree(headRange, align));
234}
235
236IOPCIScalar IOPCIRangeLastFree(IOPCIRange * headRange, IOPCIScalar align)
237{
238    IOPCIScalar   last;
239    IOPCIRange *  range;
240
241    range = headRange->allocations;
242    last  = headRange->start;
243    do
244    {
245        // keep walking down the list
246        if (!range->size) break;
247        last = range->end;
248        range = range->nextSubRange;
249    }
250    while(true);
251
252	last = IOPCIScalarAlign(last, align);
253	if (headRange->end > last)
254		last = headRange->end - last;
255	else
256		last = 0;
257
258    return (last);
259}
260
261void IOPCIRangeOptimize(IOPCIRange * headRange)
262{
263    IOPCIScalar   free;
264    IOPCIScalar	  count;
265	IOPCIScalar   chunk, bump, tail;
266    IOPCIScalar	  next, end;
267    IOPCIRange *  range;
268    IOPCIRange *  prev;
269
270    range = headRange->allocations;
271    prev  = NULL;
272    free  = 0;
273    count = 0;
274    do
275	{
276		if (prev)
277		{
278			assert(range->start >= prev->end);
279			free += (range->start - prev->end);
280		}
281        // eol
282        if (!range->size) break;
283
284		range->nextToAllocate = prev;
285		if ((kIOPCIRangeFlagMaximizeSize | kIOPCIRangeFlagMaximizeRoot | kIOPCIRangeFlagSplay)
286			 & range->flags) count++;
287		prev = range;
288        range = range->nextSubRange;
289    }
290    while(true);
291
292	if (!free) return;
293
294	end = headRange->end;
295	for (range = prev; free && range; end = range->start, range = range->nextToAllocate)
296	{
297		if (!(kIOPCIRangeFlagRelocatable & range->flags)) continue;
298
299        chunk = 0;
300		if ((kIOPCIRangeFlagMaximizeSize | kIOPCIRangeFlagSplay) & range->flags)
301        {
302            chunk = free / count;
303            chunk = IOPCIScalarTrunc(chunk, range->alignment);
304            free -= chunk;
305            count--;
306        }
307
308		next = range->end;
309		if (end < next) panic("end");
310        tail = IOPCIScalarTrunc(end - next, range->alignment);
311        if (chunk > tail) chunk = tail;
312
313		if (kIOPCIRangeFlagSplay & range->flags)
314		{
315            bump = tail - chunk;
316			range->end   += bump;
317			range->start += bump;
318		}
319        else
320		{
321            range->size        += chunk;
322            range->proposedSize = range->size;
323            range->end          = end;
324			range->start        = range->end - range->size;
325		}
326
327        if (range->start > headRange->end)   panic("s>");
328        if (range->start < headRange->start) panic("s<");
329        if (range->end > headRange->end)     panic("e>");
330        if (range->end < headRange->start)   panic("e<");
331    }
332}
333
334void IOPCIRangeListOptimize(IOPCIRange * headRange)
335{
336	IOPCIRange * next;
337	next = headRange;
338    while (next)
339    {
340		IOPCIRangeOptimize(next);
341        next = next->next;
342    }
343}
344
345bool IOPCIRangeListAllocateSubRange(IOPCIRange * headRange,
346                                    IOPCIRange * newRange,
347                                    IOPCIScalar  newStart)
348{
349    IOPCIScalar   minSize, maxSize;
350    IOPCIScalar   len, bestFit, waste;
351	IOPCIScalar   pos, endPos;
352    IOPCIRange ** where = NULL;
353    IOPCIRange *  whereNext = NULL;
354	IOPCIRange *  range = NULL;
355	IOPCIRange ** prev;
356
357	minSize = newRange->size;
358	if (!minSize)  minSize = newRange->proposedSize;
359	if (!minSize)  panic("!minSize");
360	if (!newStart) newStart = newRange->start;
361
362	bestFit = UINT64_MAX;
363    for (; headRange; headRange = headRange->next)
364    {
365        if (!headRange->size) continue;
366
367		maxSize = newRange->proposedSize;
368		if (!maxSize) panic("!maxSize");
369		if (maxSize < minSize) minSize = maxSize;
370
371        pos  = headRange->start;
372        prev = &headRange->allocations;
373        range = NULL;
374        do
375        {
376			if (range)
377			{
378				// onto next element
379				if (!range->size)
380				{
381					// end of list
382					range = NULL;
383					break;
384				}
385				pos = range->end;
386				prev = &range->nextSubRange;
387			}
388            range = *prev;
389            if (range == newRange)
390            {
391				// reallocate in place - treat as free
392                range = range->nextSubRange;
393            }
394			endPos = range->start;
395
396			// [pos,endPos] is free
397			waste = endPos - pos;
398			if (pos > newRange->maxAddress)    pos = newRange->maxAddress;
399			if (endPos > newRange->maxAddress) endPos = newRange->maxAddress;
400			if (newStart)
401			{
402				if (newStart < pos)     continue;
403				if (newStart >= endPos) continue;
404				pos = newStart;
405			}
406			else pos = IOPCIScalarAlign(pos, newRange->alignment);
407			if (kIOPCIRangeFlagMaximizeRoot & newRange->flags)
408				endPos = IOPCIScalarTrunc(endPos, newRange->alignment);
409
410			if (endPos < pos) continue;
411
412			len = endPos - pos;
413			if (len < minSize) continue;
414			if (len > maxSize) len = maxSize;
415
416			if (newStart
417				|| (where && (newRange->start < newRange->minAddress) && (pos >= newRange->minAddress))
418				|| (len < maxSize)
419				|| (kIOPCIRangeFlagMaximizeRoot & newRange->flags))
420			{
421			}
422			else
423			{
424				if ((kIOPCIRangeFlagSplay | kIOPCIRangeFlagMaximizeSize) & newRange->flags)
425				{
426					// in biggest free area position
427					waste = UINT64_MAX - waste;
428				}
429				else
430				{
431					// least waste position
432					waste -= len;
433				}
434				if (where && (bestFit < waste)) continue;
435				bestFit = waste;
436			}
437			// best candidate, will queue prev->newRange->range
438			// new size to look for
439			minSize         = len;
440			where           = prev;
441			whereNext       = range;
442			newRange->start = pos;
443			newRange->size  = len;
444			newRange->end   = pos + len;
445
446			if (newStart || !waste)
447			{
448				// use this if placed or zero waste
449				break;
450			}
451        }
452        while(true);
453    }
454
455    if (where)
456    {
457		if (kIOPCIRangeFlagMaximizeRoot & newRange->flags) newRange->proposedSize = newRange->size;
458        newRange->nextSubRange = whereNext;
459        *where = newRange;
460    }
461
462    return (where != NULL);
463}
464
465bool IOPCIRangeListDeallocateSubRange(IOPCIRange * headRange,
466                                	  IOPCIRange * oldRange)
467{
468    IOPCIRange *  range = NULL;
469    IOPCIRange ** prev = NULL;
470
471    do
472    {
473		range = oldRange->allocations;
474        if (!range->size)
475            break;
476        IOPCIRangeListDeallocateSubRange(oldRange, range);
477    }
478    while(true);
479
480    for (range = NULL;
481         headRange && !range;
482         headRange = headRange->next)
483    {
484        prev = &headRange->allocations;
485        do
486        {
487            range = *prev;
488            if (range == oldRange)
489                break;
490            // keep walking down the list
491            if (!range->size)
492            {
493                range = NULL;
494                break;
495            }
496        }
497        while (prev = &range->nextSubRange, true);
498    }
499
500    if (range)
501    {
502        *prev = range->nextSubRange;
503		oldRange->nextSubRange  = NULL;
504		oldRange->end           = 0;
505//		oldRange->proposedSize  = oldRange->size;
506//		oldRange->size          = 0;
507//		oldRange->extendSize    = 0;
508		oldRange->start         = 0;
509	}
510
511    return (range != 0);
512}
513
514void IOPCIRangeDump(IOPCIRange * head)
515{
516    IOPCIRange * range;
517    uint32_t idx;
518
519    do
520    {
521        kprintf("head.start     0x%llx\n", head->start);
522        kprintf("head.size      0x%llx\n", head->size);
523        kprintf("head.end       0x%llx\n", head->end);
524        kprintf("head.alignment 0x%llx\n", head->alignment);
525
526        kprintf("allocs:\n");
527        range = head->allocations;
528        idx = 0;
529        while (true)
530        {
531            if (range == (IOPCIRange *) &head->end)
532            {
533                kprintf("[end]\n");
534                break;
535            }
536            kprintf("[%d].start     0x%llx\n", idx, range->start);
537            kprintf("[%d].size      0x%llx\n", idx, range->size);
538            kprintf("[%d].end       0x%llx\n", idx, range->end);
539            kprintf("[%d].alignment 0x%llx\n", idx, range->alignment);
540            idx++;
541            range = range->nextSubRange;
542        }
543        kprintf("------\n");
544    }
545    while ((head = head->next));
546
547    kprintf("------------------------------------\n");
548}
549
550#ifndef KERNEL
551
552int main(int argc, char **argv)
553{
554    IOPCIRange * head = NULL;
555    IOPCIRange * range;
556    IOPCIRange * requests = NULL;
557    IOPCIRange * elems[8];
558    IOPCIScalar  shrink;
559    size_t       idx;
560    bool         ok;
561
562    for (idx = 0; idx < sizeof(elems) / sizeof(elems[0]); idx++)
563    {
564        elems[idx] = IOPCIRangeAlloc();
565        elems[idx]->maxAddress = 0xFFFFFFFFFFFFFFFFULL;
566    }
567
568#if 1
569
570    IOPCIRangeListAddRange(&head, 0, 0x00000000b5f00000, 0x0000000001100000, 0x0000000000400000);
571
572	range = elems[0];
573	IOPCIRangeInit(range, 0, 0, 0x0000000000100000, 0x0000000000100000);
574	ok = IOPCIRangeListAllocateSubRange(head, range);
575	assert(ok);
576
577	range = elems[1];
578	IOPCIRangeInit(range, 0, 0, 0x0000000000f00000, 0x400000);
579    range->flags |= kIOPCIRangeFlagRelocatable | kIOPCIRangeFlagSplay;
580	ok = IOPCIRangeListAllocateSubRange(head, range);
581	assert(ok);
582
583    IOPCIRangeDump(head);
584
585    IOPCIRangeListOptimize(head);
586
587    IOPCIRangeDump(head);
588
589    exit(0);
590
591#elif 0
592
593	uint32_t flags;
594
595    IOPCIRangeListAddRange(&head, 0, 0x25, 0x7, 1);
596    IOPCIRangeDump(head);
597
598	range = elems[0];
599	IOPCIRangeInit(range, 0, 0x25, 1, 1);
600	ok = IOPCIRangeListAllocateSubRange(head, range);
601	assert(ok);
602
603	range = elems[1];
604	IOPCIRangeInit(range, 0, 0, 6, 1);
605	range->size = 1;
606	range->flags |= kIOPCIRangeFlagMaximizeSize;
607	ok = IOPCIRangeListAllocateSubRange(head, range);
608	assert(ok);
609	assert(range->proposedSize == range->size);
610    IOPCIRangeDump(head);
611	exit(0);
612
613	range = elems[2];
614	IOPCIRangeInit(range, 0, 0x7, 1, 1);
615	ok = IOPCIRangeListAllocateSubRange(head, range);
616	assert(ok);
617
618	range = elems[3];
619	IOPCIRangeInit(range, 0, 0x6, 0x1, 1);
620	ok = IOPCIRangeListAllocateSubRange(head, range);
621	assert(ok);
622
623	range = elems[4];
624	IOPCIRangeInit(range, 0, 0x8, 1, 1);
625	ok = IOPCIRangeListAllocateSubRange(head, range);
626	assert(ok);
627
628
629
630	range = elems[5];
631	IOPCIRangeInit(range, 0, 0, 0xa, 1);
632	range->size = 9;
633	ok = IOPCIRangeListAllocateSubRange(head, range);
634	assert(0xa == range->size);
635	assert(ok);
636exit(0);
637	flags = kIOPCIRangeFlagRelocatable | kIOPCIRangeFlagSplay;
638//	flags = kIOPCIRangeFlagRelocatable | kIOPCIRangeFlagMaximizeSize;
639
640	range = elems[2];
641	IOPCIRangeInit(range, 0, 0, 0xe, 1);
642	range->flags |= flags;
643	ok = IOPCIRangeListAllocateSubRange(head, range);
644	assert(ok);
645
646	range = elems[3];
647	IOPCIRangeInit(range, 0, 0, 0x7, 1);
648	range->flags |= flags;
649	ok = IOPCIRangeListAllocateSubRange(head, range);
650	assert(ok);
651
652	range = elems[4];
653	IOPCIRangeInit(range, 0, 0, 0x7, 1);
654	range->flags |= flags;
655	ok = IOPCIRangeListAllocateSubRange(head, range);
656	assert(ok);
657
658	IOPCIRangeOptimize(head);
659
660    exit(0);
661#endif
662
663
664
665#if 0
666    IOPCIRangeListAddRange(&head, 0, 0,0, 1024*1024);
667    IOPCIRangeDump(head);
668    shrink = IOPCIRangeListLastFree(head, 1024*1024);
669    printf("IOPCIRangeListLastFree 0x%llx\n", shrink);
670exit(0);
671#endif
672
673#if 0
674    IOPCIRangeListAddRange(&head, 0, 0xa0800000, 0x500000, 0x100000);
675
676	range = elems[0];
677	IOPCIRangeInit(range, 0, 0xa0800000, 0x40000, 0x40000);
678	ok = IOPCIRangeListAllocateSubRange(head, range);
679	assert(ok);
680
681	range = elems[1];
682	IOPCIRangeInit(range, 0, 0xa0a00000, 0x400000, 0x100000);
683	ok = IOPCIRangeListAllocateSubRange(head, range);
684	assert(ok);
685
686	range->proposedSize = 0x300000;
687	ok = IOPCIRangeListAllocateSubRange(head, range);
688	assert(ok);
689//	ok = IOPCIRangeListDeallocateSubRange(head, range);
690//	assert(ok);
691    IOPCIRangeDump(head);
692
693    exit(0);
694#endif
695
696    IOPCIRangeListAddRange(&head, 0, 0x6, 0xfa, 1);
697    IOPCIRangeDump(head);
698
699	range = elems[4];
700	range->start = 0x06;
701	range->proposedSize = 0x01;
702	range->alignment = 1;
703	ok = IOPCIRangeListAllocateSubRange(head, range);
704	assert(ok);
705
706	range = elems[3];
707	range->start = 0x07;
708	range->proposedSize = 0x01;
709	range->alignment = 1;
710	ok = IOPCIRangeListAllocateSubRange(head, range);
711	assert(ok);
712
713	range = elems[1];
714	range->start = 1*0x87;
715	range->size = 3;
716	range->proposedSize = 3;
717	range->alignment = 1;
718	range->flags = kIOPCIRangeFlagSplay;
719	ok = IOPCIRangeListAllocateSubRange(head, range);
720	assert(ok);
721
722	range = elems[2];
723	range->start = 0;
724	range->proposedSize = 2;
725	range->alignment = 1;
726	range->flags = kIOPCIRangeFlagSplay;
727	ok = IOPCIRangeListAllocateSubRange(head, range);
728	assert(ok);
729
730
731	range = elems[5];
732	range->start = 0;
733	range->proposedSize = 1;
734	range->alignment = 1;
735	range->flags = kIOPCIRangeFlagSplay;
736	ok = IOPCIRangeListAllocateSubRange(head, range);
737	assert(ok);
738
739	range = elems[6];
740	range->start = 0;
741	range->proposedSize = 1;
742	range->alignment = 1;
743	range->flags = kIOPCIRangeFlagSplay;
744	ok = IOPCIRangeListAllocateSubRange(head, range);
745	assert(ok);
746
747
748    IOPCIRangeDump(head);
749	exit(0);
750
751    shrink = IOPCIRangeListLastFree(head, 1024);
752    printf("IOPCIRangeListLastFree 0x%llx\n", shrink);
753    exit(0);
754
755    idx = 0;
756    IOPCIRangeInit(elems[idx++], 0, 0, 1024*1024);
757
758    range = elems[0];
759    ok = IOPCIRangeListAllocateSubRange(head, range);
760    printf("alloc(%d) [0x%llx, 0x%llx]\n", ok, range->start, range->size);
761    IOPCIRangeDump(head);
762
763    shrink = IOPCIRangeListCollapse(head, 1024*1024);
764    printf("Collapsed by 0x%llx\n", shrink);
765    IOPCIRangeDump(head);
766    exit(0);
767
768
769    IOPCIRangeListAddRange(&head, 0, 0xA0000000, 0x10000000);
770    IOPCIRangeListAddRange(&head, 0, 0x98000000, 0x08000000);
771    IOPCIRangeListAddRange(&head, 0, 0x90000000, 0x08000000);
772    IOPCIRangeListAddRange(&head, 0, 0xB0000000, 0x10000000);
773
774//exit(0);
775
776
777    idx = 0;
778    IOPCIRangeInit(elems[idx++], 0, 0x80001000, 0x1000);
779    IOPCIRangeInit(elems[idx++], 0, 0, 0x1000000);
780    IOPCIRangeInit(elems[idx++], 0, 0, 0x20000000);
781    IOPCIRangeInit(elems[idx++], 0, 0, 0x20000000);
782    IOPCIRangeInit(elems[idx++], 0, 0x80002000, 0x800);
783    IOPCIRangeInit(elems[idx++], 0, 0, 0x10000, 1);
784
785    for (idx = 0; idx < sizeof(elems) / sizeof(elems[0]); idx++)
786    {
787        if (elems[idx]->size)
788            IOPCIRangeAppendSubRange(&requests, elems[idx]);
789    }
790
791    printf("reqs:\n");
792    range = requests;
793    idx = 0;
794    while (range)
795    {
796        printf("[%ld].start     0x%llx\n", idx, range->start);
797        printf("[%ld].size      0x%llx\n", idx, range->size);
798        printf("[%ld].end       0x%llx\n", idx, range->end);
799        printf("[%ld].alignment 0x%llx\n", idx, range->alignment);
800        idx++;
801        range = range->nextSubRange;
802    }
803
804    while ((range = requests))
805    {
806        requests = range->nextSubRange;
807        ok = IOPCIRangeListAllocateSubRange(head, range);
808        printf("alloc(%d) [0x%llx, 0x%llx]\n", ok, range->start, range->size);
809    }
810
811    IOPCIRangeDump(head);
812    shrink = IOPCIRangeListCollapse(head, 1024*1024);
813    printf("Collapsed by 0x%llx\n", shrink);
814    IOPCIRangeDump(head);
815exit(0);
816
817    for (idx = 0; idx < sizeof(elems) / sizeof(elems[0]); idx++)
818    {
819        range = elems[idx];
820        if (range->size && range->start)
821        {
822            ok = IOPCIRangeListDeallocateSubRange(head, range);
823            printf("dealloc(%d) [0x%llx, 0x%llx]\n", ok, range->start, range->size);
824            ok = IOPCIRangeListAllocateSubRange(head, range);
825            printf("alloc(%d) [0x%llx, 0x%llx]\n", ok, range->start, range->size);
826        }
827    }
828
829    // extend
830    range = elems[5];
831    range->proposedSize = 2 * range->size;
832    ok = IOPCIRangeListAllocateSubRange(head, range);
833    printf("extalloc(%d) [0x%llx, 0x%llx]\n", ok, range->start, range->size);
834    range = elems[0];
835    range->proposedSize = 2 * range->size;
836    ok = IOPCIRangeListAllocateSubRange(head, range);
837    printf("extalloc(%d) [0x%llx, 0x%llx]\n", ok, range->start, range->size);
838    range->proposedSize = 2 * range->size;
839    ok = IOPCIRangeListAllocateSubRange(head, range, range->start - range->size);
840    printf("extalloc(%d) [0x%llx, 0x%llx]\n", ok, range->start, range->size);
841
842    IOPCIRangeDump(head);
843
844    exit(0);
845}
846
847#endif
848