2 * PCI Express Hot Plug Controller Driver
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) 2003-2004 Intel Corporation
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
19 * NON INFRINGEMENT. See the GNU General Public License for more
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/types.h>
34 #include <linux/slab.h>
35 #include <linux/workqueue.h>
36 #include <linux/proc_fs.h>
37 #include <linux/pci.h>
41 #include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependant we are... */
45 int pciehp_configure_device (struct controller
* ctrl
, struct pci_func
* func
)
48 struct pci_bus
*child
;
51 if (func
->pci_dev
== NULL
)
52 func
->pci_dev
= pci_find_slot(func
->bus
, PCI_DEVFN(func
->device
, func
->function
));
54 /* Still NULL ? Well then scan for it ! */
55 if (func
->pci_dev
== NULL
) {
56 dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__
);
58 num
= pci_scan_slot(ctrl
->pci_dev
->subordinate
, PCI_DEVFN(func
->device
, func
->function
));
61 pci_bus_add_devices(ctrl
->pci_dev
->subordinate
);
63 func
->pci_dev
= pci_find_slot(func
->bus
, PCI_DEVFN(func
->device
, func
->function
));
64 if (func
->pci_dev
== NULL
) {
65 dbg("ERROR: pci_dev still null\n");
70 if (func
->pci_dev
->hdr_type
== PCI_HEADER_TYPE_BRIDGE
) {
71 pci_read_config_byte(func
->pci_dev
, PCI_SECONDARY_BUS
, &bus
);
72 child
= pci_add_new_bus(func
->pci_dev
->bus
, (func
->pci_dev
), bus
);
73 pci_do_scan_bus(child
);
81 int pciehp_unconfigure_device(struct pci_func
* func
)
87 dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__
, func
->bus
,
88 func
->device
, func
->function
);
89 pbus
= func
->pci_dev
->bus
;
91 for (j
=0; j
<8 ; j
++) {
92 struct pci_dev
* temp
= pci_find_slot(func
->bus
,
93 (func
->device
<< 3) | j
);
95 pci_remove_bus_device(temp
);
99 * Some PCI Express root ports require fixup after hot-plug operation.
102 pci_fixup_device(pci_fixup_final
, pbus
->self
);
110 * @bus_num: bus number of PCI device
111 * @dev_num: device number of PCI device
112 * @slot: pointer to u8 where slot number will be returned
114 int pciehp_set_irq (u8 bus_num
, u8 dev_num
, u8 int_pin
, u8 irq_num
)
116 #if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
119 struct pci_dev fakedev
;
120 struct pci_bus fakebus
;
122 fakedev
.devfn
= dev_num
<< 3;
123 fakedev
.bus
= &fakebus
;
124 fakebus
.number
= bus_num
;
125 dbg("%s: dev %d, bus %d, pin %d, num %d\n",
126 __FUNCTION__
, dev_num
, bus_num
, int_pin
, irq_num
);
127 rc
= pcibios_set_irq_routing(&fakedev
, int_pin
- 0x0a, irq_num
);
128 dbg("%s: rc %d\n", __FUNCTION__
, rc
);
132 /* set the Edge Level Control Register (ELCR) */
133 temp_word
= inb(0x4d0);
134 temp_word
|= inb(0x4d1) << 8;
136 temp_word
|= 0x01 << irq_num
;
138 /* This should only be for x86 as it sets the Edge Level Control Register */
139 outb((u8
) (temp_word
& 0xFF), 0x4d0);
140 outb((u8
) ((temp_word
& 0xFF00) >> 8), 0x4d1);
145 /* More PCI configuration routines; this time centered around hotplug controller */
151 * Reads configuration for all slots in a PCI bus and saves info.
153 * Note: For non-hot plug busses, the slot # saved is the device #
155 * returns 0 if success
157 int pciehp_save_config(struct controller
*ctrl
, int busnumber
, int num_ctlr_slots
, int first_device_num
)
164 struct pci_func
*new_slot
;
173 int is_hot_plug
= num_ctlr_slots
|| first_device_num
;
174 struct pci_bus lpci_bus
, *pci_bus
;
175 int FirstSupported
, LastSupported
;
177 dbg("%s: Enter\n", __FUNCTION__
);
179 memcpy(&lpci_bus
, ctrl
->pci_dev
->subordinate
, sizeof(lpci_bus
));
182 dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__
,
183 num_ctlr_slots
, first_device_num
);
185 /* Decide which slots are supported */
187 /*********************************
188 * is_hot_plug is the slot mask
189 *********************************/
190 FirstSupported
= first_device_num
;
191 LastSupported
= FirstSupported
+ num_ctlr_slots
- 1;
194 LastSupported
= 0x1F;
197 dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported
,
200 /* Save PCI configuration space for all devices in supported slots */
201 dbg("%s: pci_bus->number = %x\n", __FUNCTION__
, pci_bus
->number
);
202 pci_bus
->number
= busnumber
;
203 dbg("%s: bus = %x, dev = %x\n", __FUNCTION__
, busnumber
, device
);
204 for (device
= FirstSupported
; device
<= LastSupported
; device
++) {
206 rc
= pci_bus_read_config_dword(pci_bus
, PCI_DEVFN(device
, 0),
209 if (ID
!= 0xFFFFFFFF) { /* device in slot */
210 dbg("%s: ID = %x\n", __FUNCTION__
, ID
);
211 rc
= pci_bus_read_config_byte(pci_bus
, PCI_DEVFN(device
, 0),
216 rc
= pci_bus_read_config_byte(pci_bus
, PCI_DEVFN(device
, 0),
217 PCI_HEADER_TYPE
, &header_type
);
221 dbg("class_code = %x, header_type = %x\n", class_code
, header_type
);
223 /* If multi-function device, set max_functions to 8 */
224 if (header_type
& 0x80)
233 dbg("%s: In do loop\n", __FUNCTION__
);
235 if ((header_type
& 0x7F) == PCI_HEADER_TYPE_BRIDGE
) { /* P-P Bridge */
236 /* Recurse the subordinate bus
237 * get the subordinate bus number
239 rc
= pci_bus_read_config_byte(pci_bus
,
240 PCI_DEVFN(device
, function
),
241 PCI_SECONDARY_BUS
, &secondary_bus
);
245 sub_bus
= (int) secondary_bus
;
247 /* Save secondary bus cfg spc with this recursive call. */
248 rc
= pciehp_save_config(ctrl
, sub_bus
, 0, 0);
255 new_slot
= pciehp_slot_find(busnumber
, device
, index
++);
257 dbg("%s: new_slot = %p bus %x dev %x fun %x\n",
258 __FUNCTION__
, new_slot
, busnumber
, device
, index
-1);
260 while (new_slot
&& (new_slot
->function
!= (u8
) function
)) {
261 new_slot
= pciehp_slot_find(busnumber
, device
, index
++);
262 dbg("%s: while loop, new_slot = %p bus %x dev %x fun %x\n",
263 __FUNCTION__
, new_slot
, busnumber
, device
, index
-1);
266 /* Setup slot structure. */
267 new_slot
= pciehp_slot_create(busnumber
);
268 dbg("%s: if, new_slot = %p bus %x dev %x fun %x\n",
269 __FUNCTION__
, new_slot
, busnumber
, device
, function
);
271 if (new_slot
== NULL
)
275 new_slot
->bus
= (u8
) busnumber
;
276 new_slot
->device
= (u8
) device
;
277 new_slot
->function
= (u8
) function
;
278 new_slot
->is_a_board
= 1;
279 new_slot
->switch_save
= 0x10;
280 /* In case of unsupported board */
281 new_slot
->status
= DevError
;
282 new_slot
->pci_dev
= pci_find_slot(new_slot
->bus
,
283 (new_slot
->device
<< 3) | new_slot
->function
);
284 dbg("new_slot->pci_dev = %p\n", new_slot
->pci_dev
);
286 for (cloop
= 0; cloop
< 0x20; cloop
++) {
287 rc
= pci_bus_read_config_dword(pci_bus
,
288 PCI_DEVFN(device
, function
),
290 (u32
*) &(new_slot
->config_space
[cloop
]));
291 /* dbg("new_slot->config_space[%x] = %x\n",
292 cloop, new_slot->config_space[cloop]); */
301 /* this loop skips to the next present function
302 * reading in Class Code and Header type.
305 while ((function
< max_functions
)&&(!stop_it
)) {
306 dbg("%s: In while loop \n", __FUNCTION__
);
307 rc
= pci_bus_read_config_dword(pci_bus
,
308 PCI_DEVFN(device
, function
),
311 if (ID
== 0xFFFFFFFF) { /* nothing there. */
313 dbg("Nothing there\n");
314 } else { /* Something there */
315 rc
= pci_bus_read_config_byte(pci_bus
,
316 PCI_DEVFN(device
, function
),
321 rc
= pci_bus_read_config_byte(pci_bus
,
322 PCI_DEVFN(device
, function
),
323 PCI_HEADER_TYPE
, &header_type
);
327 dbg("class_code = %x, header_type = %x\n", class_code
, header_type
);
332 } while (function
< max_functions
);
333 /* End of IF (device in slot?) */
334 } else if (is_hot_plug
) {
335 /* Setup slot structure with entry for empty slot */
336 new_slot
= pciehp_slot_create(busnumber
);
338 if (new_slot
== NULL
) {
341 dbg("new_slot = %p, bus = %x, dev = %x, fun = %x\n", new_slot
,
342 new_slot
->bus
, new_slot
->device
, new_slot
->function
);
344 new_slot
->bus
= (u8
) busnumber
;
345 new_slot
->device
= (u8
) device
;
346 new_slot
->function
= 0;
347 new_slot
->is_a_board
= 0;
348 new_slot
->presence_save
= 0;
349 new_slot
->switch_save
= 0;
351 } /* End of FOR loop */
353 dbg("%s: Exit\n", __FUNCTION__
);
359 * pciehp_save_slot_config
361 * Saves configuration info for all PCI devices in a given slot
362 * including subordinate busses.
364 * returns 0 if success
366 int pciehp_save_slot_config(struct controller
*ctrl
, struct pci_func
* new_slot
)
378 struct pci_bus lpci_bus
, *pci_bus
;
379 memcpy(&lpci_bus
, ctrl
->pci_dev
->subordinate
, sizeof(lpci_bus
));
381 pci_bus
->number
= new_slot
->bus
;
385 pci_bus_read_config_dword(pci_bus
, PCI_DEVFN(new_slot
->device
, 0),
388 if (ID
!= 0xFFFFFFFF) { /* device in slot */
389 pci_bus_read_config_byte(pci_bus
, PCI_DEVFN(new_slot
->device
, 0),
392 pci_bus_read_config_byte(pci_bus
, PCI_DEVFN(new_slot
->device
, 0),
393 PCI_HEADER_TYPE
, &header_type
);
395 if (header_type
& 0x80) /* Multi-function device */
403 if ((header_type
& 0x7F) == PCI_HEADER_TYPE_BRIDGE
) { /* PCI-PCI Bridge */
404 /* Recurse the subordinate bus */
405 pci_bus_read_config_byte(pci_bus
,
406 PCI_DEVFN(new_slot
->device
, function
),
407 PCI_SECONDARY_BUS
, &secondary_bus
);
409 sub_bus
= (int) secondary_bus
;
411 /* Save the config headers for the secondary bus. */
412 rc
= pciehp_save_config(ctrl
, sub_bus
, 0, 0);
419 new_slot
->status
= 0;
421 for (cloop
= 0; cloop
< 0x20; cloop
++) {
422 pci_bus_read_config_dword(pci_bus
,
423 PCI_DEVFN(new_slot
->device
, function
),
425 (u32
*) &(new_slot
->config_space
[cloop
]));
432 /* this loop skips to the next present function
433 * reading in the Class Code and the Header type.
436 while ((function
< max_functions
) && (!stop_it
)) {
437 pci_bus_read_config_dword(pci_bus
,
438 PCI_DEVFN(new_slot
->device
, function
),
441 if (ID
== 0xFFFFFFFF) { /* nothing there. */
443 } else { /* Something there */
444 pci_bus_read_config_byte(pci_bus
,
445 PCI_DEVFN(new_slot
->device
, function
),
448 pci_bus_read_config_byte(pci_bus
,
449 PCI_DEVFN(new_slot
->device
, function
),
450 PCI_HEADER_TYPE
, &header_type
);
456 } while (function
< max_functions
);
457 } /* End of IF (device in slot?) */
467 * pciehp_save_used_resources
469 * Stores used resource information for existing boards. this is
470 * for boards that were in the system when this driver was loaded.
471 * this function is for hot plug ADD
473 * returns 0 if success
474 * if disable == 1(DISABLE_CARD),
475 * it loops for all functions of the slot and disables them.
476 * else, it just get resources of the function and return.
478 int pciehp_save_used_resources(struct controller
*ctrl
, struct pci_func
*func
, int disable
)
486 u16 w_base
, w_length
;
493 struct pci_resource
*mem_node
= NULL
;
494 struct pci_resource
*p_mem_node
= NULL
;
495 struct pci_resource
*t_mem_node
;
496 struct pci_resource
*io_node
;
497 struct pci_resource
*bus_node
;
498 struct pci_bus lpci_bus
, *pci_bus
;
499 memcpy(&lpci_bus
, ctrl
->pci_dev
->subordinate
, sizeof(lpci_bus
));
503 func
= pciehp_slot_find(func
->bus
, func
->device
, index
++);
505 while ((func
!= NULL
) && func
->is_a_board
) {
506 pci_bus
->number
= func
->bus
;
507 devfn
= PCI_DEVFN(func
->device
, func
->function
);
509 /* Save the command register */
510 pci_bus_read_config_word(pci_bus
, devfn
, PCI_COMMAND
, &save_command
);
515 pci_bus_write_config_word(pci_bus
, devfn
, PCI_COMMAND
, command
);
518 /* Check for Bridge */
519 pci_bus_read_config_byte(pci_bus
, devfn
, PCI_HEADER_TYPE
, &header_type
);
521 if ((header_type
& 0x7F) == PCI_HEADER_TYPE_BRIDGE
) { /* PCI-PCI Bridge */
522 dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n",
523 func
->bus
, func
->device
, save_command
);
525 /* Clear Bridge Control Register */
527 pci_bus_write_config_word(pci_bus
, devfn
, PCI_BRIDGE_CONTROL
, command
);
530 pci_bus_read_config_byte(pci_bus
, devfn
, PCI_SECONDARY_BUS
, &secondary_bus
);
531 pci_bus_read_config_byte(pci_bus
, devfn
, PCI_SUBORDINATE_BUS
, &temp_byte
);
533 bus_node
= kmalloc(sizeof(struct pci_resource
),
538 bus_node
->base
= (ulong
)secondary_bus
;
539 bus_node
->length
= (ulong
)(temp_byte
- secondary_bus
+ 1);
541 bus_node
->next
= func
->bus_head
;
542 func
->bus_head
= bus_node
;
544 /* Save IO base and Limit registers */
545 pci_bus_read_config_byte(pci_bus
, devfn
, PCI_IO_BASE
, &temp_byte
);
547 pci_bus_read_config_byte(pci_bus
, devfn
, PCI_IO_LIMIT
, &temp_byte
);
550 if ((base
<= length
) && (!disable
|| (save_command
& PCI_COMMAND_IO
))) {
551 io_node
= kmalloc(sizeof(struct pci_resource
),
556 io_node
->base
= (ulong
)(base
& PCI_IO_RANGE_MASK
) << 8;
557 io_node
->length
= (ulong
)(length
- base
+ 0x10) << 8;
559 io_node
->next
= func
->io_head
;
560 func
->io_head
= io_node
;
563 /* Save memory base and Limit registers */
564 pci_bus_read_config_word(pci_bus
, devfn
, PCI_MEMORY_BASE
, &w_base
);
565 pci_bus_read_config_word(pci_bus
, devfn
, PCI_MEMORY_LIMIT
, &w_length
);
567 if ((w_base
<= w_length
) && (!disable
|| (save_command
& PCI_COMMAND_MEMORY
))) {
568 mem_node
= kmalloc(sizeof(struct pci_resource
),
573 mem_node
->base
= (ulong
)w_base
<< 16;
574 mem_node
->length
= (ulong
)(w_length
- w_base
+ 0x10) << 16;
576 mem_node
->next
= func
->mem_head
;
577 func
->mem_head
= mem_node
;
579 /* Save prefetchable memory base and Limit registers */
580 pci_bus_read_config_word(pci_bus
, devfn
, PCI_PREF_MEMORY_BASE
, &w_base
);
581 pci_bus_read_config_word(pci_bus
, devfn
, PCI_PREF_MEMORY_LIMIT
, &w_length
);
583 if ((w_base
<= w_length
) && (!disable
|| (save_command
& PCI_COMMAND_MEMORY
))) {
584 p_mem_node
= kmalloc(sizeof(struct pci_resource
),
589 p_mem_node
->base
= (ulong
)w_base
<< 16;
590 p_mem_node
->length
= (ulong
)(w_length
- w_base
+ 0x10) << 16;
592 p_mem_node
->next
= func
->p_mem_head
;
593 func
->p_mem_head
= p_mem_node
;
595 } else if ((header_type
& 0x7F) == PCI_HEADER_TYPE_NORMAL
) {
596 dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n",
597 func
->bus
, func
->device
, save_command
);
599 /* Figure out IO and memory base lengths */
600 for (cloop
= PCI_BASE_ADDRESS_0
; cloop
<= PCI_BASE_ADDRESS_5
; cloop
+= 4) {
601 pci_bus_read_config_dword(pci_bus
, devfn
, cloop
, &save_base
);
603 temp_register
= 0xFFFFFFFF;
604 pci_bus_write_config_dword(pci_bus
, devfn
, cloop
, temp_register
);
605 pci_bus_read_config_dword(pci_bus
, devfn
, cloop
, &temp_register
);
608 pci_bus_write_config_dword(pci_bus
, devfn
, cloop
, save_base
);
613 base
= temp_register
;
615 if ((base
& PCI_BASE_ADDRESS_SPACE_IO
) &&
616 (!disable
|| (save_command
& PCI_COMMAND_IO
))) {
618 /* set temp_register = amount of IO space requested */
619 base
= base
& 0xFFFFFFFCL
;
622 io_node
= kmalloc(sizeof (struct pci_resource
),
627 io_node
->base
= (ulong
)save_base
& PCI_BASE_ADDRESS_IO_MASK
;
628 io_node
->length
= (ulong
)base
;
629 dbg("sur adapter: IO bar=0x%x(length=0x%x)\n",
630 io_node
->base
, io_node
->length
);
632 io_node
->next
= func
->io_head
;
633 func
->io_head
= io_node
;
634 } else { /* map Memory */
635 int prefetchable
= 1;
636 /* struct pci_resources **res_node; */
637 char *res_type_str
= "PMEM";
640 t_mem_node
= kmalloc(sizeof (struct pci_resource
),
645 if (!(base
& PCI_BASE_ADDRESS_MEM_PREFETCH
) &&
646 (!disable
|| (save_command
& PCI_COMMAND_MEMORY
))) {
648 mem_node
= t_mem_node
;
651 p_mem_node
= t_mem_node
;
653 base
= base
& 0xFFFFFFF0L
;
656 switch (temp_register
& PCI_BASE_ADDRESS_MEM_TYPE_MASK
) {
657 case PCI_BASE_ADDRESS_MEM_TYPE_32
:
659 p_mem_node
->base
= (ulong
)save_base
& PCI_BASE_ADDRESS_MEM_MASK
;
660 p_mem_node
->length
= (ulong
)base
;
661 dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
666 p_mem_node
->next
= func
->p_mem_head
;
667 func
->p_mem_head
= p_mem_node
;
669 mem_node
->base
= (ulong
)save_base
& PCI_BASE_ADDRESS_MEM_MASK
;
670 mem_node
->length
= (ulong
)base
;
671 dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
676 mem_node
->next
= func
->mem_head
;
677 func
->mem_head
= mem_node
;
680 case PCI_BASE_ADDRESS_MEM_TYPE_64
:
681 pci_bus_read_config_dword(pci_bus
, devfn
, cloop
+4, &temp_register2
);
682 base64
= temp_register2
;
683 base64
= (base64
<< 32) | save_base
;
685 if (temp_register2
) {
686 dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n",
687 res_type_str
, temp_register2
, (u32
)base64
);
688 base64
&= 0x00000000FFFFFFFFL
;
692 p_mem_node
->base
= base64
& PCI_BASE_ADDRESS_MEM_MASK
;
693 p_mem_node
->length
= base
;
694 dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
699 p_mem_node
->next
= func
->p_mem_head
;
700 func
->p_mem_head
= p_mem_node
;
702 mem_node
->base
= base64
& PCI_BASE_ADDRESS_MEM_MASK
;
703 mem_node
->length
= base
;
704 dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
709 mem_node
->next
= func
->mem_head
;
710 func
->mem_head
= mem_node
;
715 dbg("asur: reserved BAR type=0x%x\n",
720 } /* End of base register loop */
721 } else { /* Some other unknown header type */
722 dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n",
723 func
->bus
, func
->device
);
726 /* find the next device in this slot */
729 func
= pciehp_slot_find(func
->bus
, func
->device
, index
++);
737 * kfree_resource_list: release memory of all list members
738 * @res: resource list to free
741 return_resource_list(struct pci_resource
**func
, struct pci_resource
**res
)
743 struct pci_resource
*node
;
744 struct pci_resource
*t_node
;
750 return_resource(res
, node
);
756 * pciehp_return_board_resources
758 * this routine returns all resources allocated to a board to
759 * the available pool.
761 * returns 0 if success
763 int pciehp_return_board_resources(struct pci_func
* func
,
764 struct resource_lists
* resources
)
768 dbg("%s\n", __FUNCTION__
);
773 return_resource_list(&(func
->io_head
),&(resources
->io_head
));
774 return_resource_list(&(func
->mem_head
),&(resources
->mem_head
));
775 return_resource_list(&(func
->p_mem_head
),&(resources
->p_mem_head
));
776 return_resource_list(&(func
->bus_head
),&(resources
->bus_head
));
778 rc
= pciehp_resource_sort_and_combine(&(resources
->mem_head
));
779 rc
|= pciehp_resource_sort_and_combine(&(resources
->p_mem_head
));
780 rc
|= pciehp_resource_sort_and_combine(&(resources
->io_head
));
781 rc
|= pciehp_resource_sort_and_combine(&(resources
->bus_head
));
787 * kfree_resource_list: release memory of all list members
788 * @res: resource list to free
791 kfree_resource_list(struct pci_resource
**r
)
793 struct pci_resource
*res
, *tres
;
806 * pciehp_destroy_resource_list: put node back in the resource list
807 * @resources: list to put nodes back
809 void pciehp_destroy_resource_list(struct resource_lists
* resources
)
811 kfree_resource_list(&(resources
->io_head
));
812 kfree_resource_list(&(resources
->mem_head
));
813 kfree_resource_list(&(resources
->p_mem_head
));
814 kfree_resource_list(&(resources
->bus_head
));
818 * pciehp_destroy_board_resources: put node back in the resource list
819 * @resources: list to put nodes back
821 void pciehp_destroy_board_resources(struct pci_func
* func
)
823 kfree_resource_list(&(func
->io_head
));
824 kfree_resource_list(&(func
->mem_head
));
825 kfree_resource_list(&(func
->p_mem_head
));
826 kfree_resource_list(&(func
->bus_head
));