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
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>
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"
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
;
77 while (out_of_order
) {
80 /* Special case for swapping list head */
81 if (((*head
)->next
) &&
82 ((*head
)->length
> (*head
)->next
->length
)) {
85 *head
= (*head
)->next
;
86 current_res
->next
= (*head
)->next
;
87 (*head
)->next
= current_res
;
92 while (current_res
->next
&& current_res
->next
->next
) {
93 if (current_res
->next
->length
> current_res
->next
->next
->length
) {
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
;
101 current_res
= current_res
->next
;
103 } /* End of out_of_order loop */
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;
121 if (!((*head
)->next
))
124 while (out_of_order
) {
127 /* Special case for swapping list head */
128 if (((*head
)->next
) &&
129 ((*head
)->length
< (*head
)->next
->length
)) {
132 *head
= (*head
)->next
;
133 current_res
->next
= (*head
)->next
;
134 (*head
)->next
= current_res
;
139 while (current_res
->next
&& current_res
->next
->next
) {
140 if (current_res
->next
->length
< current_res
->next
->next
->length
) {
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
;
148 current_res
= current_res
->next
;
150 } /* 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
) && !(node
->base
& 0xfffff000))
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
;
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
;
269 if (acpiphp_resource_sort_and_combine(head
))
272 if (sort_by_max_size(head
))
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
)
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
)
291 split_node
= acpiphp_make_resource(max
->base
, temp_qword
- max
->base
);
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
);
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
)
326 /* Now take it out of the list */
327 temp
= (struct pci_resource
*) *head
;
331 while (temp
&& temp
->next
!= max
) {
335 temp
->next
= max
->next
;
342 /* If we get here, we couldn't find one */
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
;
367 if (acpiphp_resource_sort_and_combine(head
))
370 if (sort_by_size(head
))
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
)
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
)
389 split_node
= acpiphp_make_resource(node
->base
, temp_qword
- node
->base
);
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
);
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 */
426 while (prevnode
->next
!= node
)
427 prevnode
= prevnode
->next
;
429 prevnode
->next
= node
->next
;
439 * get_resource_with_base - get resource with specific base address
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
;
458 if (acpiphp_resource_sort_and_combine(head
))
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
)
467 if ((node
->base
+ node
->length
) < (base
+ size
))
470 if (node
->base
< base
) {
472 /* this one isn't base aligned properly
473 so we'll make a new entry and split it up */
476 /* Short circuit if adjusted size is too small */
477 if ((node
->length
- (temp_qword
- node
->base
)) < size
)
480 split_node
= acpiphp_make_resource(node
->base
, temp_qword
- node
->base
);
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
) {
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
);
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 */
520 while (prevnode
->next
!= node
)
521 prevnode
= prevnode
->next
;
523 prevnode
->next
= node
->next
;
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;
551 dbg("*head->next = %p\n",(*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
) {
561 /* Special case for swapping list head */
562 if (((*head
)->next
) &&
563 ((*head
)->base
> (*head
)->next
->base
)) {
565 (*head
) = (*head
)->next
;
566 node1
->next
= (*head
)->next
;
567 (*head
)->next
= node1
;
573 while (node1
->next
&& node1
->next
->next
) {
574 if (node1
->next
->base
> node1
->next
->next
->base
) {
577 node1
->next
= node1
->next
->next
;
579 node2
->next
= node1
->next
;
584 } /* End of out_of_order loop */
588 while (node1
&& node1
->next
) {
589 if ((node1
->base
+ node1
->length
) == node1
->next
->base
) {
592 node1
->length
+= node1
->next
->length
;
594 node1
->next
= node1
->next
->next
;
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
);
615 memset(res
, 0, sizeof(struct pci_resource
));
617 res
->length
= length
;
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
;
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
;
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
;
672 dbg("[%02d] %08x - %08x\n",
673 cnt
++, (u32
)p
->base
, (u32
)p
->base
+ p
->length
- 1);
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
);