pcie_pme_acpi.c 1.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
 * PCIe Native PME support, ACPI-related part
 *
 * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License V2.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */

#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/pci-acpi.h>
#include <linux/pcieport_if.h>

/**
 * pcie_pme_acpi_setup - Request the ACPI BIOS to release control over PCIe PME.
 * @srv - PCIe PME service for a root port or event collector.
 *
 * Invoked when the PCIe bus type loads PCIe PME service driver.  To avoid
 * conflict with the BIOS PCIe support requires the BIOS to yield PCIe PME
 * control to the kernel.
 */
int pcie_pme_acpi_setup(struct pcie_device *srv)
{
	acpi_status status = AE_NOT_FOUND;
	struct pci_dev *port = srv->port;
	acpi_handle handle;
31
	u32 flags;
32 33 34 35 36 37 38 39 40 41 42
	int error = 0;

	if (acpi_pci_disabled)
		return -ENOSYS;

	dev_info(&port->dev, "Requesting control of PCIe PME from ACPI BIOS\n");

	handle = acpi_find_root_bridge_handle(port);
	if (!handle)
		return -EINVAL;

43 44 45 46
	flags = OSC_PCI_EXPRESS_PME_CONTROL |
		OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL;

	status = acpi_pci_osc_control_set(handle, &flags, flags);
47 48 49 50 51 52 53 54 55 56
	if (ACPI_FAILURE(status)) {
		dev_info(&port->dev,
			"Failed to receive control of PCIe PME service: %s\n",
			(status == AE_SUPPORT || status == AE_NOT_FOUND) ?
			"no _OSC support" : "ACPI _OSC failed");
		error = -ENODEV;
	}

	return error;
}