diff options
| -rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 85 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pciehp.h | 10 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 69 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchp.h | 14 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 15 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 1 | ||||
| -rw-r--r-- | include/linux/pci_hotplug.h | 2 |
7 files changed, 105 insertions, 91 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/pciehp.h b/drivers/pci/hotplug/pciehp.h index 084b73efacb3..8492fab800cc 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
| @@ -202,9 +202,13 @@ struct hpc_ops { | |||
| 202 | #include <acpi/actypes.h> | 202 | #include <acpi/actypes.h> |
| 203 | #include <linux/pci-acpi.h> | 203 | #include <linux/pci-acpi.h> |
| 204 | 204 | ||
| 205 | extern int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev); | 205 | static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) |
| 206 | #define pciehp_get_hp_hw_control_from_firmware(dev) \ | 206 | { |
| 207 | pciehp_acpi_get_hp_hw_control_from_firmware(dev) | 207 | u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | |
| 208 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||
| 209 | return acpi_get_hp_hw_control_from_firmware(dev, flags); | ||
| 210 | } | ||
| 211 | |||
| 208 | static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, | 212 | static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, |
| 209 | struct hotplug_params *hpp) | 213 | struct hotplug_params *hpp) |
| 210 | { | 214 | { |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 7e3a3d17c334..a48021d85f22 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
| @@ -1009,75 +1009,6 @@ static struct hpc_ops pciehp_hpc_ops = { | |||
| 1009 | .check_lnk_status = hpc_check_lnk_status, | 1009 | .check_lnk_status = hpc_check_lnk_status, |
| 1010 | }; | 1010 | }; |
| 1011 | 1011 | ||
| 1012 | #ifdef CONFIG_ACPI | ||
| 1013 | int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | ||
| 1014 | { | ||
| 1015 | acpi_status status; | ||
| 1016 | acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); | ||
| 1017 | struct pci_dev *pdev = dev; | ||
| 1018 | struct pci_bus *parent; | ||
| 1019 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 1020 | |||
| 1021 | /* | ||
| 1022 | * Per PCI firmware specification, we should run the ACPI _OSC | ||
| 1023 | * method to get control of hotplug hardware before using it. | ||
| 1024 | * If an _OSC is missing, we look for an OSHP to do the same thing. | ||
| 1025 | * To handle different BIOS behavior, we look for _OSC and OSHP | ||
| 1026 | * within the scope of the hotplug controller and its parents, upto | ||
| 1027 | * the host bridge under which this controller exists. | ||
| 1028 | */ | ||
| 1029 | while (!handle) { | ||
| 1030 | /* | ||
| 1031 | * This hotplug controller was not listed in the ACPI name | ||
| 1032 | * space at all. Try to get acpi handle of parent pci bus. | ||
| 1033 | */ | ||
| 1034 | if (!pdev || !pdev->bus->parent) | ||
| 1035 | break; | ||
| 1036 | parent = pdev->bus->parent; | ||
| 1037 | dbg("Could not find %s in acpi namespace, trying parent\n", | ||
| 1038 | pci_name(pdev)); | ||
| 1039 | if (!parent->self) | ||
| 1040 | /* Parent must be a host bridge */ | ||
| 1041 | handle = acpi_get_pci_rootbridge_handle( | ||
| 1042 | pci_domain_nr(parent), | ||
| 1043 | parent->number); | ||
| 1044 | else | ||
| 1045 | handle = DEVICE_ACPI_HANDLE( | ||
| 1046 | &(parent->self->dev)); | ||
| 1047 | pdev = parent->self; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | while (handle) { | ||
| 1051 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); | ||
| 1052 | dbg("Trying to get hotplug control for %s \n", | ||
| 1053 | (char *)string.pointer); | ||
| 1054 | status = pci_osc_control_set(handle, | ||
| 1055 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | | ||
| 1056 | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); | ||
| 1057 | if (status == AE_NOT_FOUND) | ||
| 1058 | status = acpi_run_oshp(handle); | ||
| 1059 | if (ACPI_SUCCESS(status)) { | ||
| 1060 | dbg("Gained control for hotplug HW for pci %s (%s)\n", | ||
| 1061 | pci_name(dev), (char *)string.pointer); | ||
| 1062 | kfree(string.pointer); | ||
| 1063 | return 0; | ||
| 1064 | } | ||
| 1065 | if (acpi_root_bridge(handle)) | ||
| 1066 | break; | ||
| 1067 | chandle = handle; | ||
| 1068 | status = acpi_get_parent(chandle, &handle); | ||
| 1069 | if (ACPI_FAILURE(status)) | ||
| 1070 | break; | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | dbg("Cannot get control of hotplug hardware for pci %s\n", | ||
| 1074 | pci_name(dev)); | ||
| 1075 | |||
| 1076 | kfree(string.pointer); | ||
| 1077 | return -1; | ||
| 1078 | } | ||
| 1079 | #endif | ||
| 1080 | |||
| 1081 | static int pcie_init_hardware_part1(struct controller *ctrl, | 1012 | static int pcie_init_hardware_part1(struct controller *ctrl, |
| 1082 | struct pcie_device *dev) | 1013 | struct pcie_device *dev) |
| 1083 | { | 1014 | { |
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 0066b0be0928..df41ecc4e7fc 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
| @@ -330,13 +330,14 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp | |||
| 330 | 330 | ||
| 331 | static int is_shpc_capable(struct pci_dev *dev) | 331 | static int is_shpc_capable(struct pci_dev *dev) |
| 332 | { | 332 | { |
| 333 | if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == | 333 | if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == |
| 334 | PCI_DEVICE_ID_AMD_GOLAM_7450)) | 334 | PCI_DEVICE_ID_AMD_GOLAM_7450)) |
| 335 | return 1; | 335 | return 1; |
| 336 | if (pci_find_capability(dev, PCI_CAP_ID_SHPC)) | 336 | if (!pci_find_capability(dev, PCI_CAP_ID_SHPC)) |
| 337 | return 1; | 337 | return 0; |
| 338 | 338 | if (get_hp_hw_control_from_firmware(dev)) | |
| 339 | return 0; | 339 | return 0; |
| 340 | return 1; | ||
| 340 | } | 341 | } |
| 341 | 342 | ||
| 342 | static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 343 | 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, |
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 8f67e8f2a3cc..dbdcd1ad3c6a 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h | |||
| @@ -227,9 +227,9 @@ struct hotplug_params { | |||
| 227 | #include <acpi/acpi.h> | 227 | #include <acpi/acpi.h> |
| 228 | #include <acpi/acpi_bus.h> | 228 | #include <acpi/acpi_bus.h> |
| 229 | #include <acpi/actypes.h> | 229 | #include <acpi/actypes.h> |
| 230 | extern acpi_status acpi_run_oshp(acpi_handle handle); | ||
| 231 | extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, | 230 | extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, |
| 232 | struct hotplug_params *hpp); | 231 | struct hotplug_params *hpp); |
| 232 | int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); | ||
| 233 | int acpi_root_bridge(acpi_handle handle); | 233 | int acpi_root_bridge(acpi_handle handle); |
| 234 | #endif | 234 | #endif |
| 235 | #endif | 235 | #endif |
