diff options
Diffstat (limited to 'drivers/pci/hotplug/pciehp_hpc.c')
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 77e530321de2..6c14d9e46b2e 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -38,7 +38,10 @@ | |||
38 | 38 | ||
39 | #include "../pci.h" | 39 | #include "../pci.h" |
40 | #include "pciehp.h" | 40 | #include "pciehp.h" |
41 | 41 | #include <acpi/acpi.h> | |
42 | #include <acpi/acpi_bus.h> | ||
43 | #include <acpi/actypes.h> | ||
44 | #include <linux/pci-acpi.h> | ||
42 | #ifdef DEBUG | 45 | #ifdef DEBUG |
43 | #define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ | 46 | #define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ |
44 | #define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ | 47 | #define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ |
@@ -1236,6 +1239,76 @@ static struct hpc_ops pciehp_hpc_ops = { | |||
1236 | .check_lnk_status = hpc_check_lnk_status, | 1239 | .check_lnk_status = hpc_check_lnk_status, |
1237 | }; | 1240 | }; |
1238 | 1241 | ||
1242 | #ifdef CONFIG_ACPI | ||
1243 | int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | ||
1244 | { | ||
1245 | acpi_status status; | ||
1246 | acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); | ||
1247 | struct pci_dev *pdev = dev; | ||
1248 | struct pci_bus *parent; | ||
1249 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1250 | |||
1251 | /* | ||
1252 | * Per PCI firmware specification, we should run the ACPI _OSC | ||
1253 | * method to get control of hotplug hardware before using it. | ||
1254 | * If an _OSC is missing, we look for an OSHP to do the same thing. | ||
1255 | * To handle different BIOS behavior, we look for _OSC and OSHP | ||
1256 | * within the scope of the hotplug controller and its parents, upto | ||
1257 | * the host bridge under which this controller exists. | ||
1258 | */ | ||
1259 | while (!handle) { | ||
1260 | /* | ||
1261 | * This hotplug controller was not listed in the ACPI name | ||
1262 | * space at all. Try to get acpi handle of parent pci bus. | ||
1263 | */ | ||
1264 | if (!pdev || !pdev->bus->parent) | ||
1265 | break; | ||
1266 | parent = pdev->bus->parent; | ||
1267 | dbg("Could not find %s in acpi namespace, trying parent\n", | ||
1268 | pci_name(pdev)); | ||
1269 | if (!parent->self) | ||
1270 | /* Parent must be a host bridge */ | ||
1271 | handle = acpi_get_pci_rootbridge_handle( | ||
1272 | pci_domain_nr(parent), | ||
1273 | parent->number); | ||
1274 | else | ||
1275 | handle = DEVICE_ACPI_HANDLE( | ||
1276 | &(parent->self->dev)); | ||
1277 | pdev = parent->self; | ||
1278 | } | ||
1279 | |||
1280 | while (handle) { | ||
1281 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); | ||
1282 | dbg("Trying to get hotplug control for %s \n", | ||
1283 | (char *)string.pointer); | ||
1284 | status = pci_osc_control_set(handle, | ||
1285 | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); | ||
1286 | if (status == AE_NOT_FOUND) | ||
1287 | status = acpi_run_oshp(handle); | ||
1288 | if (ACPI_SUCCESS(status)) { | ||
1289 | dbg("Gained control for hotplug HW for pci %s (%s)\n", | ||
1290 | pci_name(dev), (char *)string.pointer); | ||
1291 | acpi_os_free(string.pointer); | ||
1292 | return 0; | ||
1293 | } | ||
1294 | if (acpi_root_bridge(handle)) | ||
1295 | break; | ||
1296 | chandle = handle; | ||
1297 | status = acpi_get_parent(chandle, &handle); | ||
1298 | if (ACPI_FAILURE(status)) | ||
1299 | break; | ||
1300 | } | ||
1301 | |||
1302 | err("Cannot get control of hotplug hardware for pci %s\n", | ||
1303 | pci_name(dev)); | ||
1304 | |||
1305 | acpi_os_free(string.pointer); | ||
1306 | return -1; | ||
1307 | } | ||
1308 | #endif | ||
1309 | |||
1310 | |||
1311 | |||
1239 | int pcie_init(struct controller * ctrl, struct pcie_device *dev) | 1312 | int pcie_init(struct controller * ctrl, struct pcie_device *dev) |
1240 | { | 1313 | { |
1241 | struct php_ctlr_state_s *php_ctlr, *p; | 1314 | struct php_ctlr_state_s *php_ctlr, *p; |
@@ -1334,7 +1407,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1334 | if (pci_enable_device(pdev)) | 1407 | if (pci_enable_device(pdev)) |
1335 | goto abort_free_ctlr; | 1408 | goto abort_free_ctlr; |
1336 | 1409 | ||
1337 | init_MUTEX(&ctrl->crit_sect); | 1410 | mutex_init(&ctrl->crit_sect); |
1338 | /* setup wait queue */ | 1411 | /* setup wait queue */ |
1339 | init_waitqueue_head(&ctrl->queue); | 1412 | init_waitqueue_head(&ctrl->queue); |
1340 | 1413 | ||