aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorKristen Accardi <kristen.c.accardi@intel.com>2006-02-23 20:56:03 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-23 17:35:15 -0500
commit20416ea54087c25502d6fb973b8e119973e16341 (patch)
tree47ca50997cbb408852021315ff4da315292467c2 /drivers/pci
parentceaba663055e38226a070a9668eac5881d65a2cc (diff)
[PATCH] acpiphp: add dock event handling
These patches add generic dock event handling to acpiphp. If there are pci devices that need to be inserted/removed after the dock event, the event notification will be handed down to the normal pci hotplug event handler in acpiphp so that new bridges/devices can be enumerated. Because some dock stations do not have pci bridges or pci devices that need to be inserted after a dock, acpiphp will remain loaded to handle dock events even if no hotpluggable pci slots are discovered. You probably need to have the pci=assign-busses kernel parameter enabled to use these patches, and you may not allow ibm_acpi to handle docking notifications and use this patch. This patch incorporates feedback provided by many. Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/Makefile3
-rw-r--r--drivers/pci/hotplug/acpiphp.h36
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c7
-rw-r--r--drivers/pci/hotplug/acpiphp_dock.c438
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c85
5 files changed, 545 insertions, 24 deletions
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 3c71e3077ff1..1c0ed377ed91 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -37,7 +37,8 @@ ibmphp-objs := ibmphp_core.o \
37 ibmphp_hpc.o 37 ibmphp_hpc.o
38 38
39acpiphp-objs := acpiphp_core.o \ 39acpiphp-objs := acpiphp_core.o \
40 acpiphp_glue.o 40 acpiphp_glue.o \
41 acpiphp_dock.o
41 42
42rpaphp-objs := rpaphp_core.o \ 43rpaphp-objs := rpaphp_core.o \
43 rpaphp_pci.o \ 44 rpaphp_pci.o \
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 6a91cfb0f688..885838a2e93f 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -161,6 +161,25 @@ struct acpiphp_attention_info
161 struct module *owner; 161 struct module *owner;
162}; 162};
163 163
164
165struct dependent_device {
166 struct list_head device_list;
167 struct list_head pci_list;
168 acpi_handle handle;
169 struct acpiphp_func *func;
170};
171
172
173struct acpiphp_dock_station {
174 acpi_handle handle;
175 u32 last_dock_time;
176 u32 flags;
177 struct acpiphp_func *dock_bridge;
178 struct list_head dependent_devices;
179 struct list_head pci_dependent_devices;
180};
181
182
164/* PCI bus bridge HID */ 183/* PCI bus bridge HID */
165#define ACPI_PCI_HOST_HID "PNP0A03" 184#define ACPI_PCI_HOST_HID "PNP0A03"
166 185
@@ -198,6 +217,12 @@ struct acpiphp_attention_info
198#define FUNC_HAS_PS1 (0x00000020) 217#define FUNC_HAS_PS1 (0x00000020)
199#define FUNC_HAS_PS2 (0x00000040) 218#define FUNC_HAS_PS2 (0x00000040)
200#define FUNC_HAS_PS3 (0x00000080) 219#define FUNC_HAS_PS3 (0x00000080)
220#define FUNC_HAS_DCK (0x00000100)
221#define FUNC_IS_DD (0x00000200)
222
223/* dock station flags */
224#define DOCK_DOCKING (0x00000001)
225#define DOCK_HAS_BRIDGE (0x00000002)
201 226
202/* function prototypes */ 227/* function prototypes */
203 228
@@ -211,6 +236,7 @@ extern void acpiphp_glue_exit (void);
211extern int acpiphp_get_num_slots (void); 236extern int acpiphp_get_num_slots (void);
212extern struct acpiphp_slot *get_slot_from_id (int id); 237extern struct acpiphp_slot *get_slot_from_id (int id);
213typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); 238typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
239void handle_hotplug_event_func(acpi_handle, u32, void*);
214 240
215extern int acpiphp_enable_slot (struct acpiphp_slot *slot); 241extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
216extern int acpiphp_disable_slot (struct acpiphp_slot *slot); 242extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
@@ -220,6 +246,16 @@ extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
220extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); 246extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
221extern u32 acpiphp_get_address (struct acpiphp_slot *slot); 247extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
222 248
249/* acpiphp_dock.c */
250extern int find_dock_station(void);
251extern void remove_dock_station(void);
252extern void add_dependent_device(struct dependent_device *new_dd);
253extern void add_pci_dependent_device(struct dependent_device *new_dd);
254extern struct dependent_device *get_dependent_device(acpi_handle handle);
255extern int is_dependent_device(acpi_handle handle);
256extern int detect_dependent_devices(acpi_handle *bridge_handle);
257extern struct dependent_device *alloc_dependent_device(acpi_handle handle);
258
223/* variables */ 259/* variables */
224extern int acpiphp_debug; 260extern int acpiphp_debug;
225 261
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 60c4c38047a3..bce71c933478 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -429,14 +429,17 @@ static void __exit cleanup_slots (void)
429static int __init acpiphp_init(void) 429static int __init acpiphp_init(void)
430{ 430{
431 int retval; 431 int retval;
432 int docking_station;
432 433
433 info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 434 info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
434 435
435 acpiphp_debug = debug; 436 acpiphp_debug = debug;
436 437
438 docking_station = find_dock_station();
439
437 /* read all the ACPI info from the system */ 440 /* read all the ACPI info from the system */
438 retval = init_acpi(); 441 retval = init_acpi();
439 if (retval) 442 if (retval && !(docking_station))
440 return retval; 443 return retval;
441 444
442 return init_slots(); 445 return init_slots();
@@ -448,6 +451,8 @@ static void __exit acpiphp_exit(void)
448 cleanup_slots(); 451 cleanup_slots();
449 /* deallocate internal data structures etc. */ 452 /* deallocate internal data structures etc. */
450 acpiphp_glue_exit(); 453 acpiphp_glue_exit();
454
455 remove_dock_station();
451} 456}
452 457
453module_init(acpiphp_init); 458module_init(acpiphp_init);
diff --git a/drivers/pci/hotplug/acpiphp_dock.c b/drivers/pci/hotplug/acpiphp_dock.c
new file mode 100644
index 000000000000..4f1aaf128312
--- /dev/null
+++ b/drivers/pci/hotplug/acpiphp_dock.c
@@ -0,0 +1,438 @@
1/*
2 * ACPI PCI HotPlug dock functions to ACPI CA subsystem
3 *
4 * Copyright (C) 2006 Kristen Carlson Accardi (kristen.c.accardi@intel.com)
5 * Copyright (C) 2006 Intel Corporation
6 *
7 * All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
17 * NON INFRINGEMENT. See the GNU General Public License for more
18 * details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * Send feedback to <kristen.c.accardi@intel.com>
25 *
26 */
27#include <linux/init.h>
28#include <linux/module.h>
29
30#include <linux/kernel.h>
31#include <linux/pci.h>
32#include <linux/smp_lock.h>
33#include <linux/mutex.h>
34
35#include "../pci.h"
36#include "pci_hotplug.h"
37#include "acpiphp.h"
38
39static struct acpiphp_dock_station *ds;
40#define MY_NAME "acpiphp_dock"
41
42
43int is_dependent_device(acpi_handle handle)
44{
45 return (get_dependent_device(handle) ? 1 : 0);
46}
47
48
49static acpi_status
50find_dependent_device(acpi_handle handle, u32 lvl, void *context, void **rv)
51{
52 int *count = (int *)context;
53
54 if (is_dependent_device(handle)) {
55 (*count)++;
56 return AE_CTRL_TERMINATE;
57 } else {
58 return AE_OK;
59 }
60}
61
62
63
64
65void add_dependent_device(struct dependent_device *new_dd)
66{
67 list_add_tail(&new_dd->device_list, &ds->dependent_devices);
68}
69
70
71void add_pci_dependent_device(struct dependent_device *new_dd)
72{
73 list_add_tail(&new_dd->pci_list, &ds->pci_dependent_devices);
74}
75
76
77
78struct dependent_device * get_dependent_device(acpi_handle handle)
79{
80 struct dependent_device *dd;
81
82 if (!ds)
83 return NULL;
84
85 list_for_each_entry(dd, &ds->dependent_devices, device_list) {
86 if (handle == dd->handle)
87 return dd;
88 }
89 return NULL;
90}
91
92
93
94struct dependent_device *alloc_dependent_device(acpi_handle handle)
95{
96 struct dependent_device *dd;
97
98 dd = kzalloc(sizeof(*dd), GFP_KERNEL);
99 if (dd) {
100 INIT_LIST_HEAD(&dd->pci_list);
101 INIT_LIST_HEAD(&dd->device_list);
102 dd->handle = handle;
103 }
104 return dd;
105}
106
107
108
109static int is_dock(acpi_handle handle)
110{
111 acpi_status status;
112 acpi_handle tmp;
113
114 status = acpi_get_handle(handle, "_DCK", &tmp);
115 if (ACPI_FAILURE(status)) {
116 return 0;
117 }
118 return 1;
119}
120
121
122
123static int dock_present(void)
124{
125 unsigned long sta;
126 acpi_status status;
127
128 if (ds) {
129 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
130 if (ACPI_SUCCESS(status) && sta)
131 return 1;
132 }
133 return 0;
134}
135
136
137
138static void eject_dock(void)
139{
140 struct acpi_object_list arg_list;
141 union acpi_object arg;
142
143 arg_list.count = 1;
144 arg_list.pointer = &arg;
145 arg.type = ACPI_TYPE_INTEGER;
146 arg.integer.value = 1;
147
148 if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
149 &arg_list, NULL)) || dock_present())
150 warn("%s: failed to eject dock!\n", __FUNCTION__);
151
152 return;
153}
154
155
156
157
158static acpi_status handle_dock(int dock)
159{
160 acpi_status status;
161 struct acpi_object_list arg_list;
162 union acpi_object arg;
163 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
164
165 dbg("%s: %s\n", __FUNCTION__, dock ? "docking" : "undocking");
166
167 /* _DCK method has one argument */
168 arg_list.count = 1;
169 arg_list.pointer = &arg;
170 arg.type = ACPI_TYPE_INTEGER;
171 arg.integer.value = dock;
172 status = acpi_evaluate_object(ds->handle, "_DCK",
173 &arg_list, &buffer);
174 if (ACPI_FAILURE(status))
175 err("%s: failed to execute _DCK\n", __FUNCTION__);
176 acpi_os_free(buffer.pointer);
177
178 return status;
179}
180
181
182
183static inline void dock(void)
184{
185 handle_dock(1);
186}
187
188
189
190static inline void undock(void)
191{
192 handle_dock(0);
193}
194
195
196
197/*
198 * the _DCK method can do funny things... and sometimes not
199 * hah-hah funny.
200 *
201 * TBD - figure out a way to only call fixups for
202 * systems that require them.
203 */
204static void post_dock_fixups(void)
205{
206 struct pci_bus *bus;
207 u32 buses;
208 struct dependent_device *dd;
209
210 list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list) {
211 bus = dd->func->slot->bridge->pci_bus;
212
213 /* fixup bad _DCK function that rewrites
214 * secondary bridge on slot
215 */
216 pci_read_config_dword(bus->self,
217 PCI_PRIMARY_BUS,
218 &buses);
219
220 if (((buses >> 8) & 0xff) != bus->secondary) {
221 buses = (buses & 0xff000000)
222 | ((unsigned int)(bus->primary) << 0)
223 | ((unsigned int)(bus->secondary) << 8)
224 | ((unsigned int)(bus->subordinate) << 16);
225 pci_write_config_dword(bus->self,
226 PCI_PRIMARY_BUS,
227 buses);
228 }
229 }
230}
231
232
233
234static void hotplug_pci(u32 type)
235{
236 struct dependent_device *dd;
237
238 list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list)
239 handle_hotplug_event_func(dd->handle, type, dd->func);
240}
241
242
243
244static inline void begin_dock(void)
245{
246 ds->flags |= DOCK_DOCKING;
247}
248
249
250static inline void complete_dock(void)
251{
252 ds->flags &= ~(DOCK_DOCKING);
253 ds->last_dock_time = jiffies;
254}
255
256
257static int dock_in_progress(void)
258{
259 if (ds->flags & DOCK_DOCKING ||
260 ds->last_dock_time == jiffies) {
261 dbg("dock in progress\n");
262 return 1;
263 }
264 return 0;
265}
266
267
268
269static void
270handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context)
271{
272 dbg("%s: enter\n", __FUNCTION__);
273
274 switch (type) {
275 case ACPI_NOTIFY_BUS_CHECK:
276 dbg("BUS Check\n");
277 if (!dock_in_progress() && dock_present()) {
278 begin_dock();
279 dock();
280 if (!dock_present()) {
281 err("Unable to dock!\n");
282 break;
283 }
284 post_dock_fixups();
285 hotplug_pci(type);
286 complete_dock();
287 }
288 break;
289 case ACPI_NOTIFY_EJECT_REQUEST:
290 dbg("EJECT request\n");
291 if (!dock_in_progress() && dock_present()) {
292 hotplug_pci(type);
293 undock();
294 eject_dock();
295 if (dock_present())
296 err("Unable to undock!\n");
297 }
298 break;
299 }
300}
301
302
303
304
305static acpi_status
306find_dock_ejd(acpi_handle handle, u32 lvl, void *context, void **rv)
307{
308 acpi_status status;
309 acpi_handle tmp;
310 acpi_handle dck_handle = (acpi_handle) context;
311 char objname[64];
312 struct acpi_buffer buffer = { .length = sizeof(objname),
313 .pointer = objname };
314 struct acpi_buffer ejd_buffer = {ACPI_ALLOCATE_BUFFER, NULL};
315 union acpi_object *ejd_obj;
316
317 status = acpi_get_handle(handle, "_EJD", &tmp);
318 if (ACPI_FAILURE(status))
319 return AE_OK;
320
321 /* make sure we are dependent on the dock device,
322 * by executing the _EJD method, then getting a handle
323 * to the device referenced by that name. If that
324 * device handle is the same handle as the dock station
325 * handle, then we are a device dependent on the dock station
326 */
327 acpi_get_name(dck_handle, ACPI_FULL_PATHNAME, &buffer);
328 status = acpi_evaluate_object(handle, "_EJD", NULL, &ejd_buffer);
329 if (ACPI_FAILURE(status)) {
330 err("Unable to execute _EJD!\n");
331 goto find_ejd_out;
332 }
333 ejd_obj = ejd_buffer.pointer;
334 status = acpi_get_handle(NULL, ejd_obj->string.pointer, &tmp);
335 if (ACPI_FAILURE(status))
336 goto find_ejd_out;
337
338 if (tmp == dck_handle) {
339 struct dependent_device *dd;
340 dbg("%s: found device dependent on dock\n", __FUNCTION__);
341 dd = alloc_dependent_device(handle);
342 if (!dd) {
343 err("Can't allocate memory for dependent device!\n");
344 goto find_ejd_out;
345 }
346 add_dependent_device(dd);
347 }
348
349find_ejd_out:
350 acpi_os_free(ejd_buffer.pointer);
351 return AE_OK;
352}
353
354
355
356int detect_dependent_devices(acpi_handle *bridge_handle)
357{
358 acpi_status status;
359 int count;
360
361 count = 0;
362
363 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
364 (u32)1, find_dependent_device,
365 (void *)&count, NULL);
366
367 return count;
368}
369
370
371
372
373
374static acpi_status
375find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
376{
377 int *count = (int *)context;
378
379 if (is_dock(handle)) {
380 dbg("%s: found dock\n", __FUNCTION__);
381 ds = kzalloc(sizeof(*ds), GFP_KERNEL);
382 ds->handle = handle;
383 INIT_LIST_HEAD(&ds->dependent_devices);
384 INIT_LIST_HEAD(&ds->pci_dependent_devices);
385
386 /* look for devices dependent on dock station */
387 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
388 ACPI_UINT32_MAX, find_dock_ejd, handle, NULL);
389
390 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
391 handle_hotplug_event_dock, ds);
392 (*count)++;
393 }
394
395 return AE_OK;
396}
397
398
399
400
401int find_dock_station(void)
402{
403 int num = 0;
404
405 ds = NULL;
406
407 /* start from the root object, because some laptops define
408 * _DCK methods outside the scope of PCI (IBM x-series laptop)
409 */
410 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
411 ACPI_UINT32_MAX, find_dock, &num, NULL);
412
413 return num;
414}
415
416
417
418void remove_dock_station(void)
419{
420 struct dependent_device *dd, *tmp;
421 if (ds) {
422 if (ACPI_FAILURE(acpi_remove_notify_handler(ds->handle,
423 ACPI_SYSTEM_NOTIFY, handle_hotplug_event_dock)))
424 err("failed to remove dock notify handler\n");
425
426 /* free all dependent devices */
427 list_for_each_entry_safe(dd, tmp, &ds->dependent_devices,
428 device_list)
429 kfree(dd);
430
431 /* no need to touch the pci_dependent_device list,
432 * cause all memory was freed above
433 */
434 kfree(ds);
435 }
436}
437
438
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index fe0a6b7662f7..22d0f1cf1362 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -57,7 +57,6 @@ static LIST_HEAD(bridge_list);
57#define MY_NAME "acpiphp_glue" 57#define MY_NAME "acpiphp_glue"
58 58
59static void handle_hotplug_event_bridge (acpi_handle, u32, void *); 59static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
60static void handle_hotplug_event_func (acpi_handle, u32, void *);
61static void acpiphp_sanitize_bus(struct pci_bus *bus); 60static void acpiphp_sanitize_bus(struct pci_bus *bus);
62static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); 61static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
63 62
@@ -125,6 +124,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
125 struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; 124 struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
126 struct acpiphp_slot *slot; 125 struct acpiphp_slot *slot;
127 struct acpiphp_func *newfunc; 126 struct acpiphp_func *newfunc;
127 struct dependent_device *dd;
128 acpi_handle tmp; 128 acpi_handle tmp;
129 acpi_status status = AE_OK; 129 acpi_status status = AE_OK;
130 unsigned long adr, sun; 130 unsigned long adr, sun;
@@ -138,7 +138,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
138 138
139 status = acpi_get_handle(handle, "_EJ0", &tmp); 139 status = acpi_get_handle(handle, "_EJ0", &tmp);
140 140
141 if (ACPI_FAILURE(status)) 141 if (ACPI_FAILURE(status) && !(is_dependent_device(handle)))
142 return AE_OK; 142 return AE_OK;
143 143
144 device = (adr >> 16) & 0xffff; 144 device = (adr >> 16) & 0xffff;
@@ -152,7 +152,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
152 INIT_LIST_HEAD(&newfunc->sibling); 152 INIT_LIST_HEAD(&newfunc->sibling);
153 newfunc->handle = handle; 153 newfunc->handle = handle;
154 newfunc->function = function; 154 newfunc->function = function;
155 newfunc->flags = FUNC_HAS_EJ0; 155 if (ACPI_SUCCESS(status))
156 newfunc->flags = FUNC_HAS_EJ0;
156 157
157 if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) 158 if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
158 newfunc->flags |= FUNC_HAS_STA; 159 newfunc->flags |= FUNC_HAS_STA;
@@ -163,6 +164,19 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
163 if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) 164 if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
164 newfunc->flags |= FUNC_HAS_PS3; 165 newfunc->flags |= FUNC_HAS_PS3;
165 166
167 if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) {
168 newfunc->flags |= FUNC_HAS_DCK;
169 /* add to devices dependent on dock station,
170 * because this may actually be the dock bridge
171 */
172 dd = alloc_dependent_device(handle);
173 if (!dd)
174 err("Can't allocate memory for "
175 "new dependent device!\n");
176 else
177 add_dependent_device(dd);
178 }
179
166 status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); 180 status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
167 if (ACPI_FAILURE(status)) 181 if (ACPI_FAILURE(status))
168 sun = -1; 182 sun = -1;
@@ -210,18 +224,35 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
210 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); 224 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
211 } 225 }
212 226
227 /* if this is a device dependent on a dock station,
228 * associate the acpiphp_func to the dependent_device
229 * struct.
230 */
231 if ((dd = get_dependent_device(handle))) {
232 newfunc->flags |= FUNC_IS_DD;
233 /*
234 * we don't want any devices which is dependent
235 * on the dock to have it's _EJ0 method executed.
236 * because we need to run _DCK first.
237 */
238 newfunc->flags &= ~FUNC_HAS_EJ0;
239 dd->func = newfunc;
240 add_pci_dependent_device(dd);
241 }
242
213 /* install notify handler */ 243 /* install notify handler */
214 status = acpi_install_notify_handler(handle, 244 if (!(newfunc->flags & FUNC_HAS_DCK)) {
245 status = acpi_install_notify_handler(handle,
215 ACPI_SYSTEM_NOTIFY, 246 ACPI_SYSTEM_NOTIFY,
216 handle_hotplug_event_func, 247 handle_hotplug_event_func,
217 newfunc); 248 newfunc);
218 249
219 if (ACPI_FAILURE(status)) { 250 if (ACPI_FAILURE(status))
220 err("failed to register interrupt notify handler\n"); 251 err("failed to register interrupt notify handler\n");
221 return status; 252 } else
222 } 253 status = AE_OK;
223 254
224 return AE_OK; 255 return status;
225} 256}
226 257
227 258
@@ -410,7 +441,8 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
410 goto out; 441 goto out;
411 442
412 /* check if this bridge has ejectable slots */ 443 /* check if this bridge has ejectable slots */
413 if (detect_ejectable_slots(handle) > 0) { 444 if ((detect_ejectable_slots(handle) > 0) ||
445 (detect_dependent_devices(handle) > 0)) {
414 dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); 446 dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
415 add_p2p_bridge(handle, dev); 447 add_p2p_bridge(handle, dev);
416 } 448 }
@@ -512,11 +544,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
512 list_for_each_safe (list, tmp, &slot->funcs) { 544 list_for_each_safe (list, tmp, &slot->funcs) {
513 struct acpiphp_func *func; 545 struct acpiphp_func *func;
514 func = list_entry(list, struct acpiphp_func, sibling); 546 func = list_entry(list, struct acpiphp_func, sibling);
515 status = acpi_remove_notify_handler(func->handle, 547 if (!(func->flags & FUNC_HAS_DCK)) {
548 status = acpi_remove_notify_handler(func->handle,
516 ACPI_SYSTEM_NOTIFY, 549 ACPI_SYSTEM_NOTIFY,
517 handle_hotplug_event_func); 550 handle_hotplug_event_func);
518 if (ACPI_FAILURE(status)) 551 if (ACPI_FAILURE(status))
519 err("failed to remove notify handler\n"); 552 err("failed to remove notify handler\n");
553 }
520 pci_dev_put(func->pci_dev); 554 pci_dev_put(func->pci_dev);
521 list_del(list); 555 list_del(list);
522 kfree(func); 556 kfree(func);
@@ -828,14 +862,21 @@ static int acpiphp_bus_add(struct acpiphp_func *func)
828 dbg("no parent device, assuming NULL\n"); 862 dbg("no parent device, assuming NULL\n");
829 pdevice = NULL; 863 pdevice = NULL;
830 } 864 }
831 if (acpi_bus_get_device(func->handle, &device)) { 865 if (!acpi_bus_get_device(func->handle, &device)) {
832 ret_val = acpi_bus_add(&device, pdevice, func->handle, 866 dbg("bus exists... trim\n");
833 ACPI_BUS_TYPE_DEVICE); 867 /* this shouldn't be in here, so remove
834 if (ret_val) { 868 * the bus then re-add it...
835 dbg("error adding bus, %x\n", 869 */
836 -ret_val); 870 ret_val = acpi_bus_trim(device, 1);
837 goto acpiphp_bus_add_out; 871 dbg("acpi_bus_trim return %x\n", ret_val);
838 } 872 }
873
874 ret_val = acpi_bus_add(&device, pdevice, func->handle,
875 ACPI_BUS_TYPE_DEVICE);
876 if (ret_val) {
877 dbg("error adding bus, %x\n",
878 -ret_val);
879 goto acpiphp_bus_add_out;
839 } 880 }
840 /* 881 /*
841 * try to start anyway. We could have failed to add 882 * try to start anyway. We could have failed to add
@@ -1307,7 +1348,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
1307 * handles ACPI event notification on slots 1348 * handles ACPI event notification on slots
1308 * 1349 *
1309 */ 1350 */
1310static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) 1351void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
1311{ 1352{
1312 struct acpiphp_func *func; 1353 struct acpiphp_func *func;
1313 char objname[64]; 1354 char objname[64];