aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci
diff options
context:
space:
mode:
authorMyron Stowe <mstowe@redhat.com>2011-11-21 13:54:13 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2012-02-14 11:44:46 -0500
commit925845bd49c6de437dfab3bf8dc654ea3ae21d74 (patch)
tree55d91a9f5335e50571fefa64b10651c38316d314 /arch/x86/pci
parent351fc6d1a5175d587d4f2b00ec7bff79b13ec48a (diff)
x86/PCI: Infrastructure to maintain a list of FW-assigned BIOS BAR values
Commit 58c84eda075 introduced functionality to try and reinstate the original BIOS BAR addresses of a PCI device when normal resource assignment attempts fail. To keep track of the BIOS BAR addresses, struct pci_dev was augmented with an array to hold the BAR addresses of the PCI device: 'resource_size_t fw_addr[DEVICE_COUNT_RESOURCE]'. The reinstatement of BAR addresses is an uncommon event leaving the 'fw_addr' array unused under normal circumstances. This functionality is also currently architecture specific with an implementation limited to x86. As the use of struct pci_dev is so prevalent, having the 'fw_addr' array residing within such seems somewhat wasteful. This patch introduces a stand alone data structure and interfacing routines for maintaining a list of FW-assigned BIOS BAR value entries. Signed-off-by: Myron Stowe <myron.stowe@redhat.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'arch/x86/pci')
-rw-r--r--arch/x86/pci/i386.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 91821a1a0c3a..5a1edf2b5386 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -39,6 +39,85 @@
39#include <asm/io_apic.h> 39#include <asm/io_apic.h>
40 40
41 41
42/*
43 * This list of dynamic mappings is for temporarily maintaining
44 * original BIOS BAR addresses for possible reinstatement.
45 */
46struct pcibios_fwaddrmap {
47 struct list_head list;
48 struct pci_dev *dev;
49 resource_size_t fw_addr[DEVICE_COUNT_RESOURCE];
50};
51
52static LIST_HEAD(pcibios_fwaddrmappings);
53static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock);
54
55/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */
56static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev)
57{
58 struct pcibios_fwaddrmap *map;
59
60 list_for_each_entry(map, &pcibios_fwaddrmappings, list)
61 if (map->dev == dev)
62 return map;
63
64 return NULL;
65}
66
67static void
68pcibios_save_fw_addr(struct pci_dev *dev, int idx, resource_size_t fw_addr)
69{
70 unsigned long flags;
71 struct pcibios_fwaddrmap *map;
72
73 spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
74 map = pcibios_fwaddrmap_lookup(dev);
75 if (!map) {
76 spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
77 map = kzalloc(sizeof(*map), GFP_KERNEL);
78 if (!map)
79 return;
80
81 map->dev = pci_dev_get(dev);
82 map->fw_addr[idx] = fw_addr;
83 INIT_LIST_HEAD(&map->list);
84
85 spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
86 list_add_tail(&map->list, &pcibios_fwaddrmappings);
87 } else
88 map->fw_addr[idx] = fw_addr;
89 spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
90}
91
92resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
93{
94 unsigned long flags;
95 struct pcibios_fwaddrmap *map;
96 resource_size_t fw_addr = 0;
97
98 spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
99 map = pcibios_fwaddrmap_lookup(dev);
100 if (map)
101 fw_addr = map->fw_addr[idx];
102 spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
103
104 return fw_addr;
105}
106
107static void pcibios_fw_addr_list_del(void)
108{
109 unsigned long flags;
110 struct pcibios_fwaddrmap *entry, *next;
111
112 spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
113 list_for_each_entry_safe(entry, next, &pcibios_fwaddrmappings, list) {
114 list_del(&entry->list);
115 pci_dev_put(entry->dev);
116 kfree(entry);
117 }
118 spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
119}
120
42static int 121static int
43skip_isa_ioresource_align(struct pci_dev *dev) { 122skip_isa_ioresource_align(struct pci_dev *dev) {
44 123