diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-16 20:25:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-16 20:25:46 -0400 |
commit | dc7c65db2845a8d17432d89252c4227a9a7cb15f (patch) | |
tree | 79030b0aaaafc04bc4303c21495134e744afc058 /drivers/pci/hotplug | |
parent | 8a0ca91e1db5de5eb5b18cfa919d52ff8be375af (diff) | |
parent | 58b6e5538460be358fdf1286d9a2fbcfcc2cfaba (diff) |
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (72 commits)
Revert "x86/PCI: ACPI based PCI gap calculation"
PCI: remove unnecessary volatile in PCIe hotplug struct controller
x86/PCI: ACPI based PCI gap calculation
PCI: include linux/pm_wakeup.h for device_set_wakeup_capable
PCI PM: Fix pci_prepare_to_sleep
x86/PCI: Fix PCI config space for domains > 0
Fix acpi_pm_device_sleep_wake() by providing a stub for CONFIG_PM_SLEEP=n
PCI: Simplify PCI device PM code
PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep
PCI ACPI: Rework PCI handling of wake-up
ACPI: Introduce new device wakeup flag 'prepared'
ACPI: Introduce acpi_device_sleep_wake function
PCI: rework pci_set_power_state function to call platform first
PCI: Introduce platform_pci_power_manageable function
ACPI: Introduce acpi_bus_power_manageable function
PCI: make pci_name use dev_name
PCI: handle pci_name() being const
PCI: add stub for pci_set_consistent_dma_mask()
PCI: remove unused arch pcibios_update_resource() functions
PCI: fix pci_setup_device()'s sprinting into a const buffer
...
Fixed up conflicts in various files (arch/x86/kernel/setup_64.c,
arch/x86/pci/irq.c, arch/x86/pci/pci.h, drivers/acpi/sleep/main.c,
drivers/pci/pci.c, drivers/pci/pci.h, include/acpi/acpi_bus.h) from x86
and ACPI updates manually.
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 85 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_core.c | 25 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 23 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_ibm.c | 6 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpci_hotplug_core.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpqphp_core.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/fakephp.c | 86 | ||||
-rw-r--r-- | drivers/pci/hotplug/ibmphp_ebda.c | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/pci_hotplug_core.c | 284 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 16 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 127 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 318 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpadlpar_sysfs.c | 5 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_slot.c | 44 | ||||
-rw-r--r-- | drivers/pci/hotplug/sgi_hotplug.c | 12 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp.h | 14 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 37 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 1 |
19 files changed, 471 insertions, 622 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index f8c187a763bd..93e37f0666ab 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/types.h> | 30 | #include <linux/types.h> |
31 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
32 | #include <linux/pci_hotplug.h> | 32 | #include <linux/pci_hotplug.h> |
33 | #include <linux/pci-acpi.h> | ||
33 | #include <acpi/acpi.h> | 34 | #include <acpi/acpi.h> |
34 | #include <acpi/acpi_bus.h> | 35 | #include <acpi/acpi_bus.h> |
35 | #include <acpi/actypes.h> | 36 | #include <acpi/actypes.h> |
@@ -299,7 +300,7 @@ free_and_return: | |||
299 | * | 300 | * |
300 | * @handle - the handle of the hotplug controller. | 301 | * @handle - the handle of the hotplug controller. |
301 | */ | 302 | */ |
302 | acpi_status acpi_run_oshp(acpi_handle handle) | 303 | static acpi_status acpi_run_oshp(acpi_handle handle) |
303 | { | 304 | { |
304 | acpi_status status; | 305 | acpi_status status; |
305 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; | 306 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; |
@@ -322,9 +323,6 @@ acpi_status acpi_run_oshp(acpi_handle handle) | |||
322 | kfree(string.pointer); | 323 | kfree(string.pointer); |
323 | return status; | 324 | return status; |
324 | } | 325 | } |
325 | EXPORT_SYMBOL_GPL(acpi_run_oshp); | ||
326 | |||
327 | |||
328 | 326 | ||
329 | /* acpi_get_hp_params_from_firmware | 327 | /* acpi_get_hp_params_from_firmware |
330 | * | 328 | * |
@@ -374,6 +372,85 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, | |||
374 | } | 372 | } |
375 | EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware); | 373 | EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware); |
376 | 374 | ||
375 | /** | ||
376 | * acpi_get_hp_hw_control_from_firmware | ||
377 | * @dev: the pci_dev of the bridge that has a hotplug controller | ||
378 | * @flags: requested control bits for _OSC | ||
379 | * | ||
380 | * Attempt to take hotplug control from firmware. | ||
381 | */ | ||
382 | int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) | ||
383 | { | ||
384 | acpi_status status; | ||
385 | acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); | ||
386 | struct pci_dev *pdev = dev; | ||
387 | struct pci_bus *parent; | ||
388 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
389 | |||
390 | flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | | ||
391 | OSC_SHPC_NATIVE_HP_CONTROL | | ||
392 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||
393 | if (!flags) { | ||
394 | err("Invalid flags %u specified!\n", flags); | ||
395 | return -EINVAL; | ||
396 | } | ||
397 | |||
398 | /* | ||
399 | * Per PCI firmware specification, we should run the ACPI _OSC | ||
400 | * method to get control of hotplug hardware before using it. If | ||
401 | * an _OSC is missing, we look for an OSHP to do the same thing. | ||
402 | * To handle different BIOS behavior, we look for _OSC and OSHP | ||
403 | * within the scope of the hotplug controller and its parents, | ||
404 | * upto the host bridge under which this controller exists. | ||
405 | */ | ||
406 | while (!handle) { | ||
407 | /* | ||
408 | * This hotplug controller was not listed in the ACPI name | ||
409 | * space at all. Try to get acpi handle of parent pci bus. | ||
410 | */ | ||
411 | if (!pdev || !pdev->bus->parent) | ||
412 | break; | ||
413 | parent = pdev->bus->parent; | ||
414 | dbg("Could not find %s in acpi namespace, trying parent\n", | ||
415 | pci_name(pdev)); | ||
416 | if (!parent->self) | ||
417 | /* Parent must be a host bridge */ | ||
418 | handle = acpi_get_pci_rootbridge_handle( | ||
419 | pci_domain_nr(parent), | ||
420 | parent->number); | ||
421 | else | ||
422 | handle = DEVICE_ACPI_HANDLE(&(parent->self->dev)); | ||
423 | pdev = parent->self; | ||
424 | } | ||
425 | |||
426 | while (handle) { | ||
427 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); | ||
428 | dbg("Trying to get hotplug control for %s \n", | ||
429 | (char *)string.pointer); | ||
430 | status = pci_osc_control_set(handle, flags); | ||
431 | if (status == AE_NOT_FOUND) | ||
432 | status = acpi_run_oshp(handle); | ||
433 | if (ACPI_SUCCESS(status)) { | ||
434 | dbg("Gained control for hotplug HW for pci %s (%s)\n", | ||
435 | pci_name(dev), (char *)string.pointer); | ||
436 | kfree(string.pointer); | ||
437 | return 0; | ||
438 | } | ||
439 | if (acpi_root_bridge(handle)) | ||
440 | break; | ||
441 | chandle = handle; | ||
442 | status = acpi_get_parent(chandle, &handle); | ||
443 | if (ACPI_FAILURE(status)) | ||
444 | break; | ||
445 | } | ||
446 | |||
447 | dbg("Cannot get control of hotplug hardware for pci %s\n", | ||
448 | pci_name(dev)); | ||
449 | |||
450 | kfree(string.pointer); | ||
451 | return -ENODEV; | ||
452 | } | ||
453 | EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware); | ||
377 | 454 | ||
378 | /* acpi_root_bridge - check to see if this acpi object is a root bridge | 455 | /* acpi_root_bridge - check to see if this acpi object is a root bridge |
379 | * | 456 | * |
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 7a29164d4b32..eecf7cbf4139 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -215,7 +215,6 @@ extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot); | |||
215 | extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); | 215 | extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); |
216 | extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); | 216 | extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); |
217 | extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); | 217 | extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); |
218 | extern u32 acpiphp_get_address (struct acpiphp_slot *slot); | ||
219 | 218 | ||
220 | /* variables */ | 219 | /* variables */ |
221 | extern int acpiphp_debug; | 220 | extern int acpiphp_debug; |
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 7af68ba27903..0e496e866a84 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c | |||
@@ -70,7 +70,6 @@ static int disable_slot (struct hotplug_slot *slot); | |||
70 | static int set_attention_status (struct hotplug_slot *slot, u8 value); | 70 | static int set_attention_status (struct hotplug_slot *slot, u8 value); |
71 | static int get_power_status (struct hotplug_slot *slot, u8 *value); | 71 | static int get_power_status (struct hotplug_slot *slot, u8 *value); |
72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
73 | static int get_address (struct hotplug_slot *slot, u32 *value); | ||
74 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 73 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
75 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 74 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
76 | 75 | ||
@@ -83,7 +82,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = { | |||
83 | .get_attention_status = get_attention_status, | 82 | .get_attention_status = get_attention_status, |
84 | .get_latch_status = get_latch_status, | 83 | .get_latch_status = get_latch_status, |
85 | .get_adapter_status = get_adapter_status, | 84 | .get_adapter_status = get_adapter_status, |
86 | .get_address = get_address, | ||
87 | }; | 85 | }; |
88 | 86 | ||
89 | 87 | ||
@@ -274,23 +272,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | |||
274 | return 0; | 272 | return 0; |
275 | } | 273 | } |
276 | 274 | ||
277 | |||
278 | /** | ||
279 | * get_address - get pci address of a slot | ||
280 | * @hotplug_slot: slot to get status | ||
281 | * @value: pointer to struct pci_busdev (seg, bus, dev) | ||
282 | */ | ||
283 | static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) | ||
284 | { | ||
285 | struct slot *slot = hotplug_slot->private; | ||
286 | |||
287 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | ||
288 | |||
289 | *value = acpiphp_get_address(slot->acpi_slot); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int __init init_acpi(void) | 275 | static int __init init_acpi(void) |
295 | { | 276 | { |
296 | int retval; | 277 | int retval; |
@@ -357,7 +338,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) | |||
357 | acpiphp_slot->slot = slot; | 338 | acpiphp_slot->slot = slot; |
358 | snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun); | 339 | snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun); |
359 | 340 | ||
360 | retval = pci_hp_register(slot->hotplug_slot); | 341 | retval = pci_hp_register(slot->hotplug_slot, |
342 | acpiphp_slot->bridge->pci_bus, | ||
343 | acpiphp_slot->device); | ||
344 | if (retval == -EBUSY) | ||
345 | goto error_hpslot; | ||
361 | if (retval) { | 346 | if (retval) { |
362 | err("pci_hp_register failed with error %d\n", retval); | 347 | err("pci_hp_register failed with error %d\n", retval); |
363 | goto error_hpslot; | 348 | goto error_hpslot; |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 91156f85a926..a3e4705dd8f0 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -258,7 +258,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
258 | bridge->pci_bus->number, slot->device); | 258 | bridge->pci_bus->number, slot->device); |
259 | retval = acpiphp_register_hotplug_slot(slot); | 259 | retval = acpiphp_register_hotplug_slot(slot); |
260 | if (retval) { | 260 | if (retval) { |
261 | warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval); | 261 | if (retval == -EBUSY) |
262 | warn("Slot %d already registered by another " | ||
263 | "hotplug driver\n", slot->sun); | ||
264 | else | ||
265 | warn("acpiphp_register_hotplug_slot failed " | ||
266 | "(err code = 0x%x)\n", retval); | ||
262 | goto err_exit; | 267 | goto err_exit; |
263 | } | 268 | } |
264 | } | 269 | } |
@@ -1878,19 +1883,3 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) | |||
1878 | 1883 | ||
1879 | return (sta == 0) ? 0 : 1; | 1884 | return (sta == 0) ? 0 : 1; |
1880 | } | 1885 | } |
1881 | |||
1882 | |||
1883 | /* | ||
1884 | * pci address (seg/bus/dev) | ||
1885 | */ | ||
1886 | u32 acpiphp_get_address(struct acpiphp_slot *slot) | ||
1887 | { | ||
1888 | u32 address; | ||
1889 | struct pci_bus *pci_bus = slot->bridge->pci_bus; | ||
1890 | |||
1891 | address = (pci_domain_nr(pci_bus) << 16) | | ||
1892 | (pci_bus->number << 8) | | ||
1893 | slot->device; | ||
1894 | |||
1895 | return address; | ||
1896 | } | ||
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index ede9051fdb5d..2b7c45e39370 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c | |||
@@ -33,8 +33,10 @@ | |||
33 | #include <linux/kobject.h> | 33 | #include <linux/kobject.h> |
34 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
35 | #include <linux/moduleparam.h> | 35 | #include <linux/moduleparam.h> |
36 | #include <linux/pci.h> | ||
36 | 37 | ||
37 | #include "acpiphp.h" | 38 | #include "acpiphp.h" |
39 | #include "../pci.h" | ||
38 | 40 | ||
39 | #define DRIVER_VERSION "1.0.1" | 41 | #define DRIVER_VERSION "1.0.1" |
40 | #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" | 42 | #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" |
@@ -430,7 +432,7 @@ static int __init ibm_acpiphp_init(void) | |||
430 | int retval = 0; | 432 | int retval = 0; |
431 | acpi_status status; | 433 | acpi_status status; |
432 | struct acpi_device *device; | 434 | struct acpi_device *device; |
433 | struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; | 435 | struct kobject *sysdir = &pci_slots_kset->kobj; |
434 | 436 | ||
435 | dbg("%s\n", __func__); | 437 | dbg("%s\n", __func__); |
436 | 438 | ||
@@ -477,7 +479,7 @@ init_return: | |||
477 | static void __exit ibm_acpiphp_exit(void) | 479 | static void __exit ibm_acpiphp_exit(void) |
478 | { | 480 | { |
479 | acpi_status status; | 481 | acpi_status status; |
480 | struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; | 482 | struct kobject *sysdir = &pci_slots_kset->kobj; |
481 | 483 | ||
482 | dbg("%s\n", __func__); | 484 | dbg("%s\n", __func__); |
483 | 485 | ||
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index d8a6b80ab42a..935947991dc9 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c | |||
@@ -285,7 +285,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) | |||
285 | info->attention_status = cpci_get_attention_status(slot); | 285 | info->attention_status = cpci_get_attention_status(slot); |
286 | 286 | ||
287 | dbg("registering slot %s", slot->hotplug_slot->name); | 287 | dbg("registering slot %s", slot->hotplug_slot->name); |
288 | status = pci_hp_register(slot->hotplug_slot); | 288 | status = pci_hp_register(slot->hotplug_slot, bus, i); |
289 | if (status) { | 289 | if (status) { |
290 | err("pci_hp_register failed with error %d", status); | 290 | err("pci_hp_register failed with error %d", status); |
291 | goto error_name; | 291 | goto error_name; |
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 36b115b27b0b..54defec51d08 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c | |||
@@ -434,7 +434,9 @@ static int ctrl_slot_setup(struct controller *ctrl, | |||
434 | slot->bus, slot->device, | 434 | slot->bus, slot->device, |
435 | slot->number, ctrl->slot_device_offset, | 435 | slot->number, ctrl->slot_device_offset, |
436 | slot_number); | 436 | slot_number); |
437 | result = pci_hp_register(hotplug_slot); | 437 | result = pci_hp_register(hotplug_slot, |
438 | ctrl->pci_dev->subordinate, | ||
439 | slot->device); | ||
438 | if (result) { | 440 | if (result) { |
439 | err("pci_hp_register failed with error %d\n", result); | 441 | err("pci_hp_register failed with error %d\n", result); |
440 | goto error_name; | 442 | goto error_name; |
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 7e9a827c2687..40337a06c18a 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c | |||
@@ -66,6 +66,7 @@ struct dummy_slot { | |||
66 | struct pci_dev *dev; | 66 | struct pci_dev *dev; |
67 | struct work_struct remove_work; | 67 | struct work_struct remove_work; |
68 | unsigned long removed; | 68 | unsigned long removed; |
69 | char name[8]; | ||
69 | }; | 70 | }; |
70 | 71 | ||
71 | static int debug; | 72 | static int debug; |
@@ -100,6 +101,7 @@ static int add_slot(struct pci_dev *dev) | |||
100 | struct dummy_slot *dslot; | 101 | struct dummy_slot *dslot; |
101 | struct hotplug_slot *slot; | 102 | struct hotplug_slot *slot; |
102 | int retval = -ENOMEM; | 103 | int retval = -ENOMEM; |
104 | static int count = 1; | ||
103 | 105 | ||
104 | slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); | 106 | slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); |
105 | if (!slot) | 107 | if (!slot) |
@@ -113,18 +115,18 @@ static int add_slot(struct pci_dev *dev) | |||
113 | slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; | 115 | slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; |
114 | slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; | 116 | slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; |
115 | 117 | ||
116 | slot->name = &dev->dev.bus_id[0]; | ||
117 | dbg("slot->name = %s\n", slot->name); | ||
118 | |||
119 | dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); | 118 | dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); |
120 | if (!dslot) | 119 | if (!dslot) |
121 | goto error_info; | 120 | goto error_info; |
122 | 121 | ||
122 | slot->name = dslot->name; | ||
123 | snprintf(slot->name, sizeof(dslot->name), "fake%d", count++); | ||
124 | dbg("slot->name = %s\n", slot->name); | ||
123 | slot->ops = &dummy_hotplug_slot_ops; | 125 | slot->ops = &dummy_hotplug_slot_ops; |
124 | slot->release = &dummy_release; | 126 | slot->release = &dummy_release; |
125 | slot->private = dslot; | 127 | slot->private = dslot; |
126 | 128 | ||
127 | retval = pci_hp_register(slot); | 129 | retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn)); |
128 | if (retval) { | 130 | if (retval) { |
129 | err("pci_hp_register failed with error %d\n", retval); | 131 | err("pci_hp_register failed with error %d\n", retval); |
130 | goto error_dslot; | 132 | goto error_dslot; |
@@ -148,17 +150,17 @@ error: | |||
148 | static int __init pci_scan_buses(void) | 150 | static int __init pci_scan_buses(void) |
149 | { | 151 | { |
150 | struct pci_dev *dev = NULL; | 152 | struct pci_dev *dev = NULL; |
151 | int retval = 0; | 153 | int lastslot = 0; |
152 | 154 | ||
153 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 155 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { |
154 | retval = add_slot(dev); | 156 | if (PCI_FUNC(dev->devfn) > 0 && |
155 | if (retval) { | 157 | lastslot == PCI_SLOT(dev->devfn)) |
156 | pci_dev_put(dev); | 158 | continue; |
157 | break; | 159 | lastslot = PCI_SLOT(dev->devfn); |
158 | } | 160 | add_slot(dev); |
159 | } | 161 | } |
160 | 162 | ||
161 | return retval; | 163 | return 0; |
162 | } | 164 | } |
163 | 165 | ||
164 | static void remove_slot(struct dummy_slot *dslot) | 166 | static void remove_slot(struct dummy_slot *dslot) |
@@ -296,23 +298,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) | |||
296 | return 0; | 298 | return 0; |
297 | } | 299 | } |
298 | 300 | ||
299 | /* find the hotplug_slot for the pci_dev */ | ||
300 | static struct hotplug_slot *get_slot_from_dev(struct pci_dev *dev) | ||
301 | { | ||
302 | struct dummy_slot *dslot; | ||
303 | |||
304 | list_for_each_entry(dslot, &slot_list, node) { | ||
305 | if (dslot->dev == dev) | ||
306 | return dslot->slot; | ||
307 | } | ||
308 | return NULL; | ||
309 | } | ||
310 | |||
311 | |||
312 | static int disable_slot(struct hotplug_slot *slot) | 301 | static int disable_slot(struct hotplug_slot *slot) |
313 | { | 302 | { |
314 | struct dummy_slot *dslot; | 303 | struct dummy_slot *dslot; |
315 | struct hotplug_slot *hslot; | ||
316 | struct pci_dev *dev; | 304 | struct pci_dev *dev; |
317 | int func; | 305 | int func; |
318 | 306 | ||
@@ -322,41 +310,27 @@ static int disable_slot(struct hotplug_slot *slot) | |||
322 | 310 | ||
323 | dbg("%s - physical_slot = %s\n", __func__, slot->name); | 311 | dbg("%s - physical_slot = %s\n", __func__, slot->name); |
324 | 312 | ||
325 | /* don't disable bridged devices just yet, we can't handle them easily... */ | 313 | for (func = 7; func >= 0; func--) { |
326 | if (dslot->dev->subordinate) { | 314 | dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func); |
327 | err("Can't remove PCI devices with other PCI devices behind it yet.\n"); | 315 | if (!dev) |
328 | return -ENODEV; | 316 | continue; |
329 | } | 317 | |
330 | if (test_and_set_bit(0, &dslot->removed)) { | 318 | if (test_and_set_bit(0, &dslot->removed)) { |
331 | dbg("Slot already scheduled for removal\n"); | 319 | dbg("Slot already scheduled for removal\n"); |
332 | return -ENODEV; | 320 | return -ENODEV; |
333 | } | ||
334 | /* search for subfunctions and disable them first */ | ||
335 | if (!(dslot->dev->devfn & 7)) { | ||
336 | for (func = 1; func < 8; func++) { | ||
337 | dev = pci_get_slot(dslot->dev->bus, | ||
338 | dslot->dev->devfn + func); | ||
339 | if (dev) { | ||
340 | hslot = get_slot_from_dev(dev); | ||
341 | if (hslot) | ||
342 | disable_slot(hslot); | ||
343 | else { | ||
344 | err("Hotplug slot not found for subfunction of PCI device\n"); | ||
345 | return -ENODEV; | ||
346 | } | ||
347 | pci_dev_put(dev); | ||
348 | } else | ||
349 | dbg("No device in slot found\n"); | ||
350 | } | 321 | } |
351 | } | ||
352 | 322 | ||
353 | /* remove the device from the pci core */ | 323 | /* queue work item to blow away this sysfs entry and other |
354 | pci_remove_bus_device(dslot->dev); | 324 | * parts. |
325 | */ | ||
326 | INIT_WORK(&dslot->remove_work, remove_slot_worker); | ||
327 | queue_work(dummyphp_wq, &dslot->remove_work); | ||
355 | 328 | ||
356 | /* queue work item to blow away this sysfs entry and other parts. */ | 329 | /* blow away this sysfs entry and other parts. */ |
357 | INIT_WORK(&dslot->remove_work, remove_slot_worker); | 330 | remove_slot(dslot); |
358 | queue_work(dummyphp_wq, &dslot->remove_work); | ||
359 | 331 | ||
332 | pci_dev_put(dev); | ||
333 | } | ||
360 | return 0; | 334 | return 0; |
361 | } | 335 | } |
362 | 336 | ||
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index dca7efc14be2..8467d0287325 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c | |||
@@ -1001,7 +1001,8 @@ static int __init ebda_rsrc_controller (void) | |||
1001 | tmp_slot = list_entry (list, struct slot, ibm_slot_list); | 1001 | tmp_slot = list_entry (list, struct slot, ibm_slot_list); |
1002 | 1002 | ||
1003 | snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); | 1003 | snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); |
1004 | pci_hp_register (tmp_slot->hotplug_slot); | 1004 | pci_hp_register(tmp_slot->hotplug_slot, |
1005 | pci_find_bus(0, tmp_slot->bus), tmp_slot->device); | ||
1005 | } | 1006 | } |
1006 | 1007 | ||
1007 | print_ebda_hpc (); | 1008 | print_ebda_hpc (); |
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index a11021e8ce37..5f85b1b120e3 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/pci.h> | 40 | #include <linux/pci.h> |
41 | #include <linux/pci_hotplug.h> | 41 | #include <linux/pci_hotplug.h> |
42 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
43 | #include "../pci.h" | ||
43 | 44 | ||
44 | #define MY_NAME "pci_hotplug" | 45 | #define MY_NAME "pci_hotplug" |
45 | 46 | ||
@@ -60,41 +61,7 @@ static int debug; | |||
60 | ////////////////////////////////////////////////////////////////// | 61 | ////////////////////////////////////////////////////////////////// |
61 | 62 | ||
62 | static LIST_HEAD(pci_hotplug_slot_list); | 63 | static LIST_HEAD(pci_hotplug_slot_list); |
63 | 64 | static DEFINE_SPINLOCK(pci_hotplug_slot_list_lock); | |
64 | struct kset *pci_hotplug_slots_kset; | ||
65 | |||
66 | static ssize_t hotplug_slot_attr_show(struct kobject *kobj, | ||
67 | struct attribute *attr, char *buf) | ||
68 | { | ||
69 | struct hotplug_slot *slot = to_hotplug_slot(kobj); | ||
70 | struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); | ||
71 | return attribute->show ? attribute->show(slot, buf) : -EIO; | ||
72 | } | ||
73 | |||
74 | static ssize_t hotplug_slot_attr_store(struct kobject *kobj, | ||
75 | struct attribute *attr, const char *buf, size_t len) | ||
76 | { | ||
77 | struct hotplug_slot *slot = to_hotplug_slot(kobj); | ||
78 | struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); | ||
79 | return attribute->store ? attribute->store(slot, buf, len) : -EIO; | ||
80 | } | ||
81 | |||
82 | static struct sysfs_ops hotplug_slot_sysfs_ops = { | ||
83 | .show = hotplug_slot_attr_show, | ||
84 | .store = hotplug_slot_attr_store, | ||
85 | }; | ||
86 | |||
87 | static void hotplug_slot_release(struct kobject *kobj) | ||
88 | { | ||
89 | struct hotplug_slot *slot = to_hotplug_slot(kobj); | ||
90 | if (slot->release) | ||
91 | slot->release(slot); | ||
92 | } | ||
93 | |||
94 | static struct kobj_type hotplug_slot_ktype = { | ||
95 | .sysfs_ops = &hotplug_slot_sysfs_ops, | ||
96 | .release = &hotplug_slot_release, | ||
97 | }; | ||
98 | 65 | ||
99 | /* these strings match up with the values in pci_bus_speed */ | 66 | /* these strings match up with the values in pci_bus_speed */ |
100 | static char *pci_bus_speed_strings[] = { | 67 | static char *pci_bus_speed_strings[] = { |
@@ -149,16 +116,15 @@ GET_STATUS(power_status, u8) | |||
149 | GET_STATUS(attention_status, u8) | 116 | GET_STATUS(attention_status, u8) |
150 | GET_STATUS(latch_status, u8) | 117 | GET_STATUS(latch_status, u8) |
151 | GET_STATUS(adapter_status, u8) | 118 | GET_STATUS(adapter_status, u8) |
152 | GET_STATUS(address, u32) | ||
153 | GET_STATUS(max_bus_speed, enum pci_bus_speed) | 119 | GET_STATUS(max_bus_speed, enum pci_bus_speed) |
154 | GET_STATUS(cur_bus_speed, enum pci_bus_speed) | 120 | GET_STATUS(cur_bus_speed, enum pci_bus_speed) |
155 | 121 | ||
156 | static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) | 122 | static ssize_t power_read_file(struct pci_slot *slot, char *buf) |
157 | { | 123 | { |
158 | int retval; | 124 | int retval; |
159 | u8 value; | 125 | u8 value; |
160 | 126 | ||
161 | retval = get_power_status (slot, &value); | 127 | retval = get_power_status(slot->hotplug, &value); |
162 | if (retval) | 128 | if (retval) |
163 | goto exit; | 129 | goto exit; |
164 | retval = sprintf (buf, "%d\n", value); | 130 | retval = sprintf (buf, "%d\n", value); |
@@ -166,9 +132,10 @@ exit: | |||
166 | return retval; | 132 | return retval; |
167 | } | 133 | } |
168 | 134 | ||
169 | static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, | 135 | static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf, |
170 | size_t count) | 136 | size_t count) |
171 | { | 137 | { |
138 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
172 | unsigned long lpower; | 139 | unsigned long lpower; |
173 | u8 power; | 140 | u8 power; |
174 | int retval = 0; | 141 | int retval = 0; |
@@ -204,29 +171,30 @@ exit: | |||
204 | return count; | 171 | return count; |
205 | } | 172 | } |
206 | 173 | ||
207 | static struct hotplug_slot_attribute hotplug_slot_attr_power = { | 174 | static struct pci_slot_attribute hotplug_slot_attr_power = { |
208 | .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, | 175 | .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, |
209 | .show = power_read_file, | 176 | .show = power_read_file, |
210 | .store = power_write_file | 177 | .store = power_write_file |
211 | }; | 178 | }; |
212 | 179 | ||
213 | static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) | 180 | static ssize_t attention_read_file(struct pci_slot *slot, char *buf) |
214 | { | 181 | { |
215 | int retval; | 182 | int retval; |
216 | u8 value; | 183 | u8 value; |
217 | 184 | ||
218 | retval = get_attention_status (slot, &value); | 185 | retval = get_attention_status(slot->hotplug, &value); |
219 | if (retval) | 186 | if (retval) |
220 | goto exit; | 187 | goto exit; |
221 | retval = sprintf (buf, "%d\n", value); | 188 | retval = sprintf(buf, "%d\n", value); |
222 | 189 | ||
223 | exit: | 190 | exit: |
224 | return retval; | 191 | return retval; |
225 | } | 192 | } |
226 | 193 | ||
227 | static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, | 194 | static ssize_t attention_write_file(struct pci_slot *slot, const char *buf, |
228 | size_t count) | 195 | size_t count) |
229 | { | 196 | { |
197 | struct hotplug_slot_ops *ops = slot->hotplug->ops; | ||
230 | unsigned long lattention; | 198 | unsigned long lattention; |
231 | u8 attention; | 199 | u8 attention; |
232 | int retval = 0; | 200 | int retval = 0; |
@@ -235,13 +203,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, | |||
235 | attention = (u8)(lattention & 0xff); | 203 | attention = (u8)(lattention & 0xff); |
236 | dbg (" - attention = %d\n", attention); | 204 | dbg (" - attention = %d\n", attention); |
237 | 205 | ||
238 | if (!try_module_get(slot->ops->owner)) { | 206 | if (!try_module_get(ops->owner)) { |
239 | retval = -ENODEV; | 207 | retval = -ENODEV; |
240 | goto exit; | 208 | goto exit; |
241 | } | 209 | } |
242 | if (slot->ops->set_attention_status) | 210 | if (ops->set_attention_status) |
243 | retval = slot->ops->set_attention_status(slot, attention); | 211 | retval = ops->set_attention_status(slot->hotplug, attention); |
244 | module_put(slot->ops->owner); | 212 | module_put(ops->owner); |
245 | 213 | ||
246 | exit: | 214 | exit: |
247 | if (retval) | 215 | if (retval) |
@@ -249,18 +217,18 @@ exit: | |||
249 | return count; | 217 | return count; |
250 | } | 218 | } |
251 | 219 | ||
252 | static struct hotplug_slot_attribute hotplug_slot_attr_attention = { | 220 | static struct pci_slot_attribute hotplug_slot_attr_attention = { |
253 | .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, | 221 | .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, |
254 | .show = attention_read_file, | 222 | .show = attention_read_file, |
255 | .store = attention_write_file | 223 | .store = attention_write_file |
256 | }; | 224 | }; |
257 | 225 | ||
258 | static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) | 226 | static ssize_t latch_read_file(struct pci_slot *slot, char *buf) |
259 | { | 227 | { |
260 | int retval; | 228 | int retval; |
261 | u8 value; | 229 | u8 value; |
262 | 230 | ||
263 | retval = get_latch_status (slot, &value); | 231 | retval = get_latch_status(slot->hotplug, &value); |
264 | if (retval) | 232 | if (retval) |
265 | goto exit; | 233 | goto exit; |
266 | retval = sprintf (buf, "%d\n", value); | 234 | retval = sprintf (buf, "%d\n", value); |
@@ -269,17 +237,17 @@ exit: | |||
269 | return retval; | 237 | return retval; |
270 | } | 238 | } |
271 | 239 | ||
272 | static struct hotplug_slot_attribute hotplug_slot_attr_latch = { | 240 | static struct pci_slot_attribute hotplug_slot_attr_latch = { |
273 | .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO}, | 241 | .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO}, |
274 | .show = latch_read_file, | 242 | .show = latch_read_file, |
275 | }; | 243 | }; |
276 | 244 | ||
277 | static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) | 245 | static ssize_t presence_read_file(struct pci_slot *slot, char *buf) |
278 | { | 246 | { |
279 | int retval; | 247 | int retval; |
280 | u8 value; | 248 | u8 value; |
281 | 249 | ||
282 | retval = get_adapter_status (slot, &value); | 250 | retval = get_adapter_status(slot->hotplug, &value); |
283 | if (retval) | 251 | if (retval) |
284 | goto exit; | 252 | goto exit; |
285 | retval = sprintf (buf, "%d\n", value); | 253 | retval = sprintf (buf, "%d\n", value); |
@@ -288,42 +256,20 @@ exit: | |||
288 | return retval; | 256 | return retval; |
289 | } | 257 | } |
290 | 258 | ||
291 | static struct hotplug_slot_attribute hotplug_slot_attr_presence = { | 259 | static struct pci_slot_attribute hotplug_slot_attr_presence = { |
292 | .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO}, | 260 | .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO}, |
293 | .show = presence_read_file, | 261 | .show = presence_read_file, |
294 | }; | 262 | }; |
295 | 263 | ||
296 | static ssize_t address_read_file (struct hotplug_slot *slot, char *buf) | ||
297 | { | ||
298 | int retval; | ||
299 | u32 address; | ||
300 | |||
301 | retval = get_address (slot, &address); | ||
302 | if (retval) | ||
303 | goto exit; | ||
304 | retval = sprintf (buf, "%04x:%02x:%02x\n", | ||
305 | (address >> 16) & 0xffff, | ||
306 | (address >> 8) & 0xff, | ||
307 | address & 0xff); | ||
308 | |||
309 | exit: | ||
310 | return retval; | ||
311 | } | ||
312 | |||
313 | static struct hotplug_slot_attribute hotplug_slot_attr_address = { | ||
314 | .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, | ||
315 | .show = address_read_file, | ||
316 | }; | ||
317 | |||
318 | static char *unknown_speed = "Unknown bus speed"; | 264 | static char *unknown_speed = "Unknown bus speed"; |
319 | 265 | ||
320 | static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) | 266 | static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf) |
321 | { | 267 | { |
322 | char *speed_string; | 268 | char *speed_string; |
323 | int retval; | 269 | int retval; |
324 | enum pci_bus_speed value; | 270 | enum pci_bus_speed value; |
325 | 271 | ||
326 | retval = get_max_bus_speed (slot, &value); | 272 | retval = get_max_bus_speed(slot->hotplug, &value); |
327 | if (retval) | 273 | if (retval) |
328 | goto exit; | 274 | goto exit; |
329 | 275 | ||
@@ -338,18 +284,18 @@ exit: | |||
338 | return retval; | 284 | return retval; |
339 | } | 285 | } |
340 | 286 | ||
341 | static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { | 287 | static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = { |
342 | .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO}, | 288 | .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO}, |
343 | .show = max_bus_speed_read_file, | 289 | .show = max_bus_speed_read_file, |
344 | }; | 290 | }; |
345 | 291 | ||
346 | static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) | 292 | static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf) |
347 | { | 293 | { |
348 | char *speed_string; | 294 | char *speed_string; |
349 | int retval; | 295 | int retval; |
350 | enum pci_bus_speed value; | 296 | enum pci_bus_speed value; |
351 | 297 | ||
352 | retval = get_cur_bus_speed (slot, &value); | 298 | retval = get_cur_bus_speed(slot->hotplug, &value); |
353 | if (retval) | 299 | if (retval) |
354 | goto exit; | 300 | goto exit; |
355 | 301 | ||
@@ -364,14 +310,15 @@ exit: | |||
364 | return retval; | 310 | return retval; |
365 | } | 311 | } |
366 | 312 | ||
367 | static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { | 313 | static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = { |
368 | .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO}, | 314 | .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO}, |
369 | .show = cur_bus_speed_read_file, | 315 | .show = cur_bus_speed_read_file, |
370 | }; | 316 | }; |
371 | 317 | ||
372 | static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, | 318 | static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf, |
373 | size_t count) | 319 | size_t count) |
374 | { | 320 | { |
321 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
375 | unsigned long ltest; | 322 | unsigned long ltest; |
376 | u32 test; | 323 | u32 test; |
377 | int retval = 0; | 324 | int retval = 0; |
@@ -394,13 +341,14 @@ exit: | |||
394 | return count; | 341 | return count; |
395 | } | 342 | } |
396 | 343 | ||
397 | static struct hotplug_slot_attribute hotplug_slot_attr_test = { | 344 | static struct pci_slot_attribute hotplug_slot_attr_test = { |
398 | .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, | 345 | .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, |
399 | .store = test_write_file | 346 | .store = test_write_file |
400 | }; | 347 | }; |
401 | 348 | ||
402 | static int has_power_file (struct hotplug_slot *slot) | 349 | static int has_power_file(struct pci_slot *pci_slot) |
403 | { | 350 | { |
351 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
404 | if ((!slot) || (!slot->ops)) | 352 | if ((!slot) || (!slot->ops)) |
405 | return -ENODEV; | 353 | return -ENODEV; |
406 | if ((slot->ops->enable_slot) || | 354 | if ((slot->ops->enable_slot) || |
@@ -410,8 +358,9 @@ static int has_power_file (struct hotplug_slot *slot) | |||
410 | return -ENOENT; | 358 | return -ENOENT; |
411 | } | 359 | } |
412 | 360 | ||
413 | static int has_attention_file (struct hotplug_slot *slot) | 361 | static int has_attention_file(struct pci_slot *pci_slot) |
414 | { | 362 | { |
363 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
415 | if ((!slot) || (!slot->ops)) | 364 | if ((!slot) || (!slot->ops)) |
416 | return -ENODEV; | 365 | return -ENODEV; |
417 | if ((slot->ops->set_attention_status) || | 366 | if ((slot->ops->set_attention_status) || |
@@ -420,8 +369,9 @@ static int has_attention_file (struct hotplug_slot *slot) | |||
420 | return -ENOENT; | 369 | return -ENOENT; |
421 | } | 370 | } |
422 | 371 | ||
423 | static int has_latch_file (struct hotplug_slot *slot) | 372 | static int has_latch_file(struct pci_slot *pci_slot) |
424 | { | 373 | { |
374 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
425 | if ((!slot) || (!slot->ops)) | 375 | if ((!slot) || (!slot->ops)) |
426 | return -ENODEV; | 376 | return -ENODEV; |
427 | if (slot->ops->get_latch_status) | 377 | if (slot->ops->get_latch_status) |
@@ -429,8 +379,9 @@ static int has_latch_file (struct hotplug_slot *slot) | |||
429 | return -ENOENT; | 379 | return -ENOENT; |
430 | } | 380 | } |
431 | 381 | ||
432 | static int has_adapter_file (struct hotplug_slot *slot) | 382 | static int has_adapter_file(struct pci_slot *pci_slot) |
433 | { | 383 | { |
384 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
434 | if ((!slot) || (!slot->ops)) | 385 | if ((!slot) || (!slot->ops)) |
435 | return -ENODEV; | 386 | return -ENODEV; |
436 | if (slot->ops->get_adapter_status) | 387 | if (slot->ops->get_adapter_status) |
@@ -438,17 +389,9 @@ static int has_adapter_file (struct hotplug_slot *slot) | |||
438 | return -ENOENT; | 389 | return -ENOENT; |
439 | } | 390 | } |
440 | 391 | ||
441 | static int has_address_file (struct hotplug_slot *slot) | 392 | static int has_max_bus_speed_file(struct pci_slot *pci_slot) |
442 | { | ||
443 | if ((!slot) || (!slot->ops)) | ||
444 | return -ENODEV; | ||
445 | if (slot->ops->get_address) | ||
446 | return 0; | ||
447 | return -ENOENT; | ||
448 | } | ||
449 | |||
450 | static int has_max_bus_speed_file (struct hotplug_slot *slot) | ||
451 | { | 393 | { |
394 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
452 | if ((!slot) || (!slot->ops)) | 395 | if ((!slot) || (!slot->ops)) |
453 | return -ENODEV; | 396 | return -ENODEV; |
454 | if (slot->ops->get_max_bus_speed) | 397 | if (slot->ops->get_max_bus_speed) |
@@ -456,8 +399,9 @@ static int has_max_bus_speed_file (struct hotplug_slot *slot) | |||
456 | return -ENOENT; | 399 | return -ENOENT; |
457 | } | 400 | } |
458 | 401 | ||
459 | static int has_cur_bus_speed_file (struct hotplug_slot *slot) | 402 | static int has_cur_bus_speed_file(struct pci_slot *pci_slot) |
460 | { | 403 | { |
404 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
461 | if ((!slot) || (!slot->ops)) | 405 | if ((!slot) || (!slot->ops)) |
462 | return -ENODEV; | 406 | return -ENODEV; |
463 | if (slot->ops->get_cur_bus_speed) | 407 | if (slot->ops->get_cur_bus_speed) |
@@ -465,8 +409,9 @@ static int has_cur_bus_speed_file (struct hotplug_slot *slot) | |||
465 | return -ENOENT; | 409 | return -ENOENT; |
466 | } | 410 | } |
467 | 411 | ||
468 | static int has_test_file (struct hotplug_slot *slot) | 412 | static int has_test_file(struct pci_slot *pci_slot) |
469 | { | 413 | { |
414 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
470 | if ((!slot) || (!slot->ops)) | 415 | if ((!slot) || (!slot->ops)) |
471 | return -ENODEV; | 416 | return -ENODEV; |
472 | if (slot->ops->hardware_test) | 417 | if (slot->ops->hardware_test) |
@@ -474,7 +419,7 @@ static int has_test_file (struct hotplug_slot *slot) | |||
474 | return -ENOENT; | 419 | return -ENOENT; |
475 | } | 420 | } |
476 | 421 | ||
477 | static int fs_add_slot (struct hotplug_slot *slot) | 422 | static int fs_add_slot(struct pci_slot *slot) |
478 | { | 423 | { |
479 | int retval = 0; | 424 | int retval = 0; |
480 | 425 | ||
@@ -505,13 +450,6 @@ static int fs_add_slot (struct hotplug_slot *slot) | |||
505 | goto exit_adapter; | 450 | goto exit_adapter; |
506 | } | 451 | } |
507 | 452 | ||
508 | if (has_address_file(slot) == 0) { | ||
509 | retval = sysfs_create_file(&slot->kobj, | ||
510 | &hotplug_slot_attr_address.attr); | ||
511 | if (retval) | ||
512 | goto exit_address; | ||
513 | } | ||
514 | |||
515 | if (has_max_bus_speed_file(slot) == 0) { | 453 | if (has_max_bus_speed_file(slot) == 0) { |
516 | retval = sysfs_create_file(&slot->kobj, | 454 | retval = sysfs_create_file(&slot->kobj, |
517 | &hotplug_slot_attr_max_bus_speed.attr); | 455 | &hotplug_slot_attr_max_bus_speed.attr); |
@@ -544,10 +482,6 @@ exit_cur_speed: | |||
544 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); | 482 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); |
545 | 483 | ||
546 | exit_max_speed: | 484 | exit_max_speed: |
547 | if (has_address_file(slot) == 0) | ||
548 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr); | ||
549 | |||
550 | exit_address: | ||
551 | if (has_adapter_file(slot) == 0) | 485 | if (has_adapter_file(slot) == 0) |
552 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); | 486 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); |
553 | 487 | ||
@@ -567,7 +501,7 @@ exit: | |||
567 | return retval; | 501 | return retval; |
568 | } | 502 | } |
569 | 503 | ||
570 | static void fs_remove_slot (struct hotplug_slot *slot) | 504 | static void fs_remove_slot(struct pci_slot *slot) |
571 | { | 505 | { |
572 | if (has_power_file(slot) == 0) | 506 | if (has_power_file(slot) == 0) |
573 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); | 507 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); |
@@ -581,9 +515,6 @@ static void fs_remove_slot (struct hotplug_slot *slot) | |||
581 | if (has_adapter_file(slot) == 0) | 515 | if (has_adapter_file(slot) == 0) |
582 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); | 516 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); |
583 | 517 | ||
584 | if (has_address_file(slot) == 0) | ||
585 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr); | ||
586 | |||
587 | if (has_max_bus_speed_file(slot) == 0) | 518 | if (has_max_bus_speed_file(slot) == 0) |
588 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); | 519 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); |
589 | 520 | ||
@@ -599,27 +530,33 @@ static struct hotplug_slot *get_slot_from_name (const char *name) | |||
599 | struct hotplug_slot *slot; | 530 | struct hotplug_slot *slot; |
600 | struct list_head *tmp; | 531 | struct list_head *tmp; |
601 | 532 | ||
533 | spin_lock(&pci_hotplug_slot_list_lock); | ||
602 | list_for_each (tmp, &pci_hotplug_slot_list) { | 534 | list_for_each (tmp, &pci_hotplug_slot_list) { |
603 | slot = list_entry (tmp, struct hotplug_slot, slot_list); | 535 | slot = list_entry (tmp, struct hotplug_slot, slot_list); |
604 | if (strcmp(slot->name, name) == 0) | 536 | if (strcmp(slot->name, name) == 0) |
605 | return slot; | 537 | goto out; |
606 | } | 538 | } |
607 | return NULL; | 539 | slot = NULL; |
540 | out: | ||
541 | spin_unlock(&pci_hotplug_slot_list_lock); | ||
542 | return slot; | ||
608 | } | 543 | } |
609 | 544 | ||
610 | /** | 545 | /** |
611 | * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem | 546 | * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem |
547 | * @bus: bus this slot is on | ||
612 | * @slot: pointer to the &struct hotplug_slot to register | 548 | * @slot: pointer to the &struct hotplug_slot to register |
549 | * @slot_nr: slot number | ||
613 | * | 550 | * |
614 | * Registers a hotplug slot with the pci hotplug subsystem, which will allow | 551 | * Registers a hotplug slot with the pci hotplug subsystem, which will allow |
615 | * userspace interaction to the slot. | 552 | * userspace interaction to the slot. |
616 | * | 553 | * |
617 | * Returns 0 if successful, anything else for an error. | 554 | * Returns 0 if successful, anything else for an error. |
618 | */ | 555 | */ |
619 | int pci_hp_register (struct hotplug_slot *slot) | 556 | int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr) |
620 | { | 557 | { |
621 | int result; | 558 | int result; |
622 | struct hotplug_slot *tmp; | 559 | struct pci_slot *pci_slot; |
623 | 560 | ||
624 | if (slot == NULL) | 561 | if (slot == NULL) |
625 | return -ENODEV; | 562 | return -ENODEV; |
@@ -632,57 +569,89 @@ int pci_hp_register (struct hotplug_slot *slot) | |||
632 | } | 569 | } |
633 | 570 | ||
634 | /* Check if we have already registered a slot with the same name. */ | 571 | /* Check if we have already registered a slot with the same name. */ |
635 | tmp = get_slot_from_name(slot->name); | 572 | if (get_slot_from_name(slot->name)) |
636 | if (tmp) | ||
637 | return -EEXIST; | 573 | return -EEXIST; |
638 | 574 | ||
639 | slot->kobj.kset = pci_hotplug_slots_kset; | 575 | /* |
640 | result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, | 576 | * No problems if we call this interface from both ACPI_PCI_SLOT |
641 | "%s", slot->name); | 577 | * driver and call it here again. If we've already created the |
642 | if (result) { | 578 | * pci_slot, the interface will simply bump the refcount. |
643 | err("Unable to register kobject '%s'", slot->name); | 579 | */ |
644 | return -EINVAL; | 580 | pci_slot = pci_create_slot(bus, slot_nr, slot->name); |
581 | if (IS_ERR(pci_slot)) | ||
582 | return PTR_ERR(pci_slot); | ||
583 | |||
584 | if (pci_slot->hotplug) { | ||
585 | dbg("%s: already claimed\n", __func__); | ||
586 | pci_destroy_slot(pci_slot); | ||
587 | return -EBUSY; | ||
645 | } | 588 | } |
646 | 589 | ||
647 | list_add (&slot->slot_list, &pci_hotplug_slot_list); | 590 | slot->pci_slot = pci_slot; |
591 | pci_slot->hotplug = slot; | ||
592 | |||
593 | /* | ||
594 | * Allow pcihp drivers to override the ACPI_PCI_SLOT name. | ||
595 | */ | ||
596 | if (strcmp(kobject_name(&pci_slot->kobj), slot->name)) { | ||
597 | result = kobject_rename(&pci_slot->kobj, slot->name); | ||
598 | if (result) { | ||
599 | pci_destroy_slot(pci_slot); | ||
600 | return result; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | spin_lock(&pci_hotplug_slot_list_lock); | ||
605 | list_add(&slot->slot_list, &pci_hotplug_slot_list); | ||
606 | spin_unlock(&pci_hotplug_slot_list_lock); | ||
607 | |||
608 | result = fs_add_slot(pci_slot); | ||
609 | kobject_uevent(&pci_slot->kobj, KOBJ_ADD); | ||
610 | dbg("Added slot %s to the list\n", slot->name); | ||
611 | |||
648 | 612 | ||
649 | result = fs_add_slot (slot); | ||
650 | kobject_uevent(&slot->kobj, KOBJ_ADD); | ||
651 | dbg ("Added slot %s to the list\n", slot->name); | ||
652 | return result; | 613 | return result; |
653 | } | 614 | } |
654 | 615 | ||
655 | /** | 616 | /** |
656 | * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem | 617 | * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem |
657 | * @slot: pointer to the &struct hotplug_slot to deregister | 618 | * @hotplug: pointer to the &struct hotplug_slot to deregister |
658 | * | 619 | * |
659 | * The @slot must have been registered with the pci hotplug subsystem | 620 | * The @slot must have been registered with the pci hotplug subsystem |
660 | * previously with a call to pci_hp_register(). | 621 | * previously with a call to pci_hp_register(). |
661 | * | 622 | * |
662 | * Returns 0 if successful, anything else for an error. | 623 | * Returns 0 if successful, anything else for an error. |
663 | */ | 624 | */ |
664 | int pci_hp_deregister (struct hotplug_slot *slot) | 625 | int pci_hp_deregister(struct hotplug_slot *hotplug) |
665 | { | 626 | { |
666 | struct hotplug_slot *temp; | 627 | struct hotplug_slot *temp; |
628 | struct pci_slot *slot; | ||
667 | 629 | ||
668 | if (slot == NULL) | 630 | if (!hotplug) |
669 | return -ENODEV; | 631 | return -ENODEV; |
670 | 632 | ||
671 | temp = get_slot_from_name (slot->name); | 633 | temp = get_slot_from_name(hotplug->name); |
672 | if (temp != slot) { | 634 | if (temp != hotplug) |
673 | return -ENODEV; | 635 | return -ENODEV; |
674 | } | ||
675 | list_del (&slot->slot_list); | ||
676 | 636 | ||
677 | fs_remove_slot (slot); | 637 | spin_lock(&pci_hotplug_slot_list_lock); |
678 | dbg ("Removed slot %s from the list\n", slot->name); | 638 | list_del(&hotplug->slot_list); |
679 | kobject_put(&slot->kobj); | 639 | spin_unlock(&pci_hotplug_slot_list_lock); |
640 | |||
641 | slot = hotplug->pci_slot; | ||
642 | fs_remove_slot(slot); | ||
643 | dbg("Removed slot %s from the list\n", hotplug->name); | ||
644 | |||
645 | hotplug->release(hotplug); | ||
646 | slot->hotplug = NULL; | ||
647 | pci_destroy_slot(slot); | ||
648 | |||
680 | return 0; | 649 | return 0; |
681 | } | 650 | } |
682 | 651 | ||
683 | /** | 652 | /** |
684 | * pci_hp_change_slot_info - changes the slot's information structure in the core | 653 | * pci_hp_change_slot_info - changes the slot's information structure in the core |
685 | * @slot: pointer to the slot whose info has changed | 654 | * @hotplug: pointer to the slot whose info has changed |
686 | * @info: pointer to the info copy into the slot's info structure | 655 | * @info: pointer to the info copy into the slot's info structure |
687 | * | 656 | * |
688 | * @slot must have been registered with the pci | 657 | * @slot must have been registered with the pci |
@@ -690,13 +659,15 @@ int pci_hp_deregister (struct hotplug_slot *slot) | |||
690 | * | 659 | * |
691 | * Returns 0 if successful, anything else for an error. | 660 | * Returns 0 if successful, anything else for an error. |
692 | */ | 661 | */ |
693 | int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, | 662 | int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug, |
694 | struct hotplug_slot_info *info) | 663 | struct hotplug_slot_info *info) |
695 | { | 664 | { |
696 | if ((slot == NULL) || (info == NULL)) | 665 | struct pci_slot *slot; |
666 | if (!hotplug || !info) | ||
697 | return -ENODEV; | 667 | return -ENODEV; |
668 | slot = hotplug->pci_slot; | ||
698 | 669 | ||
699 | memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); | 670 | memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info)); |
700 | 671 | ||
701 | return 0; | 672 | return 0; |
702 | } | 673 | } |
@@ -704,36 +675,22 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, | |||
704 | static int __init pci_hotplug_init (void) | 675 | static int __init pci_hotplug_init (void) |
705 | { | 676 | { |
706 | int result; | 677 | int result; |
707 | struct kset *pci_bus_kset; | ||
708 | 678 | ||
709 | pci_bus_kset = bus_get_kset(&pci_bus_type); | ||
710 | |||
711 | pci_hotplug_slots_kset = kset_create_and_add("slots", NULL, | ||
712 | &pci_bus_kset->kobj); | ||
713 | if (!pci_hotplug_slots_kset) { | ||
714 | result = -ENOMEM; | ||
715 | err("Register subsys error\n"); | ||
716 | goto exit; | ||
717 | } | ||
718 | result = cpci_hotplug_init(debug); | 679 | result = cpci_hotplug_init(debug); |
719 | if (result) { | 680 | if (result) { |
720 | err ("cpci_hotplug_init with error %d\n", result); | 681 | err ("cpci_hotplug_init with error %d\n", result); |
721 | goto err_subsys; | 682 | goto err_cpci; |
722 | } | 683 | } |
723 | 684 | ||
724 | info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 685 | info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
725 | goto exit; | ||
726 | 686 | ||
727 | err_subsys: | 687 | err_cpci: |
728 | kset_unregister(pci_hotplug_slots_kset); | ||
729 | exit: | ||
730 | return result; | 688 | return result; |
731 | } | 689 | } |
732 | 690 | ||
733 | static void __exit pci_hotplug_exit (void) | 691 | static void __exit pci_hotplug_exit (void) |
734 | { | 692 | { |
735 | cpci_hotplug_exit(); | 693 | cpci_hotplug_exit(); |
736 | kset_unregister(pci_hotplug_slots_kset); | ||
737 | } | 694 | } |
738 | 695 | ||
739 | module_init(pci_hotplug_init); | 696 | module_init(pci_hotplug_init); |
@@ -745,7 +702,6 @@ MODULE_LICENSE("GPL"); | |||
745 | module_param(debug, bool, 0644); | 702 | module_param(debug, bool, 0644); |
746 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); | 703 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); |
747 | 704 | ||
748 | EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset); | ||
749 | EXPORT_SYMBOL_GPL(pci_hp_register); | 705 | EXPORT_SYMBOL_GPL(pci_hp_register); |
750 | EXPORT_SYMBOL_GPL(pci_hp_deregister); | 706 | EXPORT_SYMBOL_GPL(pci_hp_deregister); |
751 | EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); | 707 | EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); |
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 79c9ddaad3fb..e3a1e7e7dba2 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -43,6 +43,7 @@ extern int pciehp_poll_mode; | |||
43 | extern int pciehp_poll_time; | 43 | extern int pciehp_poll_time; |
44 | extern int pciehp_debug; | 44 | extern int pciehp_debug; |
45 | extern int pciehp_force; | 45 | extern int pciehp_force; |
46 | extern int pciehp_slot_with_bus; | ||
46 | extern struct workqueue_struct *pciehp_wq; | 47 | extern struct workqueue_struct *pciehp_wq; |
47 | 48 | ||
48 | #define dbg(format, arg...) \ | 49 | #define dbg(format, arg...) \ |
@@ -96,7 +97,7 @@ struct controller { | |||
96 | u32 slot_cap; | 97 | u32 slot_cap; |
97 | u8 cap_base; | 98 | u8 cap_base; |
98 | struct timer_list poll_timer; | 99 | struct timer_list poll_timer; |
99 | volatile int cmd_busy; | 100 | int cmd_busy; |
100 | unsigned int no_cmd_complete:1; | 101 | unsigned int no_cmd_complete:1; |
101 | }; | 102 | }; |
102 | 103 | ||
@@ -156,10 +157,10 @@ extern u8 pciehp_handle_power_fault(struct slot *p_slot); | |||
156 | extern int pciehp_configure_device(struct slot *p_slot); | 157 | extern int pciehp_configure_device(struct slot *p_slot); |
157 | extern int pciehp_unconfigure_device(struct slot *p_slot); | 158 | extern int pciehp_unconfigure_device(struct slot *p_slot); |
158 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); | 159 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); |
159 | int pcie_init(struct controller *ctrl, struct pcie_device *dev); | 160 | struct controller *pcie_init(struct pcie_device *dev); |
160 | int pciehp_enable_slot(struct slot *p_slot); | 161 | int pciehp_enable_slot(struct slot *p_slot); |
161 | int pciehp_disable_slot(struct slot *p_slot); | 162 | int pciehp_disable_slot(struct slot *p_slot); |
162 | int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev); | 163 | int pcie_enable_notification(struct controller *ctrl); |
163 | 164 | ||
164 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) | 165 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) |
165 | { | 166 | { |
@@ -202,8 +203,13 @@ struct hpc_ops { | |||
202 | #include <acpi/actypes.h> | 203 | #include <acpi/actypes.h> |
203 | #include <linux/pci-acpi.h> | 204 | #include <linux/pci-acpi.h> |
204 | 205 | ||
205 | #define pciehp_get_hp_hw_control_from_firmware(dev) \ | 206 | static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) |
206 | pciehp_acpi_get_hp_hw_control_from_firmware(dev) | 207 | { |
208 | u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | | ||
209 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||
210 | return acpi_get_hp_hw_control_from_firmware(dev, flags); | ||
211 | } | ||
212 | |||
207 | static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, | 213 | static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, |
208 | struct hotplug_params *hpp) | 214 | struct hotplug_params *hpp) |
209 | { | 215 | { |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 48a2ed378914..3677495c4f91 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -72,7 +72,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); | |||
72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
73 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 73 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
74 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 74 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
75 | static int get_address (struct hotplug_slot *slot, u32 *value); | ||
76 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 75 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
77 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 76 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
78 | 77 | ||
@@ -85,7 +84,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { | |||
85 | .get_attention_status = get_attention_status, | 84 | .get_attention_status = get_attention_status, |
86 | .get_latch_status = get_latch_status, | 85 | .get_latch_status = get_latch_status, |
87 | .get_adapter_status = get_adapter_status, | 86 | .get_adapter_status = get_adapter_status, |
88 | .get_address = get_address, | ||
89 | .get_max_bus_speed = get_max_bus_speed, | 87 | .get_max_bus_speed = get_max_bus_speed, |
90 | .get_cur_bus_speed = get_cur_bus_speed, | 88 | .get_cur_bus_speed = get_cur_bus_speed, |
91 | }; | 89 | }; |
@@ -185,23 +183,10 @@ static struct hotplug_slot_attribute hotplug_slot_attr_lock = { | |||
185 | */ | 183 | */ |
186 | static void release_slot(struct hotplug_slot *hotplug_slot) | 184 | static void release_slot(struct hotplug_slot *hotplug_slot) |
187 | { | 185 | { |
188 | struct slot *slot = hotplug_slot->private; | ||
189 | |||
190 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | 186 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); |
191 | 187 | ||
192 | kfree(slot->hotplug_slot->info); | 188 | kfree(hotplug_slot->info); |
193 | kfree(slot->hotplug_slot); | 189 | kfree(hotplug_slot); |
194 | kfree(slot); | ||
195 | } | ||
196 | |||
197 | static void make_slot_name(struct slot *slot) | ||
198 | { | ||
199 | if (pciehp_slot_with_bus) | ||
200 | snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", | ||
201 | slot->bus, slot->number); | ||
202 | else | ||
203 | snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", | ||
204 | slot->number); | ||
205 | } | 190 | } |
206 | 191 | ||
207 | static int init_slots(struct controller *ctrl) | 192 | static int init_slots(struct controller *ctrl) |
@@ -210,49 +195,34 @@ static int init_slots(struct controller *ctrl) | |||
210 | struct hotplug_slot *hotplug_slot; | 195 | struct hotplug_slot *hotplug_slot; |
211 | struct hotplug_slot_info *info; | 196 | struct hotplug_slot_info *info; |
212 | int retval = -ENOMEM; | 197 | int retval = -ENOMEM; |
213 | int i; | ||
214 | |||
215 | for (i = 0; i < ctrl->num_slots; i++) { | ||
216 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
217 | if (!slot) | ||
218 | goto error; | ||
219 | 198 | ||
199 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { | ||
220 | hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); | 200 | hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); |
221 | if (!hotplug_slot) | 201 | if (!hotplug_slot) |
222 | goto error_slot; | 202 | goto error; |
223 | slot->hotplug_slot = hotplug_slot; | ||
224 | 203 | ||
225 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 204 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
226 | if (!info) | 205 | if (!info) |
227 | goto error_hpslot; | 206 | goto error_hpslot; |
228 | hotplug_slot->info = info; | ||
229 | |||
230 | hotplug_slot->name = slot->name; | ||
231 | |||
232 | slot->hp_slot = i; | ||
233 | slot->ctrl = ctrl; | ||
234 | slot->bus = ctrl->pci_dev->subordinate->number; | ||
235 | slot->device = ctrl->slot_device_offset + i; | ||
236 | slot->hpc_ops = ctrl->hpc_ops; | ||
237 | slot->number = ctrl->first_slot; | ||
238 | mutex_init(&slot->lock); | ||
239 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | ||
240 | 207 | ||
241 | /* register this slot with the hotplug pci core */ | 208 | /* register this slot with the hotplug pci core */ |
209 | hotplug_slot->info = info; | ||
210 | hotplug_slot->name = slot->name; | ||
242 | hotplug_slot->private = slot; | 211 | hotplug_slot->private = slot; |
243 | hotplug_slot->release = &release_slot; | 212 | hotplug_slot->release = &release_slot; |
244 | make_slot_name(slot); | ||
245 | hotplug_slot->ops = &pciehp_hotplug_slot_ops; | 213 | hotplug_slot->ops = &pciehp_hotplug_slot_ops; |
246 | |||
247 | get_power_status(hotplug_slot, &info->power_status); | 214 | get_power_status(hotplug_slot, &info->power_status); |
248 | get_attention_status(hotplug_slot, &info->attention_status); | 215 | get_attention_status(hotplug_slot, &info->attention_status); |
249 | get_latch_status(hotplug_slot, &info->latch_status); | 216 | get_latch_status(hotplug_slot, &info->latch_status); |
250 | get_adapter_status(hotplug_slot, &info->adapter_status); | 217 | get_adapter_status(hotplug_slot, &info->adapter_status); |
218 | slot->hotplug_slot = hotplug_slot; | ||
251 | 219 | ||
252 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " | 220 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " |
253 | "slot_device_offset=%x\n", slot->bus, slot->device, | 221 | "slot_device_offset=%x\n", slot->bus, slot->device, |
254 | slot->hp_slot, slot->number, ctrl->slot_device_offset); | 222 | slot->hp_slot, slot->number, ctrl->slot_device_offset); |
255 | retval = pci_hp_register(hotplug_slot); | 223 | retval = pci_hp_register(hotplug_slot, |
224 | ctrl->pci_dev->subordinate, | ||
225 | slot->device); | ||
256 | if (retval) { | 226 | if (retval) { |
257 | err("pci_hp_register failed with error %d\n", retval); | 227 | err("pci_hp_register failed with error %d\n", retval); |
258 | if (retval == -EEXIST) | 228 | if (retval == -EEXIST) |
@@ -263,7 +233,7 @@ static int init_slots(struct controller *ctrl) | |||
263 | } | 233 | } |
264 | /* create additional sysfs entries */ | 234 | /* create additional sysfs entries */ |
265 | if (EMI(ctrl)) { | 235 | if (EMI(ctrl)) { |
266 | retval = sysfs_create_file(&hotplug_slot->kobj, | 236 | retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, |
267 | &hotplug_slot_attr_lock.attr); | 237 | &hotplug_slot_attr_lock.attr); |
268 | if (retval) { | 238 | if (retval) { |
269 | pci_hp_deregister(hotplug_slot); | 239 | pci_hp_deregister(hotplug_slot); |
@@ -271,8 +241,6 @@ static int init_slots(struct controller *ctrl) | |||
271 | goto error_info; | 241 | goto error_info; |
272 | } | 242 | } |
273 | } | 243 | } |
274 | |||
275 | list_add(&slot->slot_list, &ctrl->slot_list); | ||
276 | } | 244 | } |
277 | 245 | ||
278 | return 0; | 246 | return 0; |
@@ -280,27 +248,18 @@ error_info: | |||
280 | kfree(info); | 248 | kfree(info); |
281 | error_hpslot: | 249 | error_hpslot: |
282 | kfree(hotplug_slot); | 250 | kfree(hotplug_slot); |
283 | error_slot: | ||
284 | kfree(slot); | ||
285 | error: | 251 | error: |
286 | return retval; | 252 | return retval; |
287 | } | 253 | } |
288 | 254 | ||
289 | static void cleanup_slots(struct controller *ctrl) | 255 | static void cleanup_slots(struct controller *ctrl) |
290 | { | 256 | { |
291 | struct list_head *tmp; | ||
292 | struct list_head *next; | ||
293 | struct slot *slot; | 257 | struct slot *slot; |
294 | 258 | ||
295 | list_for_each_safe(tmp, next, &ctrl->slot_list) { | 259 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { |
296 | slot = list_entry(tmp, struct slot, slot_list); | ||
297 | list_del(&slot->slot_list); | ||
298 | if (EMI(ctrl)) | 260 | if (EMI(ctrl)) |
299 | sysfs_remove_file(&slot->hotplug_slot->kobj, | 261 | sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj, |
300 | &hotplug_slot_attr_lock.attr); | 262 | &hotplug_slot_attr_lock.attr); |
301 | cancel_delayed_work(&slot->work); | ||
302 | flush_scheduled_work(); | ||
303 | flush_workqueue(pciehp_wq); | ||
304 | pci_hp_deregister(slot->hotplug_slot); | 263 | pci_hp_deregister(slot->hotplug_slot); |
305 | } | 264 | } |
306 | } | 265 | } |
@@ -398,19 +357,8 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | |||
398 | return 0; | 357 | return 0; |
399 | } | 358 | } |
400 | 359 | ||
401 | static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) | 360 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, |
402 | { | 361 | enum pci_bus_speed *value) |
403 | struct slot *slot = hotplug_slot->private; | ||
404 | struct pci_bus *bus = slot->ctrl->pci_dev->subordinate; | ||
405 | |||
406 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | ||
407 | |||
408 | *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | ||
414 | { | 362 | { |
415 | struct slot *slot = hotplug_slot->private; | 363 | struct slot *slot = hotplug_slot->private; |
416 | int retval; | 364 | int retval; |
@@ -444,34 +392,30 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
444 | struct controller *ctrl; | 392 | struct controller *ctrl; |
445 | struct slot *t_slot; | 393 | struct slot *t_slot; |
446 | u8 value; | 394 | u8 value; |
447 | struct pci_dev *pdev; | 395 | struct pci_dev *pdev = dev->port; |
448 | 396 | ||
449 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | 397 | if (pciehp_force) |
450 | if (!ctrl) { | 398 | dbg("Bypassing BIOS check for pciehp use on %s\n", |
451 | err("%s : out of memory\n", __func__); | 399 | pci_name(pdev)); |
400 | else if (pciehp_get_hp_hw_control_from_firmware(pdev)) | ||
452 | goto err_out_none; | 401 | goto err_out_none; |
453 | } | ||
454 | INIT_LIST_HEAD(&ctrl->slot_list); | ||
455 | |||
456 | pdev = dev->port; | ||
457 | ctrl->pci_dev = pdev; | ||
458 | 402 | ||
459 | rc = pcie_init(ctrl, dev); | 403 | ctrl = pcie_init(dev); |
460 | if (rc) { | 404 | if (!ctrl) { |
461 | dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); | 405 | dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); |
462 | goto err_out_free_ctrl; | 406 | goto err_out_none; |
463 | } | 407 | } |
464 | 408 | set_service_data(dev, ctrl); | |
465 | pci_set_drvdata(pdev, ctrl); | ||
466 | |||
467 | dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", | ||
468 | __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), | ||
469 | PCI_FUNC(pdev->devfn), pdev->irq); | ||
470 | 409 | ||
471 | /* Setup the slot information structures */ | 410 | /* Setup the slot information structures */ |
472 | rc = init_slots(ctrl); | 411 | rc = init_slots(ctrl); |
473 | if (rc) { | 412 | if (rc) { |
474 | err("%s: slot initialization failed\n", PCIE_MODULE_NAME); | 413 | if (rc == -EBUSY) |
414 | warn("%s: slot already registered by another " | ||
415 | "hotplug driver\n", PCIE_MODULE_NAME); | ||
416 | else | ||
417 | err("%s: slot initialization failed\n", | ||
418 | PCIE_MODULE_NAME); | ||
475 | goto err_out_release_ctlr; | 419 | goto err_out_release_ctlr; |
476 | } | 420 | } |
477 | 421 | ||
@@ -495,20 +439,16 @@ err_out_free_ctrl_slot: | |||
495 | cleanup_slots(ctrl); | 439 | cleanup_slots(ctrl); |
496 | err_out_release_ctlr: | 440 | err_out_release_ctlr: |
497 | ctrl->hpc_ops->release_ctlr(ctrl); | 441 | ctrl->hpc_ops->release_ctlr(ctrl); |
498 | err_out_free_ctrl: | ||
499 | kfree(ctrl); | ||
500 | err_out_none: | 442 | err_out_none: |
501 | return -ENODEV; | 443 | return -ENODEV; |
502 | } | 444 | } |
503 | 445 | ||
504 | static void pciehp_remove (struct pcie_device *dev) | 446 | static void pciehp_remove (struct pcie_device *dev) |
505 | { | 447 | { |
506 | struct pci_dev *pdev = dev->port; | 448 | struct controller *ctrl = get_service_data(dev); |
507 | struct controller *ctrl = pci_get_drvdata(pdev); | ||
508 | 449 | ||
509 | cleanup_slots(ctrl); | 450 | cleanup_slots(ctrl); |
510 | ctrl->hpc_ops->release_ctlr(ctrl); | 451 | ctrl->hpc_ops->release_ctlr(ctrl); |
511 | kfree(ctrl); | ||
512 | } | 452 | } |
513 | 453 | ||
514 | #ifdef CONFIG_PM | 454 | #ifdef CONFIG_PM |
@@ -522,13 +462,12 @@ static int pciehp_resume (struct pcie_device *dev) | |||
522 | { | 462 | { |
523 | printk("%s ENTRY\n", __func__); | 463 | printk("%s ENTRY\n", __func__); |
524 | if (pciehp_force) { | 464 | if (pciehp_force) { |
525 | struct pci_dev *pdev = dev->port; | 465 | struct controller *ctrl = get_service_data(dev); |
526 | struct controller *ctrl = pci_get_drvdata(pdev); | ||
527 | struct slot *t_slot; | 466 | struct slot *t_slot; |
528 | u8 status; | 467 | u8 status; |
529 | 468 | ||
530 | /* reinitialize the chipset's event detection logic */ | 469 | /* reinitialize the chipset's event detection logic */ |
531 | pcie_init_hardware_part2(ctrl, dev); | 470 | pcie_enable_notification(ctrl); |
532 | 471 | ||
533 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 472 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); |
534 | 473 | ||
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 79f104963166..1323a43285d7 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -247,30 +247,32 @@ static inline void pciehp_free_irq(struct controller *ctrl) | |||
247 | free_irq(ctrl->pci_dev->irq, ctrl); | 247 | free_irq(ctrl->pci_dev->irq, ctrl); |
248 | } | 248 | } |
249 | 249 | ||
250 | static inline int pcie_poll_cmd(struct controller *ctrl) | 250 | static int pcie_poll_cmd(struct controller *ctrl) |
251 | { | 251 | { |
252 | u16 slot_status; | 252 | u16 slot_status; |
253 | int timeout = 1000; | 253 | int timeout = 1000; |
254 | 254 | ||
255 | if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) | 255 | if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) { |
256 | if (slot_status & CMD_COMPLETED) | 256 | if (slot_status & CMD_COMPLETED) { |
257 | goto completed; | 257 | pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED); |
258 | for (timeout = 1000; timeout > 0; timeout -= 100) { | 258 | return 1; |
259 | msleep(100); | 259 | } |
260 | if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) | 260 | } |
261 | if (slot_status & CMD_COMPLETED) | 261 | while (timeout > 1000) { |
262 | goto completed; | 262 | msleep(10); |
263 | timeout -= 10; | ||
264 | if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) { | ||
265 | if (slot_status & CMD_COMPLETED) { | ||
266 | pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED); | ||
267 | return 1; | ||
268 | } | ||
269 | } | ||
263 | } | 270 | } |
264 | return 0; /* timeout */ | 271 | return 0; /* timeout */ |
265 | |||
266 | completed: | ||
267 | pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED); | ||
268 | return timeout; | ||
269 | } | 272 | } |
270 | 273 | ||
271 | static inline int pcie_wait_cmd(struct controller *ctrl, int poll) | 274 | static void pcie_wait_cmd(struct controller *ctrl, int poll) |
272 | { | 275 | { |
273 | int retval = 0; | ||
274 | unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; | 276 | unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; |
275 | unsigned long timeout = msecs_to_jiffies(msecs); | 277 | unsigned long timeout = msecs_to_jiffies(msecs); |
276 | int rc; | 278 | int rc; |
@@ -278,16 +280,9 @@ static inline int pcie_wait_cmd(struct controller *ctrl, int poll) | |||
278 | if (poll) | 280 | if (poll) |
279 | rc = pcie_poll_cmd(ctrl); | 281 | rc = pcie_poll_cmd(ctrl); |
280 | else | 282 | else |
281 | rc = wait_event_interruptible_timeout(ctrl->queue, | 283 | rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout); |
282 | !ctrl->cmd_busy, timeout); | ||
283 | if (!rc) | 284 | if (!rc) |
284 | dbg("Command not completed in 1000 msec\n"); | 285 | dbg("Command not completed in 1000 msec\n"); |
285 | else if (rc < 0) { | ||
286 | retval = -EINTR; | ||
287 | info("Command was interrupted by a signal\n"); | ||
288 | } | ||
289 | |||
290 | return retval; | ||
291 | } | 286 | } |
292 | 287 | ||
293 | /** | 288 | /** |
@@ -342,10 +337,6 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) | |||
342 | 337 | ||
343 | slot_ctrl &= ~mask; | 338 | slot_ctrl &= ~mask; |
344 | slot_ctrl |= (cmd & mask); | 339 | slot_ctrl |= (cmd & mask); |
345 | /* Don't enable command completed if caller is changing it. */ | ||
346 | if (!(mask & CMD_CMPL_INTR_ENABLE)) | ||
347 | slot_ctrl |= CMD_CMPL_INTR_ENABLE; | ||
348 | |||
349 | ctrl->cmd_busy = 1; | 340 | ctrl->cmd_busy = 1; |
350 | smp_mb(); | 341 | smp_mb(); |
351 | retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl); | 342 | retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl); |
@@ -365,7 +356,7 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) | |||
365 | if (!(slot_ctrl & HP_INTR_ENABLE) || | 356 | if (!(slot_ctrl & HP_INTR_ENABLE) || |
366 | !(slot_ctrl & CMD_CMPL_INTR_ENABLE)) | 357 | !(slot_ctrl & CMD_CMPL_INTR_ENABLE)) |
367 | poll = 1; | 358 | poll = 1; |
368 | retval = pcie_wait_cmd(ctrl, poll); | 359 | pcie_wait_cmd(ctrl, poll); |
369 | } | 360 | } |
370 | out: | 361 | out: |
371 | mutex_unlock(&ctrl->ctrl_lock); | 362 | mutex_unlock(&ctrl->ctrl_lock); |
@@ -614,23 +605,6 @@ static void hpc_set_green_led_blink(struct slot *slot) | |||
614 | __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); | 605 | __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); |
615 | } | 606 | } |
616 | 607 | ||
617 | static void hpc_release_ctlr(struct controller *ctrl) | ||
618 | { | ||
619 | /* Mask Hot-plug Interrupt Enable */ | ||
620 | if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) | ||
621 | err("%s: Cannot mask hotplut interrupt enable\n", __func__); | ||
622 | |||
623 | /* Free interrupt handler or interrupt polling timer */ | ||
624 | pciehp_free_irq(ctrl); | ||
625 | |||
626 | /* | ||
627 | * If this is the last controller to be released, destroy the | ||
628 | * pciehp work queue | ||
629 | */ | ||
630 | if (atomic_dec_and_test(&pciehp_num_controllers)) | ||
631 | destroy_workqueue(pciehp_wq); | ||
632 | } | ||
633 | |||
634 | static int hpc_power_on_slot(struct slot * slot) | 608 | static int hpc_power_on_slot(struct slot * slot) |
635 | { | 609 | { |
636 | struct controller *ctrl = slot->ctrl; | 610 | struct controller *ctrl = slot->ctrl; |
@@ -785,7 +759,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) | |||
785 | intr_loc |= detected; | 759 | intr_loc |= detected; |
786 | if (!intr_loc) | 760 | if (!intr_loc) |
787 | return IRQ_NONE; | 761 | return IRQ_NONE; |
788 | if (pciehp_writew(ctrl, SLOTSTATUS, detected)) { | 762 | if (detected && pciehp_writew(ctrl, SLOTSTATUS, detected)) { |
789 | err("%s: Cannot write to SLOTSTATUS\n", __func__); | 763 | err("%s: Cannot write to SLOTSTATUS\n", __func__); |
790 | return IRQ_NONE; | 764 | return IRQ_NONE; |
791 | } | 765 | } |
@@ -797,25 +771,13 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) | |||
797 | if (intr_loc & CMD_COMPLETED) { | 771 | if (intr_loc & CMD_COMPLETED) { |
798 | ctrl->cmd_busy = 0; | 772 | ctrl->cmd_busy = 0; |
799 | smp_mb(); | 773 | smp_mb(); |
800 | wake_up_interruptible(&ctrl->queue); | 774 | wake_up(&ctrl->queue); |
801 | } | 775 | } |
802 | 776 | ||
803 | if (!(intr_loc & ~CMD_COMPLETED)) | 777 | if (!(intr_loc & ~CMD_COMPLETED)) |
804 | return IRQ_HANDLED; | 778 | return IRQ_HANDLED; |
805 | 779 | ||
806 | /* | ||
807 | * Return without handling events if this handler routine is | ||
808 | * called before controller initialization is done. This may | ||
809 | * happen if hotplug event or another interrupt that shares | ||
810 | * the IRQ with pciehp arrives before slot initialization is | ||
811 | * done after interrupt handler is registered. | ||
812 | * | ||
813 | * FIXME - Need more structural fixes. We need to be ready to | ||
814 | * handle the event before installing interrupt handler. | ||
815 | */ | ||
816 | p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 780 | p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); |
817 | if (!p_slot || !p_slot->hpc_ops) | ||
818 | return IRQ_HANDLED; | ||
819 | 781 | ||
820 | /* Check MRL Sensor Changed */ | 782 | /* Check MRL Sensor Changed */ |
821 | if (intr_loc & MRL_SENS_CHANGED) | 783 | if (intr_loc & MRL_SENS_CHANGED) |
@@ -992,6 +954,7 @@ static int hpc_get_cur_lnk_width(struct slot *slot, | |||
992 | return retval; | 954 | return retval; |
993 | } | 955 | } |
994 | 956 | ||
957 | static void pcie_release_ctrl(struct controller *ctrl); | ||
995 | static struct hpc_ops pciehp_hpc_ops = { | 958 | static struct hpc_ops pciehp_hpc_ops = { |
996 | .power_on_slot = hpc_power_on_slot, | 959 | .power_on_slot = hpc_power_on_slot, |
997 | .power_off_slot = hpc_power_off_slot, | 960 | .power_off_slot = hpc_power_off_slot, |
@@ -1013,97 +976,11 @@ static struct hpc_ops pciehp_hpc_ops = { | |||
1013 | .green_led_off = hpc_set_green_led_off, | 976 | .green_led_off = hpc_set_green_led_off, |
1014 | .green_led_blink = hpc_set_green_led_blink, | 977 | .green_led_blink = hpc_set_green_led_blink, |
1015 | 978 | ||
1016 | .release_ctlr = hpc_release_ctlr, | 979 | .release_ctlr = pcie_release_ctrl, |
1017 | .check_lnk_status = hpc_check_lnk_status, | 980 | .check_lnk_status = hpc_check_lnk_status, |
1018 | }; | 981 | }; |
1019 | 982 | ||
1020 | #ifdef CONFIG_ACPI | 983 | int pcie_enable_notification(struct controller *ctrl) |
1021 | static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | ||
1022 | { | ||
1023 | acpi_status status; | ||
1024 | acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); | ||
1025 | struct pci_dev *pdev = dev; | ||
1026 | struct pci_bus *parent; | ||
1027 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1028 | |||
1029 | /* | ||
1030 | * Per PCI firmware specification, we should run the ACPI _OSC | ||
1031 | * method to get control of hotplug hardware before using it. | ||
1032 | * If an _OSC is missing, we look for an OSHP to do the same thing. | ||
1033 | * To handle different BIOS behavior, we look for _OSC and OSHP | ||
1034 | * within the scope of the hotplug controller and its parents, upto | ||
1035 | * the host bridge under which this controller exists. | ||
1036 | */ | ||
1037 | while (!handle) { | ||
1038 | /* | ||
1039 | * This hotplug controller was not listed in the ACPI name | ||
1040 | * space at all. Try to get acpi handle of parent pci bus. | ||
1041 | */ | ||
1042 | if (!pdev || !pdev->bus->parent) | ||
1043 | break; | ||
1044 | parent = pdev->bus->parent; | ||
1045 | dbg("Could not find %s in acpi namespace, trying parent\n", | ||
1046 | pci_name(pdev)); | ||
1047 | if (!parent->self) | ||
1048 | /* Parent must be a host bridge */ | ||
1049 | handle = acpi_get_pci_rootbridge_handle( | ||
1050 | pci_domain_nr(parent), | ||
1051 | parent->number); | ||
1052 | else | ||
1053 | handle = DEVICE_ACPI_HANDLE( | ||
1054 | &(parent->self->dev)); | ||
1055 | pdev = parent->self; | ||
1056 | } | ||
1057 | |||
1058 | while (handle) { | ||
1059 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); | ||
1060 | dbg("Trying to get hotplug control for %s \n", | ||
1061 | (char *)string.pointer); | ||
1062 | status = pci_osc_control_set(handle, | ||
1063 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | | ||
1064 | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); | ||
1065 | if (status == AE_NOT_FOUND) | ||
1066 | status = acpi_run_oshp(handle); | ||
1067 | if (ACPI_SUCCESS(status)) { | ||
1068 | dbg("Gained control for hotplug HW for pci %s (%s)\n", | ||
1069 | pci_name(dev), (char *)string.pointer); | ||
1070 | kfree(string.pointer); | ||
1071 | return 0; | ||
1072 | } | ||
1073 | if (acpi_root_bridge(handle)) | ||
1074 | break; | ||
1075 | chandle = handle; | ||
1076 | status = acpi_get_parent(chandle, &handle); | ||
1077 | if (ACPI_FAILURE(status)) | ||
1078 | break; | ||
1079 | } | ||
1080 | |||
1081 | dbg("Cannot get control of hotplug hardware for pci %s\n", | ||
1082 | pci_name(dev)); | ||
1083 | |||
1084 | kfree(string.pointer); | ||
1085 | return -1; | ||
1086 | } | ||
1087 | #endif | ||
1088 | |||
1089 | static int pcie_init_hardware_part1(struct controller *ctrl, | ||
1090 | struct pcie_device *dev) | ||
1091 | { | ||
1092 | /* Clear all remaining event bits in Slot Status register */ | ||
1093 | if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) { | ||
1094 | err("%s: Cannot write to SLOTSTATUS register\n", __func__); | ||
1095 | return -1; | ||
1096 | } | ||
1097 | |||
1098 | /* Mask Hot-plug Interrupt Enable */ | ||
1099 | if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { | ||
1100 | err("%s: Cannot mask hotplug interrupt enable\n", __func__); | ||
1101 | return -1; | ||
1102 | } | ||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) | ||
1107 | { | 984 | { |
1108 | u16 cmd, mask; | 985 | u16 cmd, mask; |
1109 | 986 | ||
@@ -1115,30 +992,83 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) | |||
1115 | if (MRL_SENS(ctrl)) | 992 | if (MRL_SENS(ctrl)) |
1116 | cmd |= MRL_DETECT_ENABLE; | 993 | cmd |= MRL_DETECT_ENABLE; |
1117 | if (!pciehp_poll_mode) | 994 | if (!pciehp_poll_mode) |
1118 | cmd |= HP_INTR_ENABLE; | 995 | cmd |= HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE; |
1119 | 996 | ||
1120 | mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | | 997 | mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | MRL_DETECT_ENABLE | |
1121 | PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | HP_INTR_ENABLE; | 998 | PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE; |
1122 | 999 | ||
1123 | if (pcie_write_cmd(ctrl, cmd, mask)) { | 1000 | if (pcie_write_cmd(ctrl, cmd, mask)) { |
1124 | err("%s: Cannot enable software notification\n", __func__); | 1001 | err("%s: Cannot enable software notification\n", __func__); |
1125 | goto abort; | 1002 | return -1; |
1126 | } | 1003 | } |
1004 | return 0; | ||
1005 | } | ||
1127 | 1006 | ||
1128 | if (pciehp_force) | 1007 | static void pcie_disable_notification(struct controller *ctrl) |
1129 | dbg("Bypassing BIOS check for pciehp use on %s\n", | 1008 | { |
1130 | pci_name(ctrl->pci_dev)); | 1009 | u16 mask; |
1131 | else if (pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev)) | 1010 | mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | MRL_DETECT_ENABLE | |
1132 | goto abort_disable_intr; | 1011 | PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE; |
1012 | if (pcie_write_cmd(ctrl, 0, mask)) | ||
1013 | warn("%s: Cannot disable software notification\n", __func__); | ||
1014 | } | ||
1133 | 1015 | ||
1016 | static int pcie_init_notification(struct controller *ctrl) | ||
1017 | { | ||
1018 | if (pciehp_request_irq(ctrl)) | ||
1019 | return -1; | ||
1020 | if (pcie_enable_notification(ctrl)) { | ||
1021 | pciehp_free_irq(ctrl); | ||
1022 | return -1; | ||
1023 | } | ||
1134 | return 0; | 1024 | return 0; |
1025 | } | ||
1135 | 1026 | ||
1136 | /* We end up here for the many possible ways to fail this API. */ | 1027 | static void pcie_shutdown_notification(struct controller *ctrl) |
1137 | abort_disable_intr: | 1028 | { |
1138 | if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE)) | 1029 | pcie_disable_notification(ctrl); |
1139 | err("%s : disabling interrupts failed\n", __func__); | 1030 | pciehp_free_irq(ctrl); |
1140 | abort: | 1031 | } |
1141 | return -1; | 1032 | |
1033 | static void make_slot_name(struct slot *slot) | ||
1034 | { | ||
1035 | if (pciehp_slot_with_bus) | ||
1036 | snprintf(slot->name, SLOT_NAME_SIZE, "%04d_%04d", | ||
1037 | slot->bus, slot->number); | ||
1038 | else | ||
1039 | snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number); | ||
1040 | } | ||
1041 | |||
1042 | static int pcie_init_slot(struct controller *ctrl) | ||
1043 | { | ||
1044 | struct slot *slot; | ||
1045 | |||
1046 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
1047 | if (!slot) | ||
1048 | return -ENOMEM; | ||
1049 | |||
1050 | slot->hp_slot = 0; | ||
1051 | slot->ctrl = ctrl; | ||
1052 | slot->bus = ctrl->pci_dev->subordinate->number; | ||
1053 | slot->device = ctrl->slot_device_offset + slot->hp_slot; | ||
1054 | slot->hpc_ops = ctrl->hpc_ops; | ||
1055 | slot->number = ctrl->first_slot; | ||
1056 | make_slot_name(slot); | ||
1057 | mutex_init(&slot->lock); | ||
1058 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | ||
1059 | list_add(&slot->slot_list, &ctrl->slot_list); | ||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | static void pcie_cleanup_slot(struct controller *ctrl) | ||
1064 | { | ||
1065 | struct slot *slot; | ||
1066 | slot = list_first_entry(&ctrl->slot_list, struct slot, slot_list); | ||
1067 | list_del(&slot->slot_list); | ||
1068 | cancel_delayed_work(&slot->work); | ||
1069 | flush_scheduled_work(); | ||
1070 | flush_workqueue(pciehp_wq); | ||
1071 | kfree(slot); | ||
1142 | } | 1072 | } |
1143 | 1073 | ||
1144 | static inline void dbg_ctrl(struct controller *ctrl) | 1074 | static inline void dbg_ctrl(struct controller *ctrl) |
@@ -1176,15 +1106,23 @@ static inline void dbg_ctrl(struct controller *ctrl) | |||
1176 | dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); | 1106 | dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); |
1177 | pciehp_readw(ctrl, SLOTSTATUS, ®16); | 1107 | pciehp_readw(ctrl, SLOTSTATUS, ®16); |
1178 | dbg("Slot Status : 0x%04x\n", reg16); | 1108 | dbg("Slot Status : 0x%04x\n", reg16); |
1179 | pciehp_readw(ctrl, SLOTSTATUS, ®16); | 1109 | pciehp_readw(ctrl, SLOTCTRL, ®16); |
1180 | dbg("Slot Control : 0x%04x\n", reg16); | 1110 | dbg("Slot Control : 0x%04x\n", reg16); |
1181 | } | 1111 | } |
1182 | 1112 | ||
1183 | int pcie_init(struct controller *ctrl, struct pcie_device *dev) | 1113 | struct controller *pcie_init(struct pcie_device *dev) |
1184 | { | 1114 | { |
1115 | struct controller *ctrl; | ||
1185 | u32 slot_cap; | 1116 | u32 slot_cap; |
1186 | struct pci_dev *pdev = dev->port; | 1117 | struct pci_dev *pdev = dev->port; |
1187 | 1118 | ||
1119 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | ||
1120 | if (!ctrl) { | ||
1121 | err("%s : out of memory\n", __func__); | ||
1122 | goto abort; | ||
1123 | } | ||
1124 | INIT_LIST_HEAD(&ctrl->slot_list); | ||
1125 | |||
1188 | ctrl->pci_dev = pdev; | 1126 | ctrl->pci_dev = pdev; |
1189 | ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 1127 | ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); |
1190 | if (!ctrl->cap_base) { | 1128 | if (!ctrl->cap_base) { |
@@ -1215,15 +1153,12 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) | |||
1215 | !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) | 1153 | !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) |
1216 | ctrl->no_cmd_complete = 1; | 1154 | ctrl->no_cmd_complete = 1; |
1217 | 1155 | ||
1218 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", | 1156 | /* Clear all remaining event bits in Slot Status register */ |
1219 | pdev->vendor, pdev->device, | 1157 | if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) |
1220 | pdev->subsystem_vendor, pdev->subsystem_device); | 1158 | goto abort_ctrl; |
1221 | 1159 | ||
1222 | if (pcie_init_hardware_part1(ctrl, dev)) | 1160 | /* Disable sotfware notification */ |
1223 | goto abort; | 1161 | pcie_disable_notification(ctrl); |
1224 | |||
1225 | if (pciehp_request_irq(ctrl)) | ||
1226 | goto abort; | ||
1227 | 1162 | ||
1228 | /* | 1163 | /* |
1229 | * If this is the first controller to be initialized, | 1164 | * If this is the first controller to be initialized, |
@@ -1231,18 +1166,39 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) | |||
1231 | */ | 1166 | */ |
1232 | if (atomic_add_return(1, &pciehp_num_controllers) == 1) { | 1167 | if (atomic_add_return(1, &pciehp_num_controllers) == 1) { |
1233 | pciehp_wq = create_singlethread_workqueue("pciehpd"); | 1168 | pciehp_wq = create_singlethread_workqueue("pciehpd"); |
1234 | if (!pciehp_wq) { | 1169 | if (!pciehp_wq) |
1235 | goto abort_free_irq; | 1170 | goto abort_ctrl; |
1236 | } | ||
1237 | } | 1171 | } |
1238 | 1172 | ||
1239 | if (pcie_init_hardware_part2(ctrl, dev)) | 1173 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", |
1240 | goto abort_free_irq; | 1174 | pdev->vendor, pdev->device, |
1175 | pdev->subsystem_vendor, pdev->subsystem_device); | ||
1176 | |||
1177 | if (pcie_init_slot(ctrl)) | ||
1178 | goto abort_ctrl; | ||
1241 | 1179 | ||
1242 | return 0; | 1180 | if (pcie_init_notification(ctrl)) |
1181 | goto abort_slot; | ||
1243 | 1182 | ||
1244 | abort_free_irq: | 1183 | return ctrl; |
1245 | pciehp_free_irq(ctrl); | 1184 | |
1185 | abort_slot: | ||
1186 | pcie_cleanup_slot(ctrl); | ||
1187 | abort_ctrl: | ||
1188 | kfree(ctrl); | ||
1246 | abort: | 1189 | abort: |
1247 | return -1; | 1190 | return NULL; |
1191 | } | ||
1192 | |||
1193 | void pcie_release_ctrl(struct controller *ctrl) | ||
1194 | { | ||
1195 | pcie_shutdown_notification(ctrl); | ||
1196 | pcie_cleanup_slot(ctrl); | ||
1197 | /* | ||
1198 | * If this is the last controller to be released, destroy the | ||
1199 | * pciehp work queue | ||
1200 | */ | ||
1201 | if (atomic_dec_and_test(&pciehp_num_controllers)) | ||
1202 | destroy_workqueue(pciehp_wq); | ||
1203 | kfree(ctrl); | ||
1248 | } | 1204 | } |
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index 779c5db71be4..a796301ea03f 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c | |||
@@ -14,8 +14,10 @@ | |||
14 | */ | 14 | */ |
15 | #include <linux/kobject.h> | 15 | #include <linux/kobject.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/pci.h> | ||
17 | #include <linux/pci_hotplug.h> | 18 | #include <linux/pci_hotplug.h> |
18 | #include "rpadlpar.h" | 19 | #include "rpadlpar.h" |
20 | #include "../pci.h" | ||
19 | 21 | ||
20 | #define DLPAR_KOBJ_NAME "control" | 22 | #define DLPAR_KOBJ_NAME "control" |
21 | 23 | ||
@@ -27,7 +29,6 @@ | |||
27 | 29 | ||
28 | #define MAX_DRC_NAME_LEN 64 | 30 | #define MAX_DRC_NAME_LEN 64 |
29 | 31 | ||
30 | |||
31 | static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, | 32 | static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, |
32 | const char *buf, size_t nbytes) | 33 | const char *buf, size_t nbytes) |
33 | { | 34 | { |
@@ -112,7 +113,7 @@ int dlpar_sysfs_init(void) | |||
112 | int error; | 113 | int error; |
113 | 114 | ||
114 | dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME, | 115 | dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME, |
115 | &pci_hotplug_slots_kset->kobj); | 116 | &pci_slots_kset->kobj); |
116 | if (!dlpar_kobj) | 117 | if (!dlpar_kobj) |
117 | return -EINVAL; | 118 | return -EINVAL; |
118 | 119 | ||
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 56197b600d36..9b714ea93d20 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c | |||
@@ -33,33 +33,6 @@ | |||
33 | #include <asm/rtas.h> | 33 | #include <asm/rtas.h> |
34 | #include "rpaphp.h" | 34 | #include "rpaphp.h" |
35 | 35 | ||
36 | static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf) | ||
37 | { | ||
38 | int retval; | ||
39 | struct slot *slot = (struct slot *)php_slot->private; | ||
40 | struct pci_bus *bus; | ||
41 | |||
42 | if (!slot) | ||
43 | return -ENOENT; | ||
44 | |||
45 | bus = slot->bus; | ||
46 | if (!bus) | ||
47 | return -ENOENT; | ||
48 | |||
49 | if (bus->self) | ||
50 | retval = sprintf(buf, pci_name(bus->self)); | ||
51 | else | ||
52 | retval = sprintf(buf, "%04x:%02x:00.0", | ||
53 | pci_domain_nr(bus), bus->number); | ||
54 | |||
55 | return retval; | ||
56 | } | ||
57 | |||
58 | static struct hotplug_slot_attribute php_attr_address = { | ||
59 | .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, | ||
60 | .show = address_read_file, | ||
61 | }; | ||
62 | |||
63 | /* free up the memory used by a slot */ | 36 | /* free up the memory used by a slot */ |
64 | static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) | 37 | static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) |
65 | { | 38 | { |
@@ -135,9 +108,6 @@ int rpaphp_deregister_slot(struct slot *slot) | |||
135 | 108 | ||
136 | list_del(&slot->rpaphp_slot_list); | 109 | list_del(&slot->rpaphp_slot_list); |
137 | 110 | ||
138 | /* remove "address" file */ | ||
139 | sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr); | ||
140 | |||
141 | retval = pci_hp_deregister(php_slot); | 111 | retval = pci_hp_deregister(php_slot); |
142 | if (retval) | 112 | if (retval) |
143 | err("Problem unregistering a slot %s\n", slot->name); | 113 | err("Problem unregistering a slot %s\n", slot->name); |
@@ -151,6 +121,7 @@ int rpaphp_register_slot(struct slot *slot) | |||
151 | { | 121 | { |
152 | struct hotplug_slot *php_slot = slot->hotplug_slot; | 122 | struct hotplug_slot *php_slot = slot->hotplug_slot; |
153 | int retval; | 123 | int retval; |
124 | int slotno; | ||
154 | 125 | ||
155 | dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", | 126 | dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", |
156 | __func__, slot->dn->full_name, slot->index, slot->name, | 127 | __func__, slot->dn->full_name, slot->index, slot->name, |
@@ -162,19 +133,16 @@ int rpaphp_register_slot(struct slot *slot) | |||
162 | return -EAGAIN; | 133 | return -EAGAIN; |
163 | } | 134 | } |
164 | 135 | ||
165 | retval = pci_hp_register(php_slot); | 136 | if (slot->dn->child) |
137 | slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn); | ||
138 | else | ||
139 | slotno = -1; | ||
140 | retval = pci_hp_register(php_slot, slot->bus, slotno); | ||
166 | if (retval) { | 141 | if (retval) { |
167 | err("pci_hp_register failed with error %d\n", retval); | 142 | err("pci_hp_register failed with error %d\n", retval); |
168 | return retval; | 143 | return retval; |
169 | } | 144 | } |
170 | 145 | ||
171 | /* create "address" file */ | ||
172 | retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr); | ||
173 | if (retval) { | ||
174 | err("sysfs_create_file failed with error %d\n", retval); | ||
175 | goto sysfs_fail; | ||
176 | } | ||
177 | |||
178 | /* add slot to our internal list */ | 146 | /* add slot to our internal list */ |
179 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); | 147 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); |
180 | info("Slot [%s] registered\n", slot->name); | 148 | info("Slot [%s] registered\n", slot->name); |
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 2fe37cd85b69..410fe0394a8e 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c | |||
@@ -197,13 +197,15 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, | |||
197 | static struct hotplug_slot * sn_hp_destroy(void) | 197 | static struct hotplug_slot * sn_hp_destroy(void) |
198 | { | 198 | { |
199 | struct slot *slot; | 199 | struct slot *slot; |
200 | struct pci_slot *pci_slot; | ||
200 | struct hotplug_slot *bss_hotplug_slot = NULL; | 201 | struct hotplug_slot *bss_hotplug_slot = NULL; |
201 | 202 | ||
202 | list_for_each_entry(slot, &sn_hp_list, hp_list) { | 203 | list_for_each_entry(slot, &sn_hp_list, hp_list) { |
203 | bss_hotplug_slot = slot->hotplug_slot; | 204 | bss_hotplug_slot = slot->hotplug_slot; |
205 | pci_slot = bss_hotplug_slot->pci_slot; | ||
204 | list_del(&((struct slot *)bss_hotplug_slot->private)-> | 206 | list_del(&((struct slot *)bss_hotplug_slot->private)-> |
205 | hp_list); | 207 | hp_list); |
206 | sysfs_remove_file(&bss_hotplug_slot->kobj, | 208 | sysfs_remove_file(&pci_slot->kobj, |
207 | &sn_slot_path_attr.attr); | 209 | &sn_slot_path_attr.attr); |
208 | break; | 210 | break; |
209 | } | 211 | } |
@@ -614,6 +616,7 @@ static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) | |||
614 | static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | 616 | static int sn_hotplug_slot_register(struct pci_bus *pci_bus) |
615 | { | 617 | { |
616 | int device; | 618 | int device; |
619 | struct pci_slot *pci_slot; | ||
617 | struct hotplug_slot *bss_hotplug_slot; | 620 | struct hotplug_slot *bss_hotplug_slot; |
618 | int rc = 0; | 621 | int rc = 0; |
619 | 622 | ||
@@ -650,11 +653,12 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | |||
650 | bss_hotplug_slot->ops = &sn_hotplug_slot_ops; | 653 | bss_hotplug_slot->ops = &sn_hotplug_slot_ops; |
651 | bss_hotplug_slot->release = &sn_release_slot; | 654 | bss_hotplug_slot->release = &sn_release_slot; |
652 | 655 | ||
653 | rc = pci_hp_register(bss_hotplug_slot); | 656 | rc = pci_hp_register(bss_hotplug_slot, pci_bus, device); |
654 | if (rc) | 657 | if (rc) |
655 | goto register_err; | 658 | goto register_err; |
656 | 659 | ||
657 | rc = sysfs_create_file(&bss_hotplug_slot->kobj, | 660 | pci_slot = bss_hotplug_slot->pci_slot; |
661 | rc = sysfs_create_file(&pci_slot->kobj, | ||
658 | &sn_slot_path_attr.attr); | 662 | &sn_slot_path_attr.attr); |
659 | if (rc) | 663 | if (rc) |
660 | goto register_err; | 664 | goto register_err; |
@@ -664,7 +668,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | |||
664 | 668 | ||
665 | register_err: | 669 | register_err: |
666 | dev_dbg(&pci_bus->self->dev, "bus failed to register with err = %d\n", | 670 | dev_dbg(&pci_bus->self->dev, "bus failed to register with err = %d\n", |
667 | rc); | 671 | rc); |
668 | 672 | ||
669 | alloc_err: | 673 | alloc_err: |
670 | if (rc == -ENOMEM) | 674 | if (rc == -ENOMEM) |
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index f66e8d6315ab..8a026f750deb 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
@@ -170,6 +170,7 @@ extern void shpchp_queue_pushbutton_work(struct work_struct *work); | |||
170 | extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); | 170 | extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); |
171 | 171 | ||
172 | #ifdef CONFIG_ACPI | 172 | #ifdef CONFIG_ACPI |
173 | #include <linux/pci-acpi.h> | ||
173 | static inline int get_hp_params_from_firmware(struct pci_dev *dev, | 174 | static inline int get_hp_params_from_firmware(struct pci_dev *dev, |
174 | struct hotplug_params *hpp) | 175 | struct hotplug_params *hpp) |
175 | { | 176 | { |
@@ -177,14 +178,15 @@ static inline int get_hp_params_from_firmware(struct pci_dev *dev, | |||
177 | return -ENODEV; | 178 | return -ENODEV; |
178 | return 0; | 179 | return 0; |
179 | } | 180 | } |
180 | #define get_hp_hw_control_from_firmware(pdev) \ | 181 | |
181 | do { \ | 182 | static inline int get_hp_hw_control_from_firmware(struct pci_dev *dev) |
182 | if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \ | 183 | { |
183 | acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev)));\ | 184 | u32 flags = OSC_SHPC_NATIVE_HP_CONTROL; |
184 | } while (0) | 185 | return acpi_get_hp_hw_control_from_firmware(dev, flags); |
186 | } | ||
185 | #else | 187 | #else |
186 | #define get_hp_params_from_firmware(dev, hpp) (-ENODEV) | 188 | #define get_hp_params_from_firmware(dev, hpp) (-ENODEV) |
187 | #define get_hp_hw_control_from_firmware(dev) do { } while (0) | 189 | #define get_hp_hw_control_from_firmware(dev) (0) |
188 | #endif | 190 | #endif |
189 | 191 | ||
190 | struct ctrl_reg { | 192 | struct ctrl_reg { |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 97848654652a..a8cbd039b85b 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
@@ -39,7 +39,7 @@ | |||
39 | int shpchp_debug; | 39 | int shpchp_debug; |
40 | int shpchp_poll_mode; | 40 | int shpchp_poll_mode; |
41 | int shpchp_poll_time; | 41 | int shpchp_poll_time; |
42 | int shpchp_slot_with_bus; | 42 | static int shpchp_slot_with_bus; |
43 | struct workqueue_struct *shpchp_wq; | 43 | struct workqueue_struct *shpchp_wq; |
44 | 44 | ||
45 | #define DRIVER_VERSION "0.4" | 45 | #define DRIVER_VERSION "0.4" |
@@ -68,7 +68,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); | |||
68 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 68 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
69 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 69 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
70 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 70 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
71 | static int get_address (struct hotplug_slot *slot, u32 *value); | ||
72 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 71 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
73 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 72 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
74 | 73 | ||
@@ -81,7 +80,6 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { | |||
81 | .get_attention_status = get_attention_status, | 80 | .get_attention_status = get_attention_status, |
82 | .get_latch_status = get_latch_status, | 81 | .get_latch_status = get_latch_status, |
83 | .get_adapter_status = get_adapter_status, | 82 | .get_adapter_status = get_adapter_status, |
84 | .get_address = get_address, | ||
85 | .get_max_bus_speed = get_max_bus_speed, | 83 | .get_max_bus_speed = get_max_bus_speed, |
86 | .get_cur_bus_speed = get_cur_bus_speed, | 84 | .get_cur_bus_speed = get_cur_bus_speed, |
87 | }; | 85 | }; |
@@ -159,7 +157,8 @@ static int init_slots(struct controller *ctrl) | |||
159 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " | 157 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " |
160 | "slot_device_offset=%x\n", slot->bus, slot->device, | 158 | "slot_device_offset=%x\n", slot->bus, slot->device, |
161 | slot->hp_slot, slot->number, ctrl->slot_device_offset); | 159 | slot->hp_slot, slot->number, ctrl->slot_device_offset); |
162 | retval = pci_hp_register(slot->hotplug_slot); | 160 | retval = pci_hp_register(slot->hotplug_slot, |
161 | ctrl->pci_dev->subordinate, slot->device); | ||
163 | if (retval) { | 162 | if (retval) { |
164 | err("pci_hp_register failed with error %d\n", retval); | 163 | err("pci_hp_register failed with error %d\n", retval); |
165 | if (retval == -EEXIST) | 164 | if (retval == -EEXIST) |
@@ -288,19 +287,8 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) | |||
288 | return 0; | 287 | return 0; |
289 | } | 288 | } |
290 | 289 | ||
291 | static int get_address (struct hotplug_slot *hotplug_slot, u32 *value) | 290 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, |
292 | { | 291 | enum pci_bus_speed *value) |
293 | struct slot *slot = get_slot(hotplug_slot); | ||
294 | struct pci_bus *bus = slot->ctrl->pci_dev->subordinate; | ||
295 | |||
296 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | ||
297 | |||
298 | *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | ||
304 | { | 292 | { |
305 | struct slot *slot = get_slot(hotplug_slot); | 293 | struct slot *slot = get_slot(hotplug_slot); |
306 | int retval; | 294 | int retval; |
@@ -330,13 +318,14 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp | |||
330 | 318 | ||
331 | static int is_shpc_capable(struct pci_dev *dev) | 319 | static int is_shpc_capable(struct pci_dev *dev) |
332 | { | 320 | { |
333 | if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == | 321 | if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == |
334 | PCI_DEVICE_ID_AMD_GOLAM_7450)) | 322 | PCI_DEVICE_ID_AMD_GOLAM_7450)) |
335 | return 1; | 323 | return 1; |
336 | if (pci_find_capability(dev, PCI_CAP_ID_SHPC)) | 324 | if (!pci_find_capability(dev, PCI_CAP_ID_SHPC)) |
337 | return 1; | 325 | return 0; |
338 | 326 | if (get_hp_hw_control_from_firmware(dev)) | |
339 | return 0; | 327 | return 0; |
328 | return 1; | ||
340 | } | 329 | } |
341 | 330 | ||
342 | static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 331 | static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 7d770b2cd889..7a0bff364cd4 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c | |||
@@ -1084,7 +1084,6 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) | |||
1084 | dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __func__, | 1084 | dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __func__, |
1085 | pdev->bus->number, PCI_SLOT(pdev->devfn), | 1085 | pdev->bus->number, PCI_SLOT(pdev->devfn), |
1086 | PCI_FUNC(pdev->devfn), pdev->irq); | 1086 | PCI_FUNC(pdev->devfn), pdev->irq); |
1087 | get_hp_hw_control_from_firmware(pdev); | ||
1088 | 1087 | ||
1089 | /* | 1088 | /* |
1090 | * If this is the first controller to be initialized, | 1089 | * If this is the first controller to be initialized, |