/** * aer_osc_setup - run ACPI _OSC method * @pciedev: pcie_device which AER is being enabled on * * @return: Zero on success. Nonzero otherwise. * * Invoked when PCIE bus loads AER service driver. To avoid conflict with * BIOS AER support requires BIOS to yield AER control to OS native driver. **/ int aer_osc_setup(struct pcie_device *pciedev) { acpi_status status = AE_NOT_FOUND; struct pci_dev *pdev = pciedev->port; acpi_handle handle = NULL; if (acpi_pci_disabled) return -1; /* Find root host bridge */ while (pdev->bus->self) pdev = pdev->bus->self; handle = acpi_get_pci_rootbridge_handle( pci_domain_nr(pdev->bus), pdev->bus->number); if (handle) { pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); } if (ACPI_FAILURE(status)) { printk(KERN_DEBUG "AER service couldn't init device %s - %s\n", pciedev->device.bus_id, (status == AE_SUPPORT || status == AE_NOT_FOUND) ? "no _OSC support" : "Run ACPI _OSC fails"); return -1; } return 0; }
int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) { acpi_status status; acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); struct pci_dev *pdev = dev; u8 *path_name; /* * Per PCI firmware specification, we should run the ACPI _OSC * method to get control of hotplug hardware before using it. * If an _OSC is missing, we look for an OSHP to do the same thing. * To handle different BIOS behavior, we look for _OSC and OSHP * within the scope of the hotplug controller and its parents, upto * the host bridge under which this controller exists. */ while (!handle) { /* * This hotplug controller was not listed in the ACPI name * space at all. Try to get acpi handle of parent pci bus. */ if (!pdev || !pdev->bus->parent) break; dbg("Could not find %s in acpi namespace, trying parent\n", pci_name(pdev)); if (!pdev->bus->parent->self) /* Parent must be a host bridge */ handle = acpi_get_pci_rootbridge_handle( pci_domain_nr(pdev->bus->parent), pdev->bus->parent->number); else handle = DEVICE_ACPI_HANDLE( &(pdev->bus->parent->self->dev)); pdev = pdev->bus->parent->self; } while (handle) { path_name = acpi_path_name(handle); dbg("Trying to get hotplug control for %s \n", path_name); status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); if (status == AE_NOT_FOUND) status = acpi_run_oshp(handle); if (ACPI_SUCCESS(status)) { dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev), path_name); return 0; } if (is_root_bridge(handle)) break; chandle = handle; status = acpi_get_parent(chandle, &handle); if (ACPI_FAILURE(status)) break; } err("Cannot get control of hotplug hardware for pci %s\n", pci_name(dev)); return -1; }
static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) { int num; unsigned int seg, bus; /* * The string should be the same as root bridge's name * Please look at 'pci_scan_bus_parented' */ num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus); if (num != 2) return -ENODEV; *handle = acpi_get_pci_rootbridge_handle(seg, bus); if (!*handle) return -ENODEV; return 0; }
/* acpi_get_hp_params_from_firmware * * @bus - the pci_bus of the bus on which the device is newly added * @hpp - allocated by the caller */ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, struct hotplug_params *hpp) { acpi_status status = AE_NOT_FOUND; acpi_handle handle, phandle; struct pci_bus *pbus = bus; struct pci_dev *pdev; do { pdev = pbus->self; if (!pdev) { handle = acpi_get_pci_rootbridge_handle( pci_domain_nr(pbus), pbus->number); break; } handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); pbus = pbus->parent; } while (!handle); /* * _HPP settings apply to all child buses, until another _HPP is * encountered. If we don't find an _HPP for the input pci dev, * look for it in the parent device scope since that would apply to * this pci dev. If we don't find any _HPP, use hardcoded defaults */ while (handle) { status = acpi_run_hpx(handle, hpp); if (ACPI_SUCCESS(status)) break; status = acpi_run_hpp(handle, hpp); if (ACPI_SUCCESS(status)) break; if (acpi_root_bridge(handle)) break; status = acpi_get_parent(handle, &phandle); if (ACPI_FAILURE(status)) break; handle = phandle; } return status; }