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-kouchi@cq.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
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>,<h-aono@ap.jp.nec.com>
32 #include <linux/config.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>
42 #include <linux/init.h>
44 #include <linux/string.h>
46 #include <linux/errno.h>
47 #include <linux/ioport.h>
48 #include <linux/slab.h>
49 #include <linux/interrupt.h>
50 #include <linux/timer.h>
52 #include <linux/ioctl.h>
53 #include <linux/fcntl.h>
55 #include <linux/list.h>
57 #include "pci_hotplug.h"
60 #define MY_NAME "acpiphp_res"
64 * sort_by_size - sort nodes by their length, smallest first
66 static int sort_by_size(struct pci_resource **head)
68 struct pci_resource *current_res;
69 struct pci_resource *next_res;
78 while (out_of_order) {
81 /* Special case for swapping list head */
82 if (((*head)->next) &&
83 ((*head)->length > (*head)->next->length)) {
86 *head = (*head)->next;
87 current_res->next = (*head)->next;
88 (*head)->next = current_res;
93 while (current_res->next && current_res->next->next) {
94 if (current_res->next->length > current_res->next->next->length) {
96 next_res = current_res->next;
97 current_res->next = current_res->next->next;
98 current_res = current_res->next;
99 next_res->next = current_res->next;
100 current_res->next = next_res;
102 current_res = current_res->next;
104 } /* End of out_of_order loop */
111 * sort_by_max_size - sort nodes by their length, largest first
113 static int sort_by_max_size(struct pci_resource **head)
115 struct pci_resource *current_res;
116 struct pci_resource *next_res;
117 int out_of_order = 1;
122 if (!((*head)->next))
125 while (out_of_order) {
128 /* Special case for swapping list head */
129 if (((*head)->next) &&
130 ((*head)->length < (*head)->next->length)) {
133 *head = (*head)->next;
134 current_res->next = (*head)->next;
135 (*head)->next = current_res;
140 while (current_res->next && current_res->next->next) {
141 if (current_res->next->length < current_res->next->next->length) {
143 next_res = current_res->next;
144 current_res->next = current_res->next->next;
145 current_res = current_res->next;
146 next_res->next = current_res->next;
147 current_res->next = next_res;
149 current_res = current_res->next;
151 } /* End of out_of_order loop */
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;
179 if (acpiphp_resource_sort_and_combine(head))
182 if (sort_by_size(head))
185 for (node = *head; node; node = node->next) {
186 if (node->length < size)
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)
198 split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
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);
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)
231 /* If we got here, then it is the right size
232 Now take it out of the list */
237 while (prevnode->next != node)
238 prevnode = prevnode->next;
240 prevnode->next = node->next;
252 * get_max_resource - get the largest resource
254 * Gets the largest node that is at least "size" big from the
255 * list pointed to by head. It aligns the node on top and bottom
256 * to "size" alignment before returning it.
258 struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
260 struct pci_resource *max;
261 struct pci_resource *temp;
262 struct pci_resource *split_node;
268 if (acpiphp_resource_sort_and_combine(head))
271 if (sort_by_max_size(head))
274 for (max = *head;max; max = max->next) {
276 /* If not big enough we could probably just bail,
277 instead we'll continue to the next. */
278 if (max->length < size)
281 if (max->base & (size - 1)) {
282 /* this one isn't base aligned properly
283 so we'll make a new entry and split it up */
284 temp_qword = (max->base | (size-1)) + 1;
286 /* Short circuit if adjusted size is too small */
287 if ((max->length - (temp_qword - max->base)) < size)
290 split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
295 max->base = temp_qword;
296 max->length -= split_node->length;
298 /* Put it next in the list */
299 split_node->next = max->next;
300 max->next = split_node;
303 if ((max->base + max->length) & (size - 1)) {
304 /* this one isn't end aligned properly at the top
305 so we'll make a new entry and split it up */
306 temp_qword = ((max->base + max->length) & ~(size - 1));
308 split_node = acpiphp_make_resource(temp_qword,
309 max->length + max->base - temp_qword);
314 max->length -= split_node->length;
316 /* Put it in the list */
317 split_node->next = max->next;
318 max->next = split_node;
321 /* Make sure it didn't shrink too much when we aligned it */
322 if (max->length < size)
325 /* Now take it out of the list */
326 temp = (struct pci_resource*) *head;
330 while (temp && temp->next != max) {
334 temp->next = max->next;
341 /* If we get here, we couldn't find one */
347 * get_resource - get resource (mem, pfmem)
349 * this function sorts the resource list by size and then
350 * returns the first node of "size" length. If it finds a node
351 * larger than "size" it will split it up.
353 * size must be a power of two.
356 struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
358 struct pci_resource *prevnode;
359 struct pci_resource *node;
360 struct pci_resource *split_node;
366 if (acpiphp_resource_sort_and_combine(head))
369 if (sort_by_size(head))
372 for (node = *head; node; node = node->next) {
373 dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
374 __FUNCTION__, size, node, (u32)node->base, node->length);
375 if (node->length < size)
378 if (node->base & (size - 1)) {
379 dbg("%s: not aligned\n", __FUNCTION__);
380 /* this one isn't base aligned properly
381 so we'll make a new entry and split it up */
382 temp_qword = (node->base | (size-1)) + 1;
384 /* Short circuit if adjusted size is too small */
385 if ((node->length - (temp_qword - node->base)) < size)
388 split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
393 node->base = temp_qword;
394 node->length -= split_node->length;
396 /* Put it in the list */
397 split_node->next = node->next;
398 node->next = split_node;
399 } /* End of non-aligned base */
401 /* Don't need to check if too small since we already did */
402 if (node->length > size) {
403 dbg("%s: too big\n", __FUNCTION__);
404 /* this one is longer than we need
405 so we'll make a new entry and split it up */
406 split_node = acpiphp_make_resource(node->base + size, node->length - size);
413 /* Put it in the list */
414 split_node->next = node->next;
415 node->next = split_node;
416 } /* End of too big on top end */
418 dbg("%s: got one!!!\n", __FUNCTION__);
419 /* If we got here, then it is the right size
420 Now take it out of the list */
425 while (prevnode->next != node)
426 prevnode = prevnode->next;
428 prevnode->next = node->next;
438 * get_resource_with_base - get resource with specific base address
441 * returns the first node of "size" length located at specified base address.
442 * If it finds a node larger than "size" it will split it up.
444 * size must be a power of two.
447 struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
449 struct pci_resource *prevnode;
450 struct pci_resource *node;
451 struct pci_resource *split_node;
457 if (acpiphp_resource_sort_and_combine(head))
460 for (node = *head; node; node = node->next) {
461 dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
462 (u32)base, size, node, (u32)node->base, node->length);
463 if (node->base > base)
466 if ((node->base + node->length) < (base + size))
469 if (node->base < base) {
471 /* this one isn't base aligned properly
472 so we'll make a new entry and split it up */
475 /* Short circuit if adjusted size is too small */
476 if ((node->length - (temp_qword - node->base)) < size)
479 split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
484 node->base = temp_qword;
485 node->length -= split_node->length;
487 /* Put it in the list */
488 split_node->next = node->next;
489 node->next = split_node;
492 dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
493 (u32)base, size, node, (u32)node->base, node->length);
495 /* Don't need to check if too small since we already did */
496 if (node->length > size) {
498 /* this one is longer than we need
499 so we'll make a new entry and split it up */
500 split_node = acpiphp_make_resource(node->base + size, node->length - size);
507 /* Put it in the list */
508 split_node->next = node->next;
509 node->next = split_node;
510 } /* End of too big on top end */
512 dbg(": got one!!!\n");
513 /* If we got here, then it is the right size
514 Now take it out of the list */
519 while (prevnode->next != node)
520 prevnode = prevnode->next;
522 prevnode->next = node->next;
533 * acpiphp_resource_sort_and_combine
535 * Sorts all of the nodes in the list in ascending order by
536 * their base addresses. Also does garbage collection by
537 * combining adjacent nodes.
539 * returns 0 if success
541 int acpiphp_resource_sort_and_combine (struct pci_resource **head)
543 struct pci_resource *node1;
544 struct pci_resource *node2;
545 int out_of_order = 1;
550 dbg("*head->next = %p\n",(*head)->next);
553 return 0; /* only one item on the list, already sorted! */
555 dbg("*head->base = 0x%x\n",(u32)(*head)->base);
556 dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
557 while (out_of_order) {
560 /* Special case for swapping list head */
561 if (((*head)->next) &&
562 ((*head)->base > (*head)->next->base)) {
564 (*head) = (*head)->next;
565 node1->next = (*head)->next;
566 (*head)->next = node1;
572 while (node1->next && node1->next->next) {
573 if (node1->next->base > node1->next->next->base) {
576 node1->next = node1->next->next;
578 node2->next = node1->next;
583 } /* End of out_of_order loop */
587 while (node1 && node1->next) {
588 if ((node1->base + node1->length) == node1->next->base) {
591 node1->length += node1->next->length;
593 node1->next = node1->next->next;
604 * acpiphp_make_resource - make resource structure
605 * @base: base address of a resource
606 * @length: length of a resource
608 struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
610 struct pci_resource *res;
612 res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
614 memset(res, 0, sizeof(struct pci_resource));
616 res->length = length;
624 * acpiphp_move_resource - move linked resources from one to another
625 * @from: head of linked resource list
626 * @to: head of linked resource list
628 void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
630 struct pci_resource *tmp;
639 /* *from = NULL is guaranteed */
644 * acpiphp_free_resource - free all linked resources
645 * @res: head of linked resource list
647 void acpiphp_free_resource (struct pci_resource **res)
649 struct pci_resource *tmp;
657 /* *res = NULL is guaranteed */
661 /* debug support functions; will go away sometime :) */
662 static void dump_resource(struct pci_resource *head)
664 struct pci_resource *p;
671 dbg("[%02d] %08x - %08x\n",
672 cnt++, (u32)p->base, (u32)p->base + p->length - 1);
677 void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
679 dbg("I/O resource:\n");
680 dump_resource(bridge->io_head);
681 dbg("MEM resource:\n");
682 dump_resource(bridge->mem_head);
683 dbg("PMEM resource:\n");
684 dump_resource(bridge->p_mem_head);
685 dbg("BUS resource:\n");
686 dump_resource(bridge->bus_head);
689 void acpiphp_dump_func_resource(struct acpiphp_func *func)
691 dbg("I/O resource:\n");
692 dump_resource(func->io_head);
693 dbg("MEM resource:\n");
694 dump_resource(func->mem_head);
695 dbg("PMEM resource:\n");
696 dump_resource(func->p_mem_head);
697 dbg("BUS resource:\n");
698 dump_resource(func->bus_head);