diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-07-13 16:23:51 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-07-13 16:23:51 -0400 |
commit | 327309e899662b482c58cf25f574513d38b5788c (patch) | |
tree | 069de438aa0e92dd9b6ba28e6b207e2cd07151a5 /drivers/pci | |
parent | 0c168775709faa74c1b87f1e61046e0c51ade7f3 (diff) | |
parent | c32511e2718618f0b53479eb36e07439aa363a74 (diff) |
Merge upstream 2.6.13-rc3 into ieee80211 branch of netdev-2.6.
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/Kconfig | 5 | ||||
-rw-r--r-- | drivers/pci/hotplug/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/sgi_hotplug.c | 611 | ||||
-rw-r--r-- | drivers/pci/pci-acpi.c | 110 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 198 | ||||
-rw-r--r-- | drivers/pci/pci.c | 28 | ||||
-rw-r--r-- | drivers/pci/pci.h | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv.h | 5 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 14 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 79 | ||||
-rw-r--r-- | drivers/pci/probe.c | 24 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 1 | ||||
-rw-r--r-- | drivers/pci/search.c | 1 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 3 |
16 files changed, 938 insertions, 149 deletions
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 7dea494c0d7b..3657f6199c48 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ | |||
19 | # | 19 | # |
20 | # Some architectures use the generic PCI setup functions | 20 | # Some architectures use the generic PCI setup functions |
21 | # | 21 | # |
22 | obj-$(CONFIG_X86) += setup-bus.o | ||
22 | obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o | 23 | obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o |
23 | obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o | 24 | obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o |
24 | obj-$(CONFIG_PARISC) += setup-bus.o | 25 | obj-$(CONFIG_PARISC) += setup-bus.o |
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 3903f8c559b6..b844bc972324 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c | |||
@@ -54,7 +54,7 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, | |||
54 | 54 | ||
55 | envp[i++] = scratch; | 55 | envp[i++] = scratch; |
56 | length += scnprintf (scratch, buffer_size - length, | 56 | length += scnprintf (scratch, buffer_size - length, |
57 | "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", | 57 | "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", |
58 | pdev->vendor, pdev->device, | 58 | pdev->vendor, pdev->device, |
59 | pdev->subsystem_vendor, pdev->subsystem_device, | 59 | pdev->subsystem_vendor, pdev->subsystem_device, |
60 | (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), | 60 | (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), |
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 1a4d4ca2a4dc..9c4a39ee89b5 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig | |||
@@ -187,9 +187,10 @@ config HOTPLUG_PCI_RPA_DLPAR | |||
187 | 187 | ||
188 | config HOTPLUG_PCI_SGI | 188 | config HOTPLUG_PCI_SGI |
189 | tristate "SGI PCI Hotplug Support" | 189 | tristate "SGI PCI Hotplug Support" |
190 | depends on HOTPLUG_PCI && IA64_SGI_SN2 | 190 | depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC) |
191 | help | 191 | help |
192 | Say Y here if you have an SGI IA64 Altix system. | 192 | Say Y here if you want to use the SGI Altix Hotplug |
193 | Driver for PCI devices. | ||
193 | 194 | ||
194 | When in doubt, say N. | 195 | When in doubt, say N. |
195 | 196 | ||
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 3e632ff8c717..31a307004b94 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile | |||
@@ -14,6 +14,7 @@ obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o | |||
14 | obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o | 14 | obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o |
15 | obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o | 15 | obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o |
16 | obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o | 16 | obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o |
17 | obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o | ||
17 | 18 | ||
18 | pci_hotplug-objs := pci_hotplug_core.o | 19 | pci_hotplug-objs := pci_hotplug_core.o |
19 | 20 | ||
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c new file mode 100644 index 000000000000..323041fd41dc --- /dev/null +++ b/drivers/pci/hotplug/sgi_hotplug.c | |||
@@ -0,0 +1,611 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2005 Silicon Graphics, Inc. All rights reserved. | ||
7 | * | ||
8 | * This work was based on the 2.4/2.6 kernel development by Dick Reigner. | ||
9 | * Work to add BIOS PROM support was completed by Mike Habeck. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/proc_fs.h> | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | #include <asm/sn/addrs.h> | ||
20 | #include <asm/sn/l1.h> | ||
21 | #include <asm/sn/module.h> | ||
22 | #include <asm/sn/pcibr_provider.h> | ||
23 | #include <asm/sn/pcibus_provider_defs.h> | ||
24 | #include <asm/sn/pcidev.h> | ||
25 | #include <asm/sn/sn_sal.h> | ||
26 | #include <asm/sn/types.h> | ||
27 | |||
28 | #include "../pci.h" | ||
29 | #include "pci_hotplug.h" | ||
30 | |||
31 | MODULE_LICENSE("GPL"); | ||
32 | MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); | ||
33 | MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); | ||
34 | |||
35 | #define PCIIO_ASIC_TYPE_TIOCA 4 | ||
36 | #define PCI_SLOT_ALREADY_UP 2 /* slot already up */ | ||
37 | #define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ | ||
38 | #define PCI_L1_ERR 7 /* L1 console command error */ | ||
39 | #define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ | ||
40 | #define PCI_L1_QSIZE 128 /* our L1 message buffer size */ | ||
41 | #define SN_MAX_HP_SLOTS 32 /* max number of hotplug slots */ | ||
42 | #define SGI_HOTPLUG_PROM_REV 0x0420 /* Min. required PROM version */ | ||
43 | |||
44 | /* internal list head */ | ||
45 | static struct list_head sn_hp_list; | ||
46 | |||
47 | /* hotplug_slot struct's private pointer */ | ||
48 | struct slot { | ||
49 | int device_num; | ||
50 | struct pci_bus *pci_bus; | ||
51 | /* this struct for glue internal only */ | ||
52 | struct hotplug_slot *hotplug_slot; | ||
53 | struct list_head hp_list; | ||
54 | }; | ||
55 | |||
56 | struct pcibr_slot_enable_resp { | ||
57 | int resp_sub_errno; | ||
58 | char resp_l1_msg[PCI_L1_QSIZE + 1]; | ||
59 | }; | ||
60 | |||
61 | struct pcibr_slot_disable_resp { | ||
62 | int resp_sub_errno; | ||
63 | char resp_l1_msg[PCI_L1_QSIZE + 1]; | ||
64 | }; | ||
65 | |||
66 | enum sn_pci_req_e { | ||
67 | PCI_REQ_SLOT_ELIGIBLE, | ||
68 | PCI_REQ_SLOT_DISABLE | ||
69 | }; | ||
70 | |||
71 | static int enable_slot(struct hotplug_slot *slot); | ||
72 | static int disable_slot(struct hotplug_slot *slot); | ||
73 | static int get_power_status(struct hotplug_slot *slot, u8 *value); | ||
74 | |||
75 | static struct hotplug_slot_ops sn_hotplug_slot_ops = { | ||
76 | .owner = THIS_MODULE, | ||
77 | .enable_slot = enable_slot, | ||
78 | .disable_slot = disable_slot, | ||
79 | .get_power_status = get_power_status, | ||
80 | }; | ||
81 | |||
82 | static DECLARE_MUTEX(sn_hotplug_sem); | ||
83 | |||
84 | static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) | ||
85 | { | ||
86 | struct pcibus_info *pcibus_info; | ||
87 | int bricktype; | ||
88 | int bus_num; | ||
89 | |||
90 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); | ||
91 | |||
92 | /* Check to see if this is a valid slot on 'pci_bus' */ | ||
93 | if (!(pcibus_info->pbi_valid_devices & (1 << device))) | ||
94 | return -EPERM; | ||
95 | |||
96 | bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); | ||
97 | bus_num = pcibus_info->pbi_buscommon.bs_persist_busnum & 0xf; | ||
98 | |||
99 | /* Do not allow hotplug operations on base I/O cards */ | ||
100 | if ((bricktype == L1_BRICKTYPE_IX || bricktype == L1_BRICKTYPE_IA) && | ||
101 | (bus_num == 1 && device != 1)) | ||
102 | return -EPERM; | ||
103 | |||
104 | return 1; | ||
105 | } | ||
106 | |||
107 | static int sn_pci_bus_valid(struct pci_bus *pci_bus) | ||
108 | { | ||
109 | struct pcibus_info *pcibus_info; | ||
110 | int asic_type; | ||
111 | int bricktype; | ||
112 | |||
113 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); | ||
114 | |||
115 | /* Don't register slots hanging off the TIOCA bus */ | ||
116 | asic_type = pcibus_info->pbi_buscommon.bs_asic_type; | ||
117 | if (asic_type == PCIIO_ASIC_TYPE_TIOCA) | ||
118 | return -EPERM; | ||
119 | |||
120 | /* Only register slots in I/O Bricks that support hotplug */ | ||
121 | bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); | ||
122 | switch (bricktype) { | ||
123 | case L1_BRICKTYPE_IX: | ||
124 | case L1_BRICKTYPE_PX: | ||
125 | case L1_BRICKTYPE_IA: | ||
126 | case L1_BRICKTYPE_PA: | ||
127 | return 1; | ||
128 | break; | ||
129 | default: | ||
130 | return -EPERM; | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | return -EIO; | ||
135 | } | ||
136 | |||
137 | static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, | ||
138 | struct pci_bus *pci_bus, int device) | ||
139 | { | ||
140 | struct pcibus_info *pcibus_info; | ||
141 | struct slot *slot; | ||
142 | |||
143 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); | ||
144 | |||
145 | bss_hotplug_slot->private = kcalloc(1, sizeof(struct slot), | ||
146 | GFP_KERNEL); | ||
147 | if (!bss_hotplug_slot->private) | ||
148 | return -ENOMEM; | ||
149 | slot = (struct slot *)bss_hotplug_slot->private; | ||
150 | |||
151 | bss_hotplug_slot->name = kmalloc(33, GFP_KERNEL); | ||
152 | if (!bss_hotplug_slot->name) { | ||
153 | kfree(bss_hotplug_slot->private); | ||
154 | return -ENOMEM; | ||
155 | } | ||
156 | |||
157 | slot->device_num = device; | ||
158 | slot->pci_bus = pci_bus; | ||
159 | |||
160 | sprintf(bss_hotplug_slot->name, "module_%c%c%c%c%.2d_b_%d_s_%d", | ||
161 | '0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | ||
162 | '0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | ||
163 | '0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | ||
164 | MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid), | ||
165 | MODULE_GET_BPOS(pcibus_info->pbi_moduleid), | ||
166 | ((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf, | ||
167 | device + 1); | ||
168 | |||
169 | slot->hotplug_slot = bss_hotplug_slot; | ||
170 | list_add(&slot->hp_list, &sn_hp_list); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static struct hotplug_slot * sn_hp_destroy(void) | ||
176 | { | ||
177 | struct slot *slot; | ||
178 | struct list_head *list; | ||
179 | struct hotplug_slot *bss_hotplug_slot = NULL; | ||
180 | |||
181 | list_for_each(list, &sn_hp_list) { | ||
182 | slot = list_entry(list, struct slot, hp_list); | ||
183 | bss_hotplug_slot = slot->hotplug_slot; | ||
184 | list_del(&((struct slot *)bss_hotplug_slot->private)-> | ||
185 | hp_list); | ||
186 | break; | ||
187 | } | ||
188 | return bss_hotplug_slot; | ||
189 | } | ||
190 | |||
191 | static void sn_bus_alloc_data(struct pci_dev *dev) | ||
192 | { | ||
193 | struct list_head *node; | ||
194 | struct pci_bus *subordinate_bus; | ||
195 | struct pci_dev *child; | ||
196 | |||
197 | sn_pci_fixup_slot(dev); | ||
198 | |||
199 | /* Recursively sets up the sn_irq_info structs */ | ||
200 | if (dev->subordinate) { | ||
201 | subordinate_bus = dev->subordinate; | ||
202 | list_for_each(node, &subordinate_bus->devices) { | ||
203 | child = list_entry(node, struct pci_dev, bus_list); | ||
204 | sn_bus_alloc_data(child); | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | static void sn_bus_free_data(struct pci_dev *dev) | ||
210 | { | ||
211 | struct list_head *node; | ||
212 | struct pci_bus *subordinate_bus; | ||
213 | struct pci_dev *child; | ||
214 | |||
215 | /* Recursively clean up sn_irq_info structs */ | ||
216 | if (dev->subordinate) { | ||
217 | subordinate_bus = dev->subordinate; | ||
218 | list_for_each(node, &subordinate_bus->devices) { | ||
219 | child = list_entry(node, struct pci_dev, bus_list); | ||
220 | sn_bus_free_data(child); | ||
221 | } | ||
222 | } | ||
223 | sn_pci_unfixup_slot(dev); | ||
224 | } | ||
225 | |||
226 | static u8 sn_power_status_get(struct hotplug_slot *bss_hotplug_slot) | ||
227 | { | ||
228 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
229 | struct pcibus_info *pcibus_info; | ||
230 | u8 retval; | ||
231 | |||
232 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
233 | retval = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); | ||
234 | |||
235 | return retval ? 1 : 0; | ||
236 | } | ||
237 | |||
238 | static void sn_slot_mark_enable(struct hotplug_slot *bss_hotplug_slot, | ||
239 | int device_num) | ||
240 | { | ||
241 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
242 | struct pcibus_info *pcibus_info; | ||
243 | |||
244 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
245 | pcibus_info->pbi_enabled_devices |= (1 << device_num); | ||
246 | } | ||
247 | |||
248 | static void sn_slot_mark_disable(struct hotplug_slot *bss_hotplug_slot, | ||
249 | int device_num) | ||
250 | { | ||
251 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
252 | struct pcibus_info *pcibus_info; | ||
253 | |||
254 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
255 | pcibus_info->pbi_enabled_devices &= ~(1 << device_num); | ||
256 | } | ||
257 | |||
258 | static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, | ||
259 | int device_num) | ||
260 | { | ||
261 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
262 | struct pcibus_info *pcibus_info; | ||
263 | struct pcibr_slot_enable_resp resp; | ||
264 | int rc; | ||
265 | |||
266 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
267 | |||
268 | /* | ||
269 | * Power-on and initialize the slot in the SN | ||
270 | * PCI infrastructure. | ||
271 | */ | ||
272 | rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp); | ||
273 | |||
274 | if (rc == PCI_SLOT_ALREADY_UP) { | ||
275 | dev_dbg(slot->pci_bus->self, "is already active\n"); | ||
276 | return -EPERM; | ||
277 | } | ||
278 | |||
279 | if (rc == PCI_L1_ERR) { | ||
280 | dev_dbg(slot->pci_bus->self, | ||
281 | "L1 failure %d with message: %s", | ||
282 | resp.resp_sub_errno, resp.resp_l1_msg); | ||
283 | return -EPERM; | ||
284 | } | ||
285 | |||
286 | if (rc) { | ||
287 | dev_dbg(slot->pci_bus->self, | ||
288 | "insert failed with error %d sub-error %d\n", | ||
289 | rc, resp.resp_sub_errno); | ||
290 | return -EIO; | ||
291 | } | ||
292 | |||
293 | sn_slot_mark_enable(bss_hotplug_slot, device_num); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, | ||
299 | int device_num, int action) | ||
300 | { | ||
301 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
302 | struct pcibus_info *pcibus_info; | ||
303 | struct pcibr_slot_disable_resp resp; | ||
304 | int rc; | ||
305 | |||
306 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
307 | |||
308 | rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp); | ||
309 | |||
310 | if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_SLOT_ALREADY_DOWN) { | ||
311 | dev_dbg(slot->pci_bus->self, "Slot %s already inactive\n"); | ||
312 | return -ENODEV; | ||
313 | } | ||
314 | |||
315 | if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_EMPTY_33MHZ) { | ||
316 | dev_dbg(slot->pci_bus->self, | ||
317 | "Cannot remove last 33MHz card\n"); | ||
318 | return -EPERM; | ||
319 | } | ||
320 | |||
321 | if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_L1_ERR) { | ||
322 | dev_dbg(slot->pci_bus->self, | ||
323 | "L1 failure %d with message \n%s\n", | ||
324 | resp.resp_sub_errno, resp.resp_l1_msg); | ||
325 | return -EPERM; | ||
326 | } | ||
327 | |||
328 | if (action == PCI_REQ_SLOT_ELIGIBLE && rc) { | ||
329 | dev_dbg(slot->pci_bus->self, | ||
330 | "remove failed with error %d sub-error %d\n", | ||
331 | rc, resp.resp_sub_errno); | ||
332 | return -EIO; | ||
333 | } | ||
334 | |||
335 | if (action == PCI_REQ_SLOT_ELIGIBLE && !rc) | ||
336 | return 0; | ||
337 | |||
338 | if (action == PCI_REQ_SLOT_DISABLE && !rc) { | ||
339 | sn_slot_mark_disable(bss_hotplug_slot, device_num); | ||
340 | dev_dbg(slot->pci_bus->self, "remove successful\n"); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | if (action == PCI_REQ_SLOT_DISABLE && rc) { | ||
345 | dev_dbg(slot->pci_bus->self,"remove failed rc = %d\n", rc); | ||
346 | return rc; | ||
347 | } | ||
348 | |||
349 | return rc; | ||
350 | } | ||
351 | |||
352 | static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | ||
353 | { | ||
354 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
355 | struct pci_bus *new_bus = NULL; | ||
356 | struct pci_dev *dev; | ||
357 | int func, num_funcs; | ||
358 | int new_ppb = 0; | ||
359 | int rc; | ||
360 | |||
361 | /* Serialize the Linux PCI infrastructure */ | ||
362 | down(&sn_hotplug_sem); | ||
363 | |||
364 | /* | ||
365 | * Power-on and initialize the slot in the SN | ||
366 | * PCI infrastructure. | ||
367 | */ | ||
368 | rc = sn_slot_enable(bss_hotplug_slot, slot->device_num); | ||
369 | if (rc) { | ||
370 | up(&sn_hotplug_sem); | ||
371 | return rc; | ||
372 | } | ||
373 | |||
374 | num_funcs = pci_scan_slot(slot->pci_bus, PCI_DEVFN(slot->device_num+1, | ||
375 | PCI_FUNC(0))); | ||
376 | if (!num_funcs) { | ||
377 | dev_dbg(slot->pci_bus->self, "no device in slot\n"); | ||
378 | up(&sn_hotplug_sem); | ||
379 | return -ENODEV; | ||
380 | } | ||
381 | |||
382 | sn_pci_controller_fixup(pci_domain_nr(slot->pci_bus), | ||
383 | slot->pci_bus->number, | ||
384 | slot->pci_bus); | ||
385 | /* | ||
386 | * Map SN resources for all functions on the card | ||
387 | * to the Linux PCI interface and tell the drivers | ||
388 | * about them. | ||
389 | */ | ||
390 | for (func = 0; func < num_funcs; func++) { | ||
391 | dev = pci_get_slot(slot->pci_bus, | ||
392 | PCI_DEVFN(slot->device_num + 1, | ||
393 | PCI_FUNC(func))); | ||
394 | |||
395 | |||
396 | if (dev) { | ||
397 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
398 | unsigned char sec_bus; | ||
399 | pci_read_config_byte(dev, PCI_SECONDARY_BUS, | ||
400 | &sec_bus); | ||
401 | new_bus = pci_add_new_bus(dev->bus, dev, | ||
402 | sec_bus); | ||
403 | pci_scan_child_bus(new_bus); | ||
404 | sn_pci_controller_fixup(pci_domain_nr(new_bus), | ||
405 | new_bus->number, | ||
406 | new_bus); | ||
407 | new_ppb = 1; | ||
408 | } | ||
409 | sn_bus_alloc_data(dev); | ||
410 | pci_dev_put(dev); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | /* Call the driver for the new device */ | ||
415 | pci_bus_add_devices(slot->pci_bus); | ||
416 | /* Call the drivers for the new devices subordinate to PPB */ | ||
417 | if (new_ppb) | ||
418 | pci_bus_add_devices(new_bus); | ||
419 | |||
420 | up(&sn_hotplug_sem); | ||
421 | |||
422 | if (rc == 0) | ||
423 | dev_dbg(slot->pci_bus->self, | ||
424 | "insert operation successful\n"); | ||
425 | else | ||
426 | dev_dbg(slot->pci_bus->self, | ||
427 | "insert operation failed rc = %d\n", rc); | ||
428 | |||
429 | return rc; | ||
430 | } | ||
431 | |||
432 | static int disable_slot(struct hotplug_slot *bss_hotplug_slot) | ||
433 | { | ||
434 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
435 | struct pci_dev *dev; | ||
436 | int func; | ||
437 | int rc; | ||
438 | |||
439 | /* Acquire update access to the bus */ | ||
440 | down(&sn_hotplug_sem); | ||
441 | |||
442 | /* is it okay to bring this slot down? */ | ||
443 | rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, | ||
444 | PCI_REQ_SLOT_ELIGIBLE); | ||
445 | if (rc) | ||
446 | goto leaving; | ||
447 | |||
448 | /* Free the SN resources assigned to the Linux device.*/ | ||
449 | for (func = 0; func < 8; func++) { | ||
450 | dev = pci_get_slot(slot->pci_bus, | ||
451 | PCI_DEVFN(slot->device_num+1, | ||
452 | PCI_FUNC(func))); | ||
453 | if (dev) { | ||
454 | /* | ||
455 | * Some drivers may use dma accesses during the | ||
456 | * driver remove function. We release the sysdata | ||
457 | * areas after the driver remove functions have | ||
458 | * been called. | ||
459 | */ | ||
460 | sn_bus_store_sysdata(dev); | ||
461 | sn_bus_free_data(dev); | ||
462 | pci_remove_bus_device(dev); | ||
463 | pci_dev_put(dev); | ||
464 | } | ||
465 | } | ||
466 | |||
467 | /* free the collected sysdata pointers */ | ||
468 | sn_bus_free_sysdata(); | ||
469 | |||
470 | /* Deactivate slot */ | ||
471 | rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, | ||
472 | PCI_REQ_SLOT_DISABLE); | ||
473 | leaving: | ||
474 | /* Release the bus lock */ | ||
475 | up(&sn_hotplug_sem); | ||
476 | |||
477 | return rc; | ||
478 | } | ||
479 | |||
480 | static int get_power_status(struct hotplug_slot *bss_hotplug_slot, u8 *value) | ||
481 | { | ||
482 | down(&sn_hotplug_sem); | ||
483 | *value = sn_power_status_get(bss_hotplug_slot); | ||
484 | up(&sn_hotplug_sem); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) | ||
489 | { | ||
490 | kfree(bss_hotplug_slot->info); | ||
491 | kfree(bss_hotplug_slot->name); | ||
492 | kfree(bss_hotplug_slot->private); | ||
493 | kfree(bss_hotplug_slot); | ||
494 | } | ||
495 | |||
496 | static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | ||
497 | { | ||
498 | int device; | ||
499 | struct hotplug_slot *bss_hotplug_slot; | ||
500 | int rc = 0; | ||
501 | |||
502 | /* | ||
503 | * Currently only four devices are supported, | ||
504 | * in the future there maybe more -- up to 32. | ||
505 | */ | ||
506 | |||
507 | for (device = 0; device < SN_MAX_HP_SLOTS ; device++) { | ||
508 | if (sn_pci_slot_valid(pci_bus, device) != 1) | ||
509 | continue; | ||
510 | |||
511 | bss_hotplug_slot = kcalloc(1,sizeof(struct hotplug_slot), | ||
512 | GFP_KERNEL); | ||
513 | if (!bss_hotplug_slot) { | ||
514 | rc = -ENOMEM; | ||
515 | goto alloc_err; | ||
516 | } | ||
517 | |||
518 | bss_hotplug_slot->info = | ||
519 | kcalloc(1,sizeof(struct hotplug_slot_info), | ||
520 | GFP_KERNEL); | ||
521 | if (!bss_hotplug_slot->info) { | ||
522 | rc = -ENOMEM; | ||
523 | goto alloc_err; | ||
524 | } | ||
525 | |||
526 | if (sn_hp_slot_private_alloc(bss_hotplug_slot, | ||
527 | pci_bus, device)) { | ||
528 | rc = -ENOMEM; | ||
529 | goto alloc_err; | ||
530 | } | ||
531 | |||
532 | bss_hotplug_slot->ops = &sn_hotplug_slot_ops; | ||
533 | bss_hotplug_slot->release = &sn_release_slot; | ||
534 | |||
535 | rc = pci_hp_register(bss_hotplug_slot); | ||
536 | if (rc) | ||
537 | goto register_err; | ||
538 | } | ||
539 | dev_dbg(pci_bus->self, "Registered bus with hotplug\n"); | ||
540 | return rc; | ||
541 | |||
542 | register_err: | ||
543 | dev_dbg(pci_bus->self, "bus failed to register with err = %d\n", | ||
544 | rc); | ||
545 | |||
546 | alloc_err: | ||
547 | if (rc == -ENOMEM) | ||
548 | dev_dbg(pci_bus->self, "Memory allocation error\n"); | ||
549 | |||
550 | /* destroy THIS element */ | ||
551 | if (bss_hotplug_slot) | ||
552 | sn_release_slot(bss_hotplug_slot); | ||
553 | |||
554 | /* destroy anything else on the list */ | ||
555 | while ((bss_hotplug_slot = sn_hp_destroy())) | ||
556 | pci_hp_deregister(bss_hotplug_slot); | ||
557 | |||
558 | return rc; | ||
559 | } | ||
560 | |||
561 | static int sn_pci_hotplug_init(void) | ||
562 | { | ||
563 | struct pci_bus *pci_bus = NULL; | ||
564 | int rc; | ||
565 | int registered = 0; | ||
566 | |||
567 | INIT_LIST_HEAD(&sn_hp_list); | ||
568 | |||
569 | if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) { | ||
570 | printk(KERN_ERR "%s: PROM version must be greater than 4.05\n", | ||
571 | __FUNCTION__); | ||
572 | return -EPERM; | ||
573 | } | ||
574 | |||
575 | while ((pci_bus = pci_find_next_bus(pci_bus))) { | ||
576 | if (!pci_bus->sysdata) | ||
577 | continue; | ||
578 | |||
579 | rc = sn_pci_bus_valid(pci_bus); | ||
580 | if (rc != 1) { | ||
581 | dev_dbg(pci_bus->self, "not a valid hotplug bus\n"); | ||
582 | continue; | ||
583 | } | ||
584 | dev_dbg(pci_bus->self, "valid hotplug bus\n"); | ||
585 | |||
586 | rc = sn_hotplug_slot_register(pci_bus); | ||
587 | if (!rc) | ||
588 | registered = 1; | ||
589 | else { | ||
590 | registered = 0; | ||
591 | break; | ||
592 | } | ||
593 | } | ||
594 | |||
595 | return registered == 1 ? 0 : -ENODEV; | ||
596 | } | ||
597 | |||
598 | static void sn_pci_hotplug_exit(void) | ||
599 | { | ||
600 | struct hotplug_slot *bss_hotplug_slot; | ||
601 | |||
602 | while ((bss_hotplug_slot = sn_hp_destroy())) { | ||
603 | pci_hp_deregister(bss_hotplug_slot); | ||
604 | } | ||
605 | |||
606 | if (!list_empty(&sn_hp_list)) | ||
607 | printk(KERN_ERR "%s: internal list is not empty\n", __FILE__); | ||
608 | } | ||
609 | |||
610 | module_init(sn_pci_hotplug_init); | ||
611 | module_exit(sn_pci_hotplug_exit); | ||
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index bc01d34e2634..e9e37abe1f76 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -1,9 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * File: pci-acpi.c | 2 | * File: pci-acpi.c |
3 | * Purpose: Provide PCI supports in ACPI | 3 | * Purpose: Provide PCI support in ACPI |
4 | * | 4 | * |
5 | * Copyright (C) 2004 Intel | 5 | * Copyright (C) 2005 David Shaohua Li <shaohua.li@intel.com> |
6 | * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) | 6 | * Copyright (C) 2004 Tom Long Nguyen <tom.l.nguyen@intel.com> |
7 | * Copyright (C) 2004 Intel Corp. | ||
7 | */ | 8 | */ |
8 | 9 | ||
9 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
@@ -16,6 +17,7 @@ | |||
16 | #include <acpi/acpi_bus.h> | 17 | #include <acpi/acpi_bus.h> |
17 | 18 | ||
18 | #include <linux/pci-acpi.h> | 19 | #include <linux/pci-acpi.h> |
20 | #include "pci.h" | ||
19 | 21 | ||
20 | static u32 ctrlset_buf[3] = {0, 0, 0}; | 22 | static u32 ctrlset_buf[3] = {0, 0, 0}; |
21 | static u32 global_ctrlsets = 0; | 23 | static u32 global_ctrlsets = 0; |
@@ -207,3 +209,105 @@ acpi_status pci_osc_control_set(u32 flags) | |||
207 | return status; | 209 | return status; |
208 | } | 210 | } |
209 | EXPORT_SYMBOL(pci_osc_control_set); | 211 | EXPORT_SYMBOL(pci_osc_control_set); |
212 | |||
213 | /* | ||
214 | * _SxD returns the D-state with the highest power | ||
215 | * (lowest D-state number) supported in the S-state "x". | ||
216 | * | ||
217 | * If the devices does not have a _PRW | ||
218 | * (Power Resources for Wake) supporting system wakeup from "x" | ||
219 | * then the OS is free to choose a lower power (higher number | ||
220 | * D-state) than the return value from _SxD. | ||
221 | * | ||
222 | * But if _PRW is enabled at S-state "x", the OS | ||
223 | * must not choose a power lower than _SxD -- | ||
224 | * unless the device has an _SxW method specifying | ||
225 | * the lowest power (highest D-state number) the device | ||
226 | * may enter while still able to wake the system. | ||
227 | * | ||
228 | * ie. depending on global OS policy: | ||
229 | * | ||
230 | * if (_PRW at S-state x) | ||
231 | * choose from highest power _SxD to lowest power _SxW | ||
232 | * else // no _PRW at S-state x | ||
233 | * choose highest power _SxD or any lower power | ||
234 | * | ||
235 | * currently we simply return _SxD, if present. | ||
236 | */ | ||
237 | |||
238 | static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) | ||
239 | { | ||
240 | /* TBD */ | ||
241 | |||
242 | return -ENODEV; | ||
243 | } | ||
244 | |||
245 | static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | ||
246 | { | ||
247 | acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
248 | static int state_conv[] = { | ||
249 | [0] = 0, | ||
250 | [1] = 1, | ||
251 | [2] = 2, | ||
252 | [3] = 3, | ||
253 | [4] = 3 | ||
254 | }; | ||
255 | int acpi_state = state_conv[(int __force) state]; | ||
256 | |||
257 | if (!handle) | ||
258 | return -ENODEV; | ||
259 | return acpi_bus_set_power(handle, acpi_state); | ||
260 | } | ||
261 | |||
262 | |||
263 | /* ACPI bus type */ | ||
264 | static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | ||
265 | { | ||
266 | struct pci_dev * pci_dev; | ||
267 | acpi_integer addr; | ||
268 | |||
269 | pci_dev = to_pci_dev(dev); | ||
270 | /* Please ref to ACPI spec for the syntax of _ADR */ | ||
271 | addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); | ||
272 | *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); | ||
273 | if (!*handle) | ||
274 | return -ENODEV; | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | ||
279 | { | ||
280 | int num; | ||
281 | unsigned int seg, bus; | ||
282 | |||
283 | /* | ||
284 | * The string should be the same as root bridge's name | ||
285 | * Please look at 'pci_scan_bus_parented' | ||
286 | */ | ||
287 | num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus); | ||
288 | if (num != 2) | ||
289 | return -ENODEV; | ||
290 | *handle = acpi_get_pci_rootbridge_handle(seg, bus); | ||
291 | if (!*handle) | ||
292 | return -ENODEV; | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static struct acpi_bus_type pci_acpi_bus = { | ||
297 | .bus = &pci_bus_type, | ||
298 | .find_device = pci_acpi_find_device, | ||
299 | .find_bridge = pci_acpi_find_root_bridge, | ||
300 | }; | ||
301 | |||
302 | static int __init pci_acpi_init(void) | ||
303 | { | ||
304 | int ret; | ||
305 | |||
306 | ret = register_acpi_bus_type(&pci_acpi_bus); | ||
307 | if (ret) | ||
308 | return 0; | ||
309 | platform_pci_choose_state = acpi_pci_choose_state; | ||
310 | platform_pci_set_power_state = acpi_pci_set_power_state; | ||
311 | return 0; | ||
312 | } | ||
313 | arch_initcall(pci_acpi_init); | ||
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e65bf2b395aa..e4115a0d5ba6 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | #include <linux/device.h> | 9 | #include <linux/device.h> |
10 | #include <linux/pci-dynids.h> | ||
11 | #include "pci.h" | 10 | #include "pci.h" |
12 | 11 | ||
13 | /* | 12 | /* |
@@ -18,36 +17,12 @@ | |||
18 | * Dynamic device IDs are disabled for !CONFIG_HOTPLUG | 17 | * Dynamic device IDs are disabled for !CONFIG_HOTPLUG |
19 | */ | 18 | */ |
20 | 19 | ||
21 | #ifdef CONFIG_HOTPLUG | 20 | struct pci_dynid { |
22 | /** | 21 | struct list_head node; |
23 | * pci_device_probe_dynamic() | 22 | struct pci_device_id id; |
24 | * | 23 | }; |
25 | * Walk the dynamic ID list looking for a match. | ||
26 | * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error. | ||
27 | */ | ||
28 | static int | ||
29 | pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) | ||
30 | { | ||
31 | int error = -ENODEV; | ||
32 | struct list_head *pos; | ||
33 | struct dynid *dynid; | ||
34 | 24 | ||
35 | spin_lock(&drv->dynids.lock); | 25 | #ifdef CONFIG_HOTPLUG |
36 | list_for_each(pos, &drv->dynids.list) { | ||
37 | dynid = list_entry(pos, struct dynid, node); | ||
38 | if (pci_match_one_device(&dynid->id, pci_dev)) { | ||
39 | spin_unlock(&drv->dynids.lock); | ||
40 | error = drv->probe(pci_dev, &dynid->id); | ||
41 | if (error >= 0) { | ||
42 | pci_dev->driver = drv; | ||
43 | return 0; | ||
44 | } | ||
45 | return error; | ||
46 | } | ||
47 | } | ||
48 | spin_unlock(&drv->dynids.lock); | ||
49 | return error; | ||
50 | } | ||
51 | 26 | ||
52 | /** | 27 | /** |
53 | * store_new_id | 28 | * store_new_id |
@@ -58,8 +33,7 @@ pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) | |||
58 | static inline ssize_t | 33 | static inline ssize_t |
59 | store_new_id(struct device_driver *driver, const char *buf, size_t count) | 34 | store_new_id(struct device_driver *driver, const char *buf, size_t count) |
60 | { | 35 | { |
61 | struct dynid *dynid; | 36 | struct pci_dynid *dynid; |
62 | struct bus_type * bus; | ||
63 | struct pci_driver *pdrv = to_pci_driver(driver); | 37 | struct pci_driver *pdrv = to_pci_driver(driver); |
64 | __u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID, | 38 | __u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID, |
65 | subdevice=PCI_ANY_ID, class=0, class_mask=0; | 39 | subdevice=PCI_ANY_ID, class=0, class_mask=0; |
@@ -91,37 +65,22 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) | |||
91 | list_add_tail(&pdrv->dynids.list, &dynid->node); | 65 | list_add_tail(&pdrv->dynids.list, &dynid->node); |
92 | spin_unlock(&pdrv->dynids.lock); | 66 | spin_unlock(&pdrv->dynids.lock); |
93 | 67 | ||
94 | bus = get_bus(pdrv->driver.bus); | 68 | if (get_driver(&pdrv->driver)) { |
95 | if (bus) { | 69 | driver_attach(&pdrv->driver); |
96 | if (get_driver(&pdrv->driver)) { | 70 | put_driver(&pdrv->driver); |
97 | down_write(&bus->subsys.rwsem); | ||
98 | driver_attach(&pdrv->driver); | ||
99 | up_write(&bus->subsys.rwsem); | ||
100 | put_driver(&pdrv->driver); | ||
101 | } | ||
102 | put_bus(bus); | ||
103 | } | 71 | } |
104 | 72 | ||
105 | return count; | 73 | return count; |
106 | } | 74 | } |
107 | |||
108 | static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); | 75 | static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); |
109 | static inline void | ||
110 | pci_init_dynids(struct pci_dynids *dynids) | ||
111 | { | ||
112 | spin_lock_init(&dynids->lock); | ||
113 | INIT_LIST_HEAD(&dynids->list); | ||
114 | } | ||
115 | 76 | ||
116 | static void | 77 | static void |
117 | pci_free_dynids(struct pci_driver *drv) | 78 | pci_free_dynids(struct pci_driver *drv) |
118 | { | 79 | { |
119 | struct list_head *pos, *n; | 80 | struct pci_dynid *dynid, *n; |
120 | struct dynid *dynid; | ||
121 | 81 | ||
122 | spin_lock(&drv->dynids.lock); | 82 | spin_lock(&drv->dynids.lock); |
123 | list_for_each_safe(pos, n, &drv->dynids.list) { | 83 | list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { |
124 | dynid = list_entry(pos, struct dynid, node); | ||
125 | list_del(&dynid->node); | 84 | list_del(&dynid->node); |
126 | kfree(dynid); | 85 | kfree(dynid); |
127 | } | 86 | } |
@@ -138,83 +97,70 @@ pci_create_newid_file(struct pci_driver *drv) | |||
138 | return error; | 97 | return error; |
139 | } | 98 | } |
140 | 99 | ||
141 | static int | ||
142 | pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv) | ||
143 | { | ||
144 | struct list_head *pos; | ||
145 | struct dynid *dynid; | ||
146 | |||
147 | spin_lock(&pci_drv->dynids.lock); | ||
148 | list_for_each(pos, &pci_drv->dynids.list) { | ||
149 | dynid = list_entry(pos, struct dynid, node); | ||
150 | if (pci_match_one_device(&dynid->id, pci_dev)) { | ||
151 | spin_unlock(&pci_drv->dynids.lock); | ||
152 | return 1; | ||
153 | } | ||
154 | } | ||
155 | spin_unlock(&pci_drv->dynids.lock); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | #else /* !CONFIG_HOTPLUG */ | 100 | #else /* !CONFIG_HOTPLUG */ |
160 | static inline int pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) | ||
161 | { | ||
162 | return -ENODEV; | ||
163 | } | ||
164 | static inline void pci_init_dynids(struct pci_dynids *dynids) {} | ||
165 | static inline void pci_free_dynids(struct pci_driver *drv) {} | 101 | static inline void pci_free_dynids(struct pci_driver *drv) {} |
166 | static inline int pci_create_newid_file(struct pci_driver *drv) | 102 | static inline int pci_create_newid_file(struct pci_driver *drv) |
167 | { | 103 | { |
168 | return 0; | 104 | return 0; |
169 | } | 105 | } |
170 | static inline int pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv) | ||
171 | { | ||
172 | return 0; | ||
173 | } | ||
174 | #endif | 106 | #endif |
175 | 107 | ||
176 | /** | 108 | /** |
177 | * pci_match_device - Tell if a PCI device structure has a matching | 109 | * pci_match_id - See if a pci device matches a given pci_id table |
178 | * PCI device id structure | ||
179 | * @ids: array of PCI device id structures to search in | 110 | * @ids: array of PCI device id structures to search in |
180 | * @dev: the PCI device structure to match against | 111 | * @dev: the PCI device structure to match against. |
181 | * | 112 | * |
182 | * Used by a driver to check whether a PCI device present in the | 113 | * Used by a driver to check whether a PCI device present in the |
183 | * system is in its list of supported devices.Returns the matching | 114 | * system is in its list of supported devices. Returns the matching |
184 | * pci_device_id structure or %NULL if there is no match. | 115 | * pci_device_id structure or %NULL if there is no match. |
116 | * | ||
117 | * Depreciated, don't use this as it will not catch any dynamic ids | ||
118 | * that a driver might want to check for. | ||
185 | */ | 119 | */ |
186 | const struct pci_device_id * | 120 | const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, |
187 | pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) | 121 | struct pci_dev *dev) |
188 | { | 122 | { |
189 | while (ids->vendor || ids->subvendor || ids->class_mask) { | 123 | if (ids) { |
190 | if (pci_match_one_device(ids, dev)) | 124 | while (ids->vendor || ids->subvendor || ids->class_mask) { |
191 | return ids; | 125 | if (pci_match_one_device(ids, dev)) |
192 | ids++; | 126 | return ids; |
127 | ids++; | ||
128 | } | ||
193 | } | 129 | } |
194 | return NULL; | 130 | return NULL; |
195 | } | 131 | } |
196 | 132 | ||
197 | /** | 133 | /** |
198 | * pci_device_probe_static() | 134 | * pci_match_device - Tell if a PCI device structure has a matching |
199 | * | 135 | * PCI device id structure |
200 | * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error. | 136 | * @ids: array of PCI device id structures to search in |
137 | * @dev: the PCI device structure to match against | ||
138 | * @drv: the PCI driver to match against | ||
139 | * | ||
140 | * Used by a driver to check whether a PCI device present in the | ||
141 | * system is in its list of supported devices. Returns the matching | ||
142 | * pci_device_id structure or %NULL if there is no match. | ||
201 | */ | 143 | */ |
202 | static int | 144 | const struct pci_device_id *pci_match_device(struct pci_driver *drv, |
203 | pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev) | 145 | struct pci_dev *dev) |
204 | { | 146 | { |
205 | int error = -ENODEV; | ||
206 | const struct pci_device_id *id; | 147 | const struct pci_device_id *id; |
148 | struct pci_dynid *dynid; | ||
207 | 149 | ||
208 | if (!drv->id_table) | 150 | id = pci_match_id(drv->id_table, dev); |
209 | return error; | ||
210 | id = pci_match_device(drv->id_table, pci_dev); | ||
211 | if (id) | 151 | if (id) |
212 | error = drv->probe(pci_dev, id); | 152 | return id; |
213 | if (error >= 0) { | 153 | |
214 | pci_dev->driver = drv; | 154 | /* static ids didn't match, lets look at the dynamic ones */ |
215 | error = 0; | 155 | spin_lock(&drv->dynids.lock); |
156 | list_for_each_entry(dynid, &drv->dynids.list, node) { | ||
157 | if (pci_match_one_device(&dynid->id, dev)) { | ||
158 | spin_unlock(&drv->dynids.lock); | ||
159 | return &dynid->id; | ||
160 | } | ||
216 | } | 161 | } |
217 | return error; | 162 | spin_unlock(&drv->dynids.lock); |
163 | return NULL; | ||
218 | } | 164 | } |
219 | 165 | ||
220 | /** | 166 | /** |
@@ -225,13 +171,20 @@ pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev) | |||
225 | */ | 171 | */ |
226 | static int | 172 | static int |
227 | __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) | 173 | __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) |
228 | { | 174 | { |
175 | const struct pci_device_id *id; | ||
229 | int error = 0; | 176 | int error = 0; |
230 | 177 | ||
231 | if (!pci_dev->driver && drv->probe) { | 178 | if (!pci_dev->driver && drv->probe) { |
232 | error = pci_device_probe_static(drv, pci_dev); | 179 | error = -ENODEV; |
233 | if (error == -ENODEV) | 180 | |
234 | error = pci_device_probe_dynamic(drv, pci_dev); | 181 | id = pci_match_device(drv, pci_dev); |
182 | if (id) | ||
183 | error = drv->probe(pci_dev, id); | ||
184 | if (error >= 0) { | ||
185 | pci_dev->driver = drv; | ||
186 | error = 0; | ||
187 | } | ||
235 | } | 188 | } |
236 | return error; | 189 | return error; |
237 | } | 190 | } |
@@ -371,12 +324,6 @@ static struct kobj_type pci_driver_kobj_type = { | |||
371 | .sysfs_ops = &pci_driver_sysfs_ops, | 324 | .sysfs_ops = &pci_driver_sysfs_ops, |
372 | }; | 325 | }; |
373 | 326 | ||
374 | static int | ||
375 | pci_populate_driver_dir(struct pci_driver *drv) | ||
376 | { | ||
377 | return pci_create_newid_file(drv); | ||
378 | } | ||
379 | |||
380 | /** | 327 | /** |
381 | * pci_register_driver - register a new pci driver | 328 | * pci_register_driver - register a new pci driver |
382 | * @drv: the driver structure to register | 329 | * @drv: the driver structure to register |
@@ -401,13 +348,15 @@ int pci_register_driver(struct pci_driver *drv) | |||
401 | drv->driver.shutdown = pci_device_shutdown; | 348 | drv->driver.shutdown = pci_device_shutdown; |
402 | drv->driver.owner = drv->owner; | 349 | drv->driver.owner = drv->owner; |
403 | drv->driver.kobj.ktype = &pci_driver_kobj_type; | 350 | drv->driver.kobj.ktype = &pci_driver_kobj_type; |
404 | pci_init_dynids(&drv->dynids); | 351 | |
352 | spin_lock_init(&drv->dynids.lock); | ||
353 | INIT_LIST_HEAD(&drv->dynids.list); | ||
405 | 354 | ||
406 | /* register with core */ | 355 | /* register with core */ |
407 | error = driver_register(&drv->driver); | 356 | error = driver_register(&drv->driver); |
408 | 357 | ||
409 | if (!error) | 358 | if (!error) |
410 | pci_populate_driver_dir(drv); | 359 | error = pci_create_newid_file(drv); |
411 | 360 | ||
412 | return error; | 361 | return error; |
413 | } | 362 | } |
@@ -463,21 +412,17 @@ pci_dev_driver(const struct pci_dev *dev) | |||
463 | * system is in its list of supported devices.Returns the matching | 412 | * system is in its list of supported devices.Returns the matching |
464 | * pci_device_id structure or %NULL if there is no match. | 413 | * pci_device_id structure or %NULL if there is no match. |
465 | */ | 414 | */ |
466 | static int pci_bus_match(struct device * dev, struct device_driver * drv) | 415 | static int pci_bus_match(struct device *dev, struct device_driver *drv) |
467 | { | 416 | { |
468 | const struct pci_dev * pci_dev = to_pci_dev(dev); | 417 | struct pci_dev *pci_dev = to_pci_dev(dev); |
469 | struct pci_driver * pci_drv = to_pci_driver(drv); | 418 | struct pci_driver *pci_drv = to_pci_driver(drv); |
470 | const struct pci_device_id * ids = pci_drv->id_table; | ||
471 | const struct pci_device_id *found_id; | 419 | const struct pci_device_id *found_id; |
472 | 420 | ||
473 | if (!ids) | 421 | found_id = pci_match_device(pci_drv, pci_dev); |
474 | return 0; | ||
475 | |||
476 | found_id = pci_match_device(ids, pci_dev); | ||
477 | if (found_id) | 422 | if (found_id) |
478 | return 1; | 423 | return 1; |
479 | 424 | ||
480 | return pci_bus_match_dynids(pci_dev, pci_drv); | 425 | return 0; |
481 | } | 426 | } |
482 | 427 | ||
483 | /** | 428 | /** |
@@ -536,6 +481,7 @@ static int __init pci_driver_init(void) | |||
536 | 481 | ||
537 | postcore_initcall(pci_driver_init); | 482 | postcore_initcall(pci_driver_init); |
538 | 483 | ||
484 | EXPORT_SYMBOL(pci_match_id); | ||
539 | EXPORT_SYMBOL(pci_match_device); | 485 | EXPORT_SYMBOL(pci_match_device); |
540 | EXPORT_SYMBOL(pci_register_driver); | 486 | EXPORT_SYMBOL(pci_register_driver); |
541 | EXPORT_SYMBOL(pci_unregister_driver); | 487 | EXPORT_SYMBOL(pci_unregister_driver); |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f04b9ffe4153..1b34fc56067e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -235,7 +235,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) | |||
235 | * -EIO if device does not support PCI PM. | 235 | * -EIO if device does not support PCI PM. |
236 | * 0 if we can successfully change the power state. | 236 | * 0 if we can successfully change the power state. |
237 | */ | 237 | */ |
238 | 238 | int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); | |
239 | int | 239 | int |
240 | pci_set_power_state(struct pci_dev *dev, pci_power_t state) | 240 | pci_set_power_state(struct pci_dev *dev, pci_power_t state) |
241 | { | 241 | { |
@@ -299,11 +299,20 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
299 | msleep(10); | 299 | msleep(10); |
300 | else if (state == PCI_D2 || dev->current_state == PCI_D2) | 300 | else if (state == PCI_D2 || dev->current_state == PCI_D2) |
301 | udelay(200); | 301 | udelay(200); |
302 | dev->current_state = state; | ||
303 | 302 | ||
303 | /* | ||
304 | * Give firmware a chance to be called, such as ACPI _PRx, _PSx | ||
305 | * Firmware method after natice method ? | ||
306 | */ | ||
307 | if (platform_pci_set_power_state) | ||
308 | platform_pci_set_power_state(dev, state); | ||
309 | |||
310 | dev->current_state = state; | ||
304 | return 0; | 311 | return 0; |
305 | } | 312 | } |
306 | 313 | ||
314 | int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); | ||
315 | |||
307 | /** | 316 | /** |
308 | * pci_choose_state - Choose the power state of a PCI device | 317 | * pci_choose_state - Choose the power state of a PCI device |
309 | * @dev: PCI device to be suspended | 318 | * @dev: PCI device to be suspended |
@@ -316,10 +325,17 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
316 | 325 | ||
317 | pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) | 326 | pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) |
318 | { | 327 | { |
328 | int ret; | ||
329 | |||
319 | if (!pci_find_capability(dev, PCI_CAP_ID_PM)) | 330 | if (!pci_find_capability(dev, PCI_CAP_ID_PM)) |
320 | return PCI_D0; | 331 | return PCI_D0; |
321 | 332 | ||
322 | switch (state) { | 333 | if (platform_pci_choose_state) { |
334 | ret = platform_pci_choose_state(dev, state); | ||
335 | if (ret >= 0) | ||
336 | state = ret; | ||
337 | } | ||
338 | switch (state) { | ||
323 | case 0: return PCI_D0; | 339 | case 0: return PCI_D0; |
324 | case 3: return PCI_D3hot; | 340 | case 3: return PCI_D3hot; |
325 | default: | 341 | default: |
@@ -334,10 +350,6 @@ EXPORT_SYMBOL(pci_choose_state); | |||
334 | /** | 350 | /** |
335 | * pci_save_state - save the PCI configuration space of a device before suspending | 351 | * pci_save_state - save the PCI configuration space of a device before suspending |
336 | * @dev: - PCI device that we're dealing with | 352 | * @dev: - PCI device that we're dealing with |
337 | * @buffer: - buffer to hold config space context | ||
338 | * | ||
339 | * @buffer must be large enough to hold the entire PCI 2.2 config space | ||
340 | * (>= 64 bytes). | ||
341 | */ | 353 | */ |
342 | int | 354 | int |
343 | pci_save_state(struct pci_dev *dev) | 355 | pci_save_state(struct pci_dev *dev) |
@@ -352,8 +364,6 @@ pci_save_state(struct pci_dev *dev) | |||
352 | /** | 364 | /** |
353 | * pci_restore_state - Restore the saved state of a PCI device | 365 | * pci_restore_state - Restore the saved state of a PCI device |
354 | * @dev: - PCI device that we're dealing with | 366 | * @dev: - PCI device that we're dealing with |
355 | * @buffer: - saved PCI config space | ||
356 | * | ||
357 | */ | 367 | */ |
358 | int | 368 | int |
359 | pci_restore_state(struct pci_dev *dev) | 369 | pci_restore_state(struct pci_dev *dev) |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 744da0d4ae5f..d94d7af4f7a0 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -11,6 +11,10 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, | |||
11 | void (*alignf)(void *, struct resource *, | 11 | void (*alignf)(void *, struct resource *, |
12 | unsigned long, unsigned long), | 12 | unsigned long, unsigned long), |
13 | void *alignf_data); | 13 | void *alignf_data); |
14 | /* Firmware callbacks */ | ||
15 | extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); | ||
16 | extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); | ||
17 | |||
14 | /* PCI /proc functions */ | 18 | /* PCI /proc functions */ |
15 | #ifdef CONFIG_PROC_FS | 19 | #ifdef CONFIG_PROC_FS |
16 | extern int pci_proc_attach_device(struct pci_dev *dev); | 20 | extern int pci_proc_attach_device(struct pci_dev *dev); |
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 537b372dc340..a63bd8f72601 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h | |||
@@ -27,6 +27,11 @@ | |||
27 | 27 | ||
28 | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) | 28 | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) |
29 | 29 | ||
30 | struct pcie_port_device_ext { | ||
31 | int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */ | ||
32 | unsigned int saved_msi_config_space[5]; | ||
33 | }; | ||
34 | |||
30 | extern struct bus_type pcie_port_bus_type; | 35 | extern struct bus_type pcie_port_bus_type; |
31 | extern int pcie_port_device_probe(struct pci_dev *dev); | 36 | extern int pcie_port_device_probe(struct pci_dev *dev); |
32 | extern int pcie_port_device_register(struct pci_dev *dev); | 37 | extern int pcie_port_device_register(struct pci_dev *dev); |
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index f5c5f10a3d2f..393e0cee91a9 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -275,10 +275,17 @@ int pcie_port_device_probe(struct pci_dev *dev) | |||
275 | 275 | ||
276 | int pcie_port_device_register(struct pci_dev *dev) | 276 | int pcie_port_device_register(struct pci_dev *dev) |
277 | { | 277 | { |
278 | struct pcie_port_device_ext *p_ext; | ||
278 | int status, type, capabilities, irq_mode, i; | 279 | int status, type, capabilities, irq_mode, i; |
279 | int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; | 280 | int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; |
280 | u16 reg16; | 281 | u16 reg16; |
281 | 282 | ||
283 | /* Allocate port device extension */ | ||
284 | if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL))) | ||
285 | return -ENOMEM; | ||
286 | |||
287 | pci_set_drvdata(dev, p_ext); | ||
288 | |||
282 | /* Get port type */ | 289 | /* Get port type */ |
283 | pci_read_config_word(dev, | 290 | pci_read_config_word(dev, |
284 | pci_find_capability(dev, PCI_CAP_ID_EXP) + | 291 | pci_find_capability(dev, PCI_CAP_ID_EXP) + |
@@ -288,6 +295,7 @@ int pcie_port_device_register(struct pci_dev *dev) | |||
288 | /* Now get port services */ | 295 | /* Now get port services */ |
289 | capabilities = get_port_device_capability(dev); | 296 | capabilities = get_port_device_capability(dev); |
290 | irq_mode = assign_interrupt_mode(dev, vectors, capabilities); | 297 | irq_mode = assign_interrupt_mode(dev, vectors, capabilities); |
298 | p_ext->interrupt_mode = irq_mode; | ||
291 | 299 | ||
292 | /* Allocate child services if any */ | 300 | /* Allocate child services if any */ |
293 | for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { | 301 | for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { |
@@ -317,7 +325,7 @@ int pcie_port_device_register(struct pci_dev *dev) | |||
317 | static int suspend_iter(struct device *dev, void *data) | 325 | static int suspend_iter(struct device *dev, void *data) |
318 | { | 326 | { |
319 | struct pcie_port_service_driver *service_driver; | 327 | struct pcie_port_service_driver *service_driver; |
320 | u32 state = (u32)data; | 328 | pm_message_t state = * (pm_message_t *) data; |
321 | 329 | ||
322 | if ((dev->bus == &pcie_port_bus_type) && | 330 | if ((dev->bus == &pcie_port_bus_type) && |
323 | (dev->driver)) { | 331 | (dev->driver)) { |
@@ -328,9 +336,9 @@ static int suspend_iter(struct device *dev, void *data) | |||
328 | return 0; | 336 | return 0; |
329 | } | 337 | } |
330 | 338 | ||
331 | int pcie_port_device_suspend(struct pci_dev *dev, u32 state) | 339 | int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) |
332 | { | 340 | { |
333 | device_for_each_child(&dev->dev, (void *)state, suspend_iter); | 341 | device_for_each_child(&dev->dev, &state, suspend_iter); |
334 | return 0; | 342 | return 0; |
335 | } | 343 | } |
336 | 344 | ||
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index e9095ee508e3..30bac7ed7c16 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -29,6 +29,78 @@ MODULE_LICENSE("GPL"); | |||
29 | /* global data */ | 29 | /* global data */ |
30 | static const char device_name[] = "pcieport-driver"; | 30 | static const char device_name[] = "pcieport-driver"; |
31 | 31 | ||
32 | static void pci_save_msi_state(struct pci_dev *dev) | ||
33 | { | ||
34 | struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); | ||
35 | int i = 0, pos; | ||
36 | u16 control; | ||
37 | |||
38 | if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) | ||
39 | return; | ||
40 | |||
41 | pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]); | ||
42 | control = p_ext->saved_msi_config_space[0] >> 16; | ||
43 | pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, | ||
44 | &p_ext->saved_msi_config_space[i++]); | ||
45 | if (control & PCI_MSI_FLAGS_64BIT) { | ||
46 | pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, | ||
47 | &p_ext->saved_msi_config_space[i++]); | ||
48 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, | ||
49 | &p_ext->saved_msi_config_space[i++]); | ||
50 | } else | ||
51 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, | ||
52 | &p_ext->saved_msi_config_space[i++]); | ||
53 | if (control & PCI_MSI_FLAGS_MASKBIT) | ||
54 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, | ||
55 | &p_ext->saved_msi_config_space[i++]); | ||
56 | } | ||
57 | |||
58 | static void pci_restore_msi_state(struct pci_dev *dev) | ||
59 | { | ||
60 | struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); | ||
61 | int i = 0, pos; | ||
62 | u16 control; | ||
63 | |||
64 | if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) | ||
65 | return; | ||
66 | |||
67 | control = p_ext->saved_msi_config_space[i++] >> 16; | ||
68 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | ||
69 | pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, | ||
70 | p_ext->saved_msi_config_space[i++]); | ||
71 | if (control & PCI_MSI_FLAGS_64BIT) { | ||
72 | pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, | ||
73 | p_ext->saved_msi_config_space[i++]); | ||
74 | pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, | ||
75 | p_ext->saved_msi_config_space[i++]); | ||
76 | } else | ||
77 | pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, | ||
78 | p_ext->saved_msi_config_space[i++]); | ||
79 | if (control & PCI_MSI_FLAGS_MASKBIT) | ||
80 | pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, | ||
81 | p_ext->saved_msi_config_space[i++]); | ||
82 | } | ||
83 | |||
84 | static void pcie_portdrv_save_config(struct pci_dev *dev) | ||
85 | { | ||
86 | struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); | ||
87 | |||
88 | pci_save_state(dev); | ||
89 | if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) | ||
90 | pci_save_msi_state(dev); | ||
91 | } | ||
92 | |||
93 | static void pcie_portdrv_restore_config(struct pci_dev *dev) | ||
94 | { | ||
95 | struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); | ||
96 | |||
97 | pci_restore_state(dev); | ||
98 | if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) | ||
99 | pci_restore_msi_state(dev); | ||
100 | pci_enable_device(dev); | ||
101 | pci_set_master(dev); | ||
102 | } | ||
103 | |||
32 | /* | 104 | /* |
33 | * pcie_portdrv_probe - Probe PCI-Express port devices | 105 | * pcie_portdrv_probe - Probe PCI-Express port devices |
34 | * @dev: PCI-Express port device being probed | 106 | * @dev: PCI-Express port device being probed |
@@ -64,16 +136,21 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, | |||
64 | static void pcie_portdrv_remove (struct pci_dev *dev) | 136 | static void pcie_portdrv_remove (struct pci_dev *dev) |
65 | { | 137 | { |
66 | pcie_port_device_remove(dev); | 138 | pcie_port_device_remove(dev); |
139 | kfree(pci_get_drvdata(dev)); | ||
67 | } | 140 | } |
68 | 141 | ||
69 | #ifdef CONFIG_PM | 142 | #ifdef CONFIG_PM |
70 | static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) | 143 | static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) |
71 | { | 144 | { |
72 | return pcie_port_device_suspend(dev, state); | 145 | int ret = pcie_port_device_suspend(dev, state); |
146 | |||
147 | pcie_portdrv_save_config(dev); | ||
148 | return ret; | ||
73 | } | 149 | } |
74 | 150 | ||
75 | static int pcie_portdrv_resume (struct pci_dev *dev) | 151 | static int pcie_portdrv_resume (struct pci_dev *dev) |
76 | { | 152 | { |
153 | pcie_portdrv_restore_config(dev); | ||
77 | return pcie_port_device_resume(dev); | 154 | return pcie_port_device_resume(dev); |
78 | } | 155 | } |
79 | #endif | 156 | #endif |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6a0a82f0508b..df3bdae2040f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -239,9 +239,8 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) | |||
239 | 239 | ||
240 | if (dev->transparent) { | 240 | if (dev->transparent) { |
241 | printk(KERN_INFO "PCI: Transparent bridge - %s\n", pci_name(dev)); | 241 | printk(KERN_INFO "PCI: Transparent bridge - %s\n", pci_name(dev)); |
242 | for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) | 242 | for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) |
243 | child->resource[i] = child->parent->resource[i]; | 243 | child->resource[i] = child->parent->resource[i - 3]; |
244 | return; | ||
245 | } | 244 | } |
246 | 245 | ||
247 | for(i=0; i<3; i++) | 246 | for(i=0; i<3; i++) |
@@ -398,6 +397,16 @@ static void pci_enable_crs(struct pci_dev *dev) | |||
398 | pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl); | 397 | pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl); |
399 | } | 398 | } |
400 | 399 | ||
400 | static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) | ||
401 | { | ||
402 | struct pci_bus *parent = child->parent; | ||
403 | while (parent->parent && parent->subordinate < max) { | ||
404 | parent->subordinate = max; | ||
405 | pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max); | ||
406 | parent = parent->parent; | ||
407 | } | ||
408 | } | ||
409 | |||
401 | unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); | 410 | unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); |
402 | 411 | ||
403 | /* | 412 | /* |
@@ -499,7 +508,13 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max | |||
499 | 508 | ||
500 | if (!is_cardbus) { | 509 | if (!is_cardbus) { |
501 | child->bridge_ctl = PCI_BRIDGE_CTL_NO_ISA; | 510 | child->bridge_ctl = PCI_BRIDGE_CTL_NO_ISA; |
502 | 511 | /* | |
512 | * Adjust subordinate busnr in parent buses. | ||
513 | * We do this before scanning for children because | ||
514 | * some devices may not be detected if the bios | ||
515 | * was lazy. | ||
516 | */ | ||
517 | pci_fixup_parent_subordinate_busnr(child, max); | ||
503 | /* Now we can scan all subordinate buses... */ | 518 | /* Now we can scan all subordinate buses... */ |
504 | max = pci_scan_child_bus(child); | 519 | max = pci_scan_child_bus(child); |
505 | } else { | 520 | } else { |
@@ -513,6 +528,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max | |||
513 | max+i+1)) | 528 | max+i+1)) |
514 | break; | 529 | break; |
515 | max += i; | 530 | max += i; |
531 | pci_fixup_parent_subordinate_busnr(child, max); | ||
516 | } | 532 | } |
517 | /* | 533 | /* |
518 | * Set the subordinate bus number to its real value. | 534 | * Set the subordinate bus number to its real value. |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 968033fd29f0..1521fd5d95cc 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -767,6 +767,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) | |||
767 | if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { | 767 | if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { |
768 | if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB) | 768 | if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB) |
769 | switch(dev->subsystem_device) { | 769 | switch(dev->subsystem_device) { |
770 | case 0x8025: /* P4B-LX */ | ||
770 | case 0x8070: /* P4B */ | 771 | case 0x8070: /* P4B */ |
771 | case 0x8088: /* P4B533 */ | 772 | case 0x8088: /* P4B533 */ |
772 | case 0x1626: /* L3C notebook */ | 773 | case 0x1626: /* L3C notebook */ |
diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a90a533eba0f..05fa91a31c62 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c | |||
@@ -379,6 +379,7 @@ exit: | |||
379 | EXPORT_SYMBOL(pci_dev_present); | 379 | EXPORT_SYMBOL(pci_dev_present); |
380 | 380 | ||
381 | EXPORT_SYMBOL(pci_find_bus); | 381 | EXPORT_SYMBOL(pci_find_bus); |
382 | EXPORT_SYMBOL(pci_find_next_bus); | ||
382 | EXPORT_SYMBOL(pci_find_device); | 383 | EXPORT_SYMBOL(pci_find_device); |
383 | EXPORT_SYMBOL(pci_find_device_reverse); | 384 | EXPORT_SYMBOL(pci_find_device_reverse); |
384 | EXPORT_SYMBOL(pci_find_slot); | 385 | EXPORT_SYMBOL(pci_find_slot); |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 6b628de948af..9fe48f712be9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -74,6 +74,7 @@ pbus_assign_resources_sorted(struct pci_bus *bus) | |||
74 | idx = res - &list->dev->resource[0]; | 74 | idx = res - &list->dev->resource[0]; |
75 | if (pci_assign_resource(list->dev, idx)) { | 75 | if (pci_assign_resource(list->dev, idx)) { |
76 | res->start = 0; | 76 | res->start = 0; |
77 | res->end = 0; | ||
77 | res->flags = 0; | 78 | res->flags = 0; |
78 | } | 79 | } |
79 | tmp = list; | 80 | tmp = list; |
@@ -273,6 +274,8 @@ find_free_bus_resource(struct pci_bus *bus, unsigned long type) | |||
273 | 274 | ||
274 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | 275 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { |
275 | r = bus->resource[i]; | 276 | r = bus->resource[i]; |
277 | if (r == &ioport_resource || r == &iomem_resource) | ||
278 | continue; | ||
276 | if (r && (r->flags & type_mask) == type && !r->parent) | 279 | if (r && (r->flags & type_mask) == type && !r->parent) |
277 | return r; | 280 | return r; |
278 | } | 281 | } |