diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 117 |
1 files changed, 21 insertions, 96 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 3affc6472e65..f09b1010d477 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/kernel.h> | 46 | #include <linux/kernel.h> |
47 | #include <linux/pci.h> | 47 | #include <linux/pci.h> |
48 | #include <linux/pci_hotplug.h> | 48 | #include <linux/pci_hotplug.h> |
49 | #include <linux/pci-acpi.h> | ||
49 | #include <linux/mutex.h> | 50 | #include <linux/mutex.h> |
50 | 51 | ||
51 | #include "../pci.h" | 52 | #include "../pci.h" |
@@ -62,61 +63,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus); | |||
62 | static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); | 63 | static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); |
63 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); | 64 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); |
64 | 65 | ||
65 | |||
66 | /* | ||
67 | * initialization & terminatation routines | ||
68 | */ | ||
69 | |||
70 | /** | ||
71 | * is_ejectable - determine if a slot is ejectable | ||
72 | * @handle: handle to acpi namespace | ||
73 | * | ||
74 | * Ejectable slot should satisfy at least these conditions: | ||
75 | * | ||
76 | * 1. has _ADR method | ||
77 | * 2. has _EJ0 method | ||
78 | * | ||
79 | * optionally | ||
80 | * | ||
81 | * 1. has _STA method | ||
82 | * 2. has _PS0 method | ||
83 | * 3. has _PS3 method | ||
84 | * 4. .. | ||
85 | */ | ||
86 | static int is_ejectable(acpi_handle handle) | ||
87 | { | ||
88 | acpi_status status; | ||
89 | acpi_handle tmp; | ||
90 | |||
91 | status = acpi_get_handle(handle, "_ADR", &tmp); | ||
92 | if (ACPI_FAILURE(status)) { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | status = acpi_get_handle(handle, "_EJ0", &tmp); | ||
97 | if (ACPI_FAILURE(status)) { | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | |||
105 | /* callback routine to check for the existence of ejectable slots */ | ||
106 | static acpi_status | ||
107 | is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
108 | { | ||
109 | int *count = (int *)context; | ||
110 | |||
111 | if (is_ejectable(handle)) { | ||
112 | (*count)++; | ||
113 | /* only one ejectable slot is enough */ | ||
114 | return AE_CTRL_TERMINATE; | ||
115 | } else { | ||
116 | return AE_OK; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | /* callback routine to check for the existence of a pci dock device */ | 66 | /* callback routine to check for the existence of a pci dock device */ |
121 | static acpi_status | 67 | static acpi_status |
122 | is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) | 68 | is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) |
@@ -131,9 +77,6 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
131 | } | 77 | } |
132 | } | 78 | } |
133 | 79 | ||
134 | |||
135 | |||
136 | |||
137 | /* | 80 | /* |
138 | * the _DCK method can do funny things... and sometimes not | 81 | * the _DCK method can do funny things... and sometimes not |
139 | * hah-hah funny. | 82 | * hah-hah funny. |
@@ -160,9 +103,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, | |||
160 | 103 | ||
161 | if (((buses >> 8) & 0xff) != bus->secondary) { | 104 | if (((buses >> 8) & 0xff) != bus->secondary) { |
162 | buses = (buses & 0xff000000) | 105 | buses = (buses & 0xff000000) |
163 | | ((unsigned int)(bus->primary) << 0) | 106 | | ((unsigned int)(bus->primary) << 0) |
164 | | ((unsigned int)(bus->secondary) << 8) | 107 | | ((unsigned int)(bus->secondary) << 8) |
165 | | ((unsigned int)(bus->subordinate) << 16); | 108 | | ((unsigned int)(bus->subordinate) << 16); |
166 | pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); | 109 | pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); |
167 | } | 110 | } |
168 | return NOTIFY_OK; | 111 | return NOTIFY_OK; |
@@ -184,17 +127,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
184 | acpi_status status = AE_OK; | 127 | acpi_status status = AE_OK; |
185 | unsigned long long adr, sun; | 128 | unsigned long long adr, sun; |
186 | int device, function, retval; | 129 | int device, function, retval; |
130 | struct pci_bus *pbus = bridge->pci_bus; | ||
187 | 131 | ||
188 | status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); | 132 | if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) |
189 | |||
190 | if (ACPI_FAILURE(status)) | ||
191 | return AE_OK; | ||
192 | |||
193 | status = acpi_get_handle(handle, "_EJ0", &tmp); | ||
194 | |||
195 | if (ACPI_FAILURE(status) && !(is_dock_device(handle))) | ||
196 | return AE_OK; | 133 | return AE_OK; |
197 | 134 | ||
135 | acpi_evaluate_integer(handle, "_ADR", NULL, &adr); | ||
198 | device = (adr >> 16) & 0xffff; | 136 | device = (adr >> 16) & 0xffff; |
199 | function = adr & 0xffff; | 137 | function = adr & 0xffff; |
200 | 138 | ||
@@ -205,7 +143,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
205 | INIT_LIST_HEAD(&newfunc->sibling); | 143 | INIT_LIST_HEAD(&newfunc->sibling); |
206 | newfunc->handle = handle; | 144 | newfunc->handle = handle; |
207 | newfunc->function = function; | 145 | newfunc->function = function; |
208 | if (ACPI_SUCCESS(status)) | 146 | |
147 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) | ||
209 | newfunc->flags = FUNC_HAS_EJ0; | 148 | newfunc->flags = FUNC_HAS_EJ0; |
210 | 149 | ||
211 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) | 150 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) |
@@ -256,8 +195,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
256 | bridge->nr_slots++; | 195 | bridge->nr_slots++; |
257 | 196 | ||
258 | dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", | 197 | dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", |
259 | slot->sun, pci_domain_nr(bridge->pci_bus), | 198 | slot->sun, pci_domain_nr(pbus), pbus->number, device); |
260 | bridge->pci_bus->number, slot->device); | ||
261 | retval = acpiphp_register_hotplug_slot(slot); | 199 | retval = acpiphp_register_hotplug_slot(slot); |
262 | if (retval) { | 200 | if (retval) { |
263 | if (retval == -EBUSY) | 201 | if (retval == -EBUSY) |
@@ -274,8 +212,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
274 | list_add_tail(&newfunc->sibling, &slot->funcs); | 212 | list_add_tail(&newfunc->sibling, &slot->funcs); |
275 | 213 | ||
276 | /* associate corresponding pci_dev */ | 214 | /* associate corresponding pci_dev */ |
277 | newfunc->pci_dev = pci_get_slot(bridge->pci_bus, | 215 | newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function)); |
278 | PCI_DEVFN(device, function)); | ||
279 | if (newfunc->pci_dev) { | 216 | if (newfunc->pci_dev) { |
280 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | 217 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); |
281 | } | 218 | } |
@@ -324,27 +261,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
324 | 261 | ||
325 | 262 | ||
326 | /* see if it's worth looking at this bridge */ | 263 | /* see if it's worth looking at this bridge */ |
327 | static int detect_ejectable_slots(acpi_handle *bridge_handle) | 264 | static int detect_ejectable_slots(struct pci_bus *pbus) |
328 | { | 265 | { |
329 | acpi_status status; | 266 | int found = acpi_pci_detect_ejectable(pbus); |
330 | int count; | 267 | if (!found) { |
331 | 268 | acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus); | |
332 | count = 0; | 269 | acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, |
333 | 270 | is_pci_dock_device, (void *)&found, NULL); | |
334 | /* only check slots defined directly below bridge object */ | 271 | } |
335 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, | 272 | return found; |
336 | is_ejectable_slot, (void *)&count, NULL); | ||
337 | |||
338 | /* | ||
339 | * we also need to add this bridge if there is a dock bridge or | ||
340 | * other pci device on a dock station (removable) | ||
341 | */ | ||
342 | if (!count) | ||
343 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, | ||
344 | (u32)1, is_pci_dock_device, (void *)&count, | ||
345 | NULL); | ||
346 | |||
347 | return count; | ||
348 | } | 273 | } |
349 | 274 | ||
350 | 275 | ||
@@ -554,7 +479,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
554 | goto out; | 479 | goto out; |
555 | 480 | ||
556 | /* check if this bridge has ejectable slots */ | 481 | /* check if this bridge has ejectable slots */ |
557 | if ((detect_ejectable_slots(handle) > 0)) { | 482 | if ((detect_ejectable_slots(dev->subordinate) > 0)) { |
558 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); | 483 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); |
559 | add_p2p_bridge(handle, dev); | 484 | add_p2p_bridge(handle, dev); |
560 | } | 485 | } |
@@ -615,7 +540,7 @@ static int add_bridge(acpi_handle handle) | |||
615 | } | 540 | } |
616 | 541 | ||
617 | /* check if this bridge has ejectable slots */ | 542 | /* check if this bridge has ejectable slots */ |
618 | if (detect_ejectable_slots(handle) > 0) { | 543 | if (detect_ejectable_slots(pci_bus) > 0) { |
619 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); | 544 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); |
620 | add_host_bridge(handle, pci_bus); | 545 | add_host_bridge(handle, pci_bus); |
621 | } | 546 | } |