Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / pci / hotplug / acpiphp_res.c
1 /*
2  * ACPI PCI HotPlug Utility functions
3  *
4  * Copyright (C) 1995,2001 Compaq Computer Corporation
5  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6  * Copyright (C) 2001 IBM Corp.
7  * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
8  * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
9  * Copyright (C) 2002 NEC Corporation
10  *
11  * All rights reserved.
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or (at
16  * your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
21  * NON INFRINGEMENT.  See the GNU General Public License for more
22  * details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  *
28  * Send feedback to <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com>
29  *
30  */
31
32 #include <linux/init.h>
33 #include <linux/module.h>
34
35 #include <linux/kernel.h>
36 #include <linux/types.h>
37 #include <linux/proc_fs.h>
38 #include <linux/sysctl.h>
39 #include <linux/pci.h>
40 #include <linux/smp.h>
41 #include <linux/smp_lock.h>
42
43 #include <linux/string.h>
44 #include <linux/mm.h>
45 #include <linux/errno.h>
46 #include <linux/ioport.h>
47 #include <linux/slab.h>
48 #include <linux/interrupt.h>
49 #include <linux/timer.h>
50
51 #include <linux/ioctl.h>
52 #include <linux/fcntl.h>
53
54 #include <linux/list.h>
55
56 #include "pci_hotplug.h"
57 #include "acpiphp.h"
58
59 #define MY_NAME "acpiphp_res"
60
61
62 /*
63  * sort_by_size - sort nodes by their length, smallest first
64  */
65 static int sort_by_size(struct pci_resource **head)
66 {
67         struct pci_resource *current_res;
68         struct pci_resource *next_res;
69         int out_of_order = 1;
70
71         if (!(*head))
72                 return 1;
73
74         if (!((*head)->next))
75                 return 0;
76
77         while (out_of_order) {
78                 out_of_order = 0;
79
80                 /* Special case for swapping list head */
81                 if (((*head)->next) &&
82                     ((*head)->length > (*head)->next->length)) {
83                         out_of_order++;
84                         current_res = *head;
85                         *head = (*head)->next;
86                         current_res->next = (*head)->next;
87                         (*head)->next = current_res;
88                 }
89
90                 current_res = *head;
91
92                 while (current_res->next && current_res->next->next) {
93                         if (current_res->next->length > current_res->next->next->length) {
94                                 out_of_order++;
95                                 next_res = current_res->next;
96                                 current_res->next = current_res->next->next;
97                                 current_res = current_res->next;
98                                 next_res->next = current_res->next;
99                                 current_res->next = next_res;
100                         } else
101                                 current_res = current_res->next;
102                 }
103         }  /* End of out_of_order loop */
104
105         return 0;
106 }
107
108 #if 0
109 /*
110  * sort_by_max_size - sort nodes by their length, largest first
111  */
112 static int sort_by_max_size(struct pci_resource **head)
113 {
114         struct pci_resource *current_res;
115         struct pci_resource *next_res;
116         int out_of_order = 1;
117
118         if (!(*head))
119                 return 1;
120
121         if (!((*head)->next))
122                 return 0;
123
124         while (out_of_order) {
125                 out_of_order = 0;
126
127                 /* Special case for swapping list head */
128                 if (((*head)->next) &&
129                     ((*head)->length < (*head)->next->length)) {
130                         out_of_order++;
131                         current_res = *head;
132                         *head = (*head)->next;
133                         current_res->next = (*head)->next;
134                         (*head)->next = current_res;
135                 }
136
137                 current_res = *head;
138
139                 while (current_res->next && current_res->next->next) {
140                         if (current_res->next->length < current_res->next->next->length) {
141                                 out_of_order++;
142                                 next_res = current_res->next;
143                                 current_res->next = current_res->next->next;
144                                 current_res = current_res->next;
145                                 next_res->next = current_res->next;
146                                 current_res->next = next_res;
147                         } else
148                                 current_res = current_res->next;
149                 }
150         }  /* End of out_of_order loop */
151
152         return 0;
153 }
154 #endif
155
156 /**
157  * get_io_resource - get resource for I/O ports
158  *
159  * this function sorts the resource list by size and then
160  * returns the first node of "size" length that is not in the
161  * ISA aliasing window.  If it finds a node larger than "size"
162  * it will split it up.
163  *
164  * size must be a power of two.
165  *
166  * difference from get_resource is handling of ISA aliasing space.
167  *
168  */
169 struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size)
170 {
171         struct pci_resource *prevnode;
172         struct pci_resource *node;
173         struct pci_resource *split_node;
174         u64 temp_qword;
175
176         if (!(*head))
177                 return NULL;
178
179         if (acpiphp_resource_sort_and_combine(head))
180                 return NULL;
181
182         if (sort_by_size(head))
183                 return NULL;
184
185         for (node = *head; node; node = node->next) {
186                 if (node->length < size)
187                         continue;
188
189                 if (node->base & (size - 1)) {
190                         /* this one isn't base aligned properly
191                            so we'll make a new entry and split it up */
192                         temp_qword = (node->base | (size-1)) + 1;
193
194                         /* Short circuit if adjusted size is too small */
195                         if ((node->length - (temp_qword - node->base)) < size)
196                                 continue;
197
198                         split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
199
200                         if (!split_node)
201                                 return NULL;
202
203                         node->base = temp_qword;
204                         node->length -= split_node->length;
205
206                         /* Put it in the list */
207                         split_node->next = node->next;
208                         node->next = split_node;
209                 } /* End of non-aligned base */
210
211                 /* Don't need to check if too small since we already did */
212                 if (node->length > size) {
213                         /* this one is longer than we need
214                            so we'll make a new entry and split it up */
215                         split_node = acpiphp_make_resource(node->base + size, node->length - size);
216
217                         if (!split_node)
218                                 return NULL;
219
220                         node->length = size;
221
222                         /* Put it in the list */
223                         split_node->next = node->next;
224                         node->next = split_node;
225                 }  /* End of too big on top end */
226
227                 /* For IO make sure it's not in the ISA aliasing space */
228                 if ((node->base & 0x300L) && !(node->base & 0xfffff000))
229                         continue;
230
231                 /* If we got here, then it is the right size
232                    Now take it out of the list */
233                 if (*head == node) {
234                         *head = node->next;
235                 } else {
236                         prevnode = *head;
237                         while (prevnode->next != node)
238                                 prevnode = prevnode->next;
239
240                         prevnode->next = node->next;
241                 }
242                 node->next = NULL;
243                 /* Stop looping */
244                 break;
245         }
246
247         return node;
248 }
249
250
251 #if 0
252 /**
253  * get_max_resource - get the largest resource
254  *
255  * Gets the largest node that is at least "size" big from the
256  * list pointed to by head.  It aligns the node on top and bottom
257  * to "size" alignment before returning it.
258  */
259 static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
260 {
261         struct pci_resource *max;
262         struct pci_resource *temp;
263         struct pci_resource *split_node;
264         u64 temp_qword;
265
266         if (!(*head))
267                 return NULL;
268
269         if (acpiphp_resource_sort_and_combine(head))
270                 return NULL;
271
272         if (sort_by_max_size(head))
273                 return NULL;
274
275         for (max = *head;max; max = max->next) {
276
277                 /* If not big enough we could probably just bail,
278                    instead we'll continue to the next. */
279                 if (max->length < size)
280                         continue;
281
282                 if (max->base & (size - 1)) {
283                         /* this one isn't base aligned properly
284                            so we'll make a new entry and split it up */
285                         temp_qword = (max->base | (size-1)) + 1;
286
287                         /* Short circuit if adjusted size is too small */
288                         if ((max->length - (temp_qword - max->base)) < size)
289                                 continue;
290
291                         split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
292
293                         if (!split_node)
294                                 return NULL;
295
296                         max->base = temp_qword;
297                         max->length -= split_node->length;
298
299                         /* Put it next in the list */
300                         split_node->next = max->next;
301                         max->next = split_node;
302                 }
303
304                 if ((max->base + max->length) & (size - 1)) {
305                         /* this one isn't end aligned properly at the top
306                            so we'll make a new entry and split it up */
307                         temp_qword = ((max->base + max->length) & ~(size - 1));
308
309                         split_node = acpiphp_make_resource(temp_qword,
310                                                            max->length + max->base - temp_qword);
311
312                         if (!split_node)
313                                 return NULL;
314
315                         max->length -= split_node->length;
316
317                         /* Put it in the list */
318                         split_node->next = max->next;
319                         max->next = split_node;
320                 }
321
322                 /* Make sure it didn't shrink too much when we aligned it */
323                 if (max->length < size)
324                         continue;
325
326                 /* Now take it out of the list */
327                 temp = (struct pci_resource*) *head;
328                 if (temp == max) {
329                         *head = max->next;
330                 } else {
331                         while (temp && temp->next != max) {
332                                 temp = temp->next;
333                         }
334
335                         temp->next = max->next;
336                 }
337
338                 max->next = NULL;
339                 return max;
340         }
341
342         /* If we get here, we couldn't find one */
343         return NULL;
344 }
345 #endif
346
347 /**
348  * get_resource - get resource (mem, pfmem)
349  *
350  * this function sorts the resource list by size and then
351  * returns the first node of "size" length.  If it finds a node
352  * larger than "size" it will split it up.
353  *
354  * size must be a power of two.
355  *
356  */
357 struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
358 {
359         struct pci_resource *prevnode;
360         struct pci_resource *node;
361         struct pci_resource *split_node;
362         u64 temp_qword;
363
364         if (!(*head))
365                 return NULL;
366
367         if (acpiphp_resource_sort_and_combine(head))
368                 return NULL;
369
370         if (sort_by_size(head))
371                 return NULL;
372
373         for (node = *head; node; node = node->next) {
374                 dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
375                     __FUNCTION__, size, node, (u32)node->base, node->length);
376                 if (node->length < size)
377                         continue;
378
379                 if (node->base & (size - 1)) {
380                         dbg("%s: not aligned\n", __FUNCTION__);
381                         /* this one isn't base aligned properly
382                            so we'll make a new entry and split it up */
383                         temp_qword = (node->base | (size-1)) + 1;
384
385                         /* Short circuit if adjusted size is too small */
386                         if ((node->length - (temp_qword - node->base)) < size)
387                                 continue;
388
389                         split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
390
391                         if (!split_node)
392                                 return NULL;
393
394                         node->base = temp_qword;
395                         node->length -= split_node->length;
396
397                         /* Put it in the list */
398                         split_node->next = node->next;
399                         node->next = split_node;
400                 } /* End of non-aligned base */
401
402                 /* Don't need to check if too small since we already did */
403                 if (node->length > size) {
404                         dbg("%s: too big\n", __FUNCTION__);
405                         /* this one is longer than we need
406                            so we'll make a new entry and split it up */
407                         split_node = acpiphp_make_resource(node->base + size, node->length - size);
408
409                         if (!split_node)
410                                 return NULL;
411
412                         node->length = size;
413
414                         /* Put it in the list */
415                         split_node->next = node->next;
416                         node->next = split_node;
417                 }  /* End of too big on top end */
418
419                 dbg("%s: got one!!!\n", __FUNCTION__);
420                 /* If we got here, then it is the right size
421                    Now take it out of the list */
422                 if (*head == node) {
423                         *head = node->next;
424                 } else {
425                         prevnode = *head;
426                         while (prevnode->next != node)
427                                 prevnode = prevnode->next;
428
429                         prevnode->next = node->next;
430                 }
431                 node->next = NULL;
432                 /* Stop looping */
433                 break;
434         }
435         return node;
436 }
437
438 /**
439  * get_resource_with_base - get resource with specific base address
440  *
441  * this function
442  * returns the first node of "size" length located at specified base address.
443  * If it finds a node larger than "size" it will split it up.
444  *
445  * size must be a power of two.
446  *
447  */
448 struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
449 {
450         struct pci_resource *prevnode;
451         struct pci_resource *node;
452         struct pci_resource *split_node;
453         u64 temp_qword;
454
455         if (!(*head))
456                 return NULL;
457
458         if (acpiphp_resource_sort_and_combine(head))
459                 return NULL;
460
461         for (node = *head; node; node = node->next) {
462                 dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
463                     (u32)base, size, node, (u32)node->base, node->length);
464                 if (node->base > base)
465                         continue;
466
467                 if ((node->base + node->length) < (base + size))
468                         continue;
469
470                 if (node->base < base) {
471                         dbg(": split 1\n");
472                         /* this one isn't base aligned properly
473                            so we'll make a new entry and split it up */
474                         temp_qword = base;
475
476                         /* Short circuit if adjusted size is too small */
477                         if ((node->length - (temp_qword - node->base)) < size)
478                                 continue;
479
480                         split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
481
482                         if (!split_node)
483                                 return NULL;
484
485                         node->base = temp_qword;
486                         node->length -= split_node->length;
487
488                         /* Put it in the list */
489                         split_node->next = node->next;
490                         node->next = split_node;
491                 }
492
493                 dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
494                     (u32)base, size, node, (u32)node->base, node->length);
495
496                 /* Don't need to check if too small since we already did */
497                 if (node->length > size) {
498                         dbg(": split 2\n");
499                         /* this one is longer than we need
500                            so we'll make a new entry and split it up */
501                         split_node = acpiphp_make_resource(node->base + size, node->length - size);
502
503                         if (!split_node)
504                                 return NULL;
505
506                         node->length = size;
507
508                         /* Put it in the list */
509                         split_node->next = node->next;
510                         node->next = split_node;
511                 }  /* End of too big on top end */
512
513                 dbg(": got one!!!\n");
514                 /* If we got here, then it is the right size
515                    Now take it out of the list */
516                 if (*head == node) {
517                         *head = node->next;
518                 } else {
519                         prevnode = *head;
520                         while (prevnode->next != node)
521                                 prevnode = prevnode->next;
522
523                         prevnode->next = node->next;
524                 }
525                 node->next = NULL;
526                 /* Stop looping */
527                 break;
528         }
529         return node;
530 }
531
532
533 /**
534  * acpiphp_resource_sort_and_combine
535  *
536  * Sorts all of the nodes in the list in ascending order by
537  * their base addresses.  Also does garbage collection by
538  * combining adjacent nodes.
539  *
540  * returns 0 if success
541  */
542 int acpiphp_resource_sort_and_combine (struct pci_resource **head)
543 {
544         struct pci_resource *node1;
545         struct pci_resource *node2;
546         int out_of_order = 1;
547
548         if (!(*head))
549                 return 1;
550
551         dbg("*head->next = %p\n",(*head)->next);
552
553         if (!(*head)->next)
554                 return 0;       /* only one item on the list, already sorted! */
555
556         dbg("*head->base = 0x%x\n",(u32)(*head)->base);
557         dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
558         while (out_of_order) {
559                 out_of_order = 0;
560
561                 /* Special case for swapping list head */
562                 if (((*head)->next) &&
563                     ((*head)->base > (*head)->next->base)) {
564                         node1 = *head;
565                         (*head) = (*head)->next;
566                         node1->next = (*head)->next;
567                         (*head)->next = node1;
568                         out_of_order++;
569                 }
570
571                 node1 = (*head);
572
573                 while (node1->next && node1->next->next) {
574                         if (node1->next->base > node1->next->next->base) {
575                                 out_of_order++;
576                                 node2 = node1->next;
577                                 node1->next = node1->next->next;
578                                 node1 = node1->next;
579                                 node2->next = node1->next;
580                                 node1->next = node2;
581                         } else
582                                 node1 = node1->next;
583                 }
584         }  /* End of out_of_order loop */
585
586         node1 = *head;
587
588         while (node1 && node1->next) {
589                 if ((node1->base + node1->length) == node1->next->base) {
590                         /* Combine */
591                         dbg("8..\n");
592                         node1->length += node1->next->length;
593                         node2 = node1->next;
594                         node1->next = node1->next->next;
595                         kfree(node2);
596                 } else
597                         node1 = node1->next;
598         }
599
600         return 0;
601 }
602
603
604 /**
605  * acpiphp_make_resource - make resource structure
606  * @base: base address of a resource
607  * @length: length of a resource
608  */
609 struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
610 {
611         struct pci_resource *res;
612
613         res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
614         if (res) {
615                 memset(res, 0, sizeof(struct pci_resource));
616                 res->base = base;
617                 res->length = length;
618         }
619
620         return res;
621 }
622
623
624 /**
625  * acpiphp_move_resource - move linked resources from one to another
626  * @from: head of linked resource list
627  * @to: head of linked resource list
628  */
629 void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
630 {
631         struct pci_resource *tmp;
632
633         while (*from) {
634                 tmp = (*from)->next;
635                 (*from)->next = *to;
636                 *to = *from;
637                 *from = tmp;
638         }
639
640         /* *from = NULL is guaranteed */
641 }
642
643
644 /**
645  * acpiphp_free_resource - free all linked resources
646  * @res: head of linked resource list
647  */
648 void acpiphp_free_resource (struct pci_resource **res)
649 {
650         struct pci_resource *tmp;
651
652         while (*res) {
653                 tmp = (*res)->next;
654                 kfree(*res);
655                 *res = tmp;
656         }
657
658         /* *res = NULL is guaranteed */
659 }
660
661
662 /* debug support functions;  will go away sometime :) */
663 static void dump_resource(struct pci_resource *head)
664 {
665         struct pci_resource *p;
666         int cnt;
667
668         p = head;
669         cnt = 0;
670
671         while (p) {
672                 dbg("[%02d] %08x - %08x\n",
673                     cnt++, (u32)p->base, (u32)p->base + p->length - 1);
674                 p = p->next;
675         }
676 }
677
678 void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
679 {
680         dbg("I/O resource:\n");
681         dump_resource(bridge->io_head);
682         dbg("MEM resource:\n");
683         dump_resource(bridge->mem_head);
684         dbg("PMEM resource:\n");
685         dump_resource(bridge->p_mem_head);
686         dbg("BUS resource:\n");
687         dump_resource(bridge->bus_head);
688 }
689
690 void acpiphp_dump_func_resource(struct acpiphp_func *func)
691 {
692         dbg("I/O resource:\n");
693         dump_resource(func->io_head);
694         dbg("MEM resource:\n");
695         dump_resource(func->mem_head);
696         dbg("PMEM resource:\n");
697         dump_resource(func->p_mem_head);
698         dbg("BUS resource:\n");
699         dump_resource(func->bus_head);
700 }