Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / pci / hotplug / acpiphp_res.c
blobf54b1fa7b75af98ca8fde94147e027dea29d0526
1 /*
2 * ACPI PCI HotPlug Utility functions
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
11 * All rights reserved.
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.
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.
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.
28 * Send feedback to <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com>
32 #include <linux/init.h>
33 #include <linux/module.h>
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>
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>
51 #include <linux/ioctl.h>
52 #include <linux/fcntl.h>
54 #include <linux/list.h>
56 #include "pci_hotplug.h"
57 #include "acpiphp.h"
59 #define MY_NAME "acpiphp_res"
63 * sort_by_size - sort nodes by their length, smallest first
65 static int sort_by_size(struct pci_resource **head)
67 struct pci_resource *current_res;
68 struct pci_resource *next_res;
69 int out_of_order = 1;
71 if (!(*head))
72 return 1;
74 if (!((*head)->next))
75 return 0;
77 while (out_of_order) {
78 out_of_order = 0;
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;
90 current_res = *head;
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;
103 } /* End of out_of_order loop */
105 return 0;
108 #if 0
110 * sort_by_max_size - sort nodes by their length, largest first
112 static int sort_by_max_size(struct pci_resource **head)
114 struct pci_resource *current_res;
115 struct pci_resource *next_res;
116 int out_of_order = 1;
118 if (!(*head))
119 return 1;
121 if (!((*head)->next))
122 return 0;
124 while (out_of_order) {
125 out_of_order = 0;
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;
137 current_res = *head;
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;
150 } /* End of out_of_order loop */
152 return 0;
154 #endif
157 * get_io_resource - get resource for I/O ports
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.
164 * size must be a power of two.
166 * difference from get_resource is handling of ISA aliasing space.
169 struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size)
171 struct pci_resource *prevnode;
172 struct pci_resource *node;
173 struct pci_resource *split_node;
174 u64 temp_qword;
176 if (!(*head))
177 return NULL;
179 if (acpiphp_resource_sort_and_combine(head))
180 return NULL;
182 if (sort_by_size(head))
183 return NULL;
185 for (node = *head; node; node = node->next) {
186 if (node->length < size)
187 continue;
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;
194 /* Short circuit if adjusted size is too small */
195 if ((node->length - (temp_qword - node->base)) < size)
196 continue;
198 split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
200 if (!split_node)
201 return NULL;
203 node->base = temp_qword;
204 node->length -= split_node->length;
206 /* Put it in the list */
207 split_node->next = node->next;
208 node->next = split_node;
209 } /* End of non-aligned base */
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);
217 if (!split_node)
218 return NULL;
220 node->length = size;
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 */
227 /* For IO make sure it's not in the ISA aliasing space */
228 if ((node->base & 0x300L) && !(node->base & 0xfffff000))
229 continue;
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;
240 prevnode->next = node->next;
242 node->next = NULL;
243 /* Stop looping */
244 break;
247 return node;
251 #if 0
253 * get_max_resource - get the largest resource
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.
259 static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
261 struct pci_resource *max;
262 struct pci_resource *temp;
263 struct pci_resource *split_node;
264 u64 temp_qword;
266 if (!(*head))
267 return NULL;
269 if (acpiphp_resource_sort_and_combine(head))
270 return NULL;
272 if (sort_by_max_size(head))
273 return NULL;
275 for (max = *head;max; max = max->next) {
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;
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;
287 /* Short circuit if adjusted size is too small */
288 if ((max->length - (temp_qword - max->base)) < size)
289 continue;
291 split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
293 if (!split_node)
294 return NULL;
296 max->base = temp_qword;
297 max->length -= split_node->length;
299 /* Put it next in the list */
300 split_node->next = max->next;
301 max->next = split_node;
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));
309 split_node = acpiphp_make_resource(temp_qword,
310 max->length + max->base - temp_qword);
312 if (!split_node)
313 return NULL;
315 max->length -= split_node->length;
317 /* Put it in the list */
318 split_node->next = max->next;
319 max->next = split_node;
322 /* Make sure it didn't shrink too much when we aligned it */
323 if (max->length < size)
324 continue;
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;
335 temp->next = max->next;
338 max->next = NULL;
339 return max;
342 /* If we get here, we couldn't find one */
343 return NULL;
345 #endif
348 * get_resource - get resource (mem, pfmem)
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.
354 * size must be a power of two.
357 struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
359 struct pci_resource *prevnode;
360 struct pci_resource *node;
361 struct pci_resource *split_node;
362 u64 temp_qword;
364 if (!(*head))
365 return NULL;
367 if (acpiphp_resource_sort_and_combine(head))
368 return NULL;
370 if (sort_by_size(head))
371 return NULL;
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;
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;
385 /* Short circuit if adjusted size is too small */
386 if ((node->length - (temp_qword - node->base)) < size)
387 continue;
389 split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
391 if (!split_node)
392 return NULL;
394 node->base = temp_qword;
395 node->length -= split_node->length;
397 /* Put it in the list */
398 split_node->next = node->next;
399 node->next = split_node;
400 } /* End of non-aligned base */
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);
409 if (!split_node)
410 return NULL;
412 node->length = size;
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 */
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;
429 prevnode->next = node->next;
431 node->next = NULL;
432 /* Stop looping */
433 break;
435 return node;
439 * get_resource_with_base - get resource with specific base address
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.
445 * size must be a power of two.
448 struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
450 struct pci_resource *prevnode;
451 struct pci_resource *node;
452 struct pci_resource *split_node;
453 u64 temp_qword;
455 if (!(*head))
456 return NULL;
458 if (acpiphp_resource_sort_and_combine(head))
459 return NULL;
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;
467 if ((node->base + node->length) < (base + size))
468 continue;
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;
476 /* Short circuit if adjusted size is too small */
477 if ((node->length - (temp_qword - node->base)) < size)
478 continue;
480 split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
482 if (!split_node)
483 return NULL;
485 node->base = temp_qword;
486 node->length -= split_node->length;
488 /* Put it in the list */
489 split_node->next = node->next;
490 node->next = split_node;
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);
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);
503 if (!split_node)
504 return NULL;
506 node->length = size;
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 */
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;
523 prevnode->next = node->next;
525 node->next = NULL;
526 /* Stop looping */
527 break;
529 return node;
534 * acpiphp_resource_sort_and_combine
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.
540 * returns 0 if success
542 int acpiphp_resource_sort_and_combine (struct pci_resource **head)
544 struct pci_resource *node1;
545 struct pci_resource *node2;
546 int out_of_order = 1;
548 if (!(*head))
549 return 1;
551 dbg("*head->next = %p\n",(*head)->next);
553 if (!(*head)->next)
554 return 0; /* only one item on the list, already sorted! */
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;
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++;
571 node1 = (*head);
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;
584 } /* End of out_of_order loop */
586 node1 = *head;
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;
600 return 0;
605 * acpiphp_make_resource - make resource structure
606 * @base: base address of a resource
607 * @length: length of a resource
609 struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
611 struct pci_resource *res;
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;
620 return res;
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
629 void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
631 struct pci_resource *tmp;
633 while (*from) {
634 tmp = (*from)->next;
635 (*from)->next = *to;
636 *to = *from;
637 *from = tmp;
640 /* *from = NULL is guaranteed */
645 * acpiphp_free_resource - free all linked resources
646 * @res: head of linked resource list
648 void acpiphp_free_resource (struct pci_resource **res)
650 struct pci_resource *tmp;
652 while (*res) {
653 tmp = (*res)->next;
654 kfree(*res);
655 *res = tmp;
658 /* *res = NULL is guaranteed */
662 /* debug support functions; will go away sometime :) */
663 static void dump_resource(struct pci_resource *head)
665 struct pci_resource *p;
666 int cnt;
668 p = head;
669 cnt = 0;
671 while (p) {
672 dbg("[%02d] %08x - %08x\n",
673 cnt++, (u32)p->base, (u32)p->base + p->length - 1);
674 p = p->next;
678 void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
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);
690 void acpiphp_dump_func_resource(struct acpiphp_func *func)
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);