linux/drivers/pci/pci-acpi.c

// SPDX-License-Identifier: GPL-2.0
/*
 * PCI support in ACPI
 *
 * Copyright (C) 2005 David Shaohua Li <[email protected]>
 * Copyright (C) 2004 Tom Long Nguyen <[email protected]>
 * Copyright (C) 2004 Intel Corp.
 */

#include <linux/delay.h>
#include <linux/init.h>
#include <linux/irqdomain.h>
#include <linux/pci.h>
#include <linux/msi.h>
#include <linux/pci_hotplug.h>
#include <linux/module.h>
#include <linux/pci-acpi.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/rwsem.h>
#include "pci.h"

/*
 * The GUID is defined in the PCI Firmware Specification available
 * here to PCI-SIG members:
 * https://members.pcisig.com/wg/PCI-SIG/document/15350
 */
const guid_t pci_acpi_dsm_guid =;

#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64)
static int acpi_get_rc_addr(struct acpi_device *adev, struct resource *res)
{
	struct device *dev = &adev->dev;
	struct resource_entry *entry;
	struct list_head list;
	unsigned long flags;
	int ret;

	INIT_LIST_HEAD(&list);
	flags = IORESOURCE_MEM;
	ret = acpi_dev_get_resources(adev, &list,
				     acpi_dev_filter_resource_type_cb,
				     (void *) flags);
	if (ret < 0) {
		dev_err(dev, "failed to parse _CRS method, error code %d\n",
			ret);
		return ret;
	}

	if (ret == 0) {
		dev_err(dev, "no IO and memory resources present in _CRS\n");
		return -EINVAL;
	}

	entry = list_first_entry(&list, struct resource_entry, node);
	*res = *entry->res;
	acpi_dev_free_resource_list(&list);
	return 0;
}

static acpi_status acpi_match_rc(acpi_handle handle, u32 lvl, void *context,
				 void **retval)
{
	u16 *segment = context;
	unsigned long long uid;
	acpi_status status;

	status = acpi_evaluate_integer(handle, METHOD_NAME__UID, NULL, &uid);
	if (ACPI_FAILURE(status) || uid != *segment)
		return AE_CTRL_DEPTH;

	*(acpi_handle *)retval = handle;
	return AE_CTRL_TERMINATE;
}

int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
			  struct resource *res)
{
	struct acpi_device *adev;
	acpi_status status;
	acpi_handle handle;
	int ret;

	status = acpi_get_devices(hid, acpi_match_rc, &segment, &handle);
	if (ACPI_FAILURE(status)) {
		dev_err(dev, "can't find _HID %s device to locate resources\n",
			hid);
		return -ENODEV;
	}

	adev = acpi_fetch_acpi_dev(handle);
	if (!adev)
		return -ENODEV;

	ret = acpi_get_rc_addr(adev, res);
	if (ret) {
		dev_err(dev, "can't get resource from %s\n",
			dev_name(&adev->dev));
		return ret;
	}

	return 0;
}
#endif

phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
{}

bool pci_acpi_preserve_config(struct pci_host_bridge *host_bridge)
{}

/* _HPX PCI Setting Record (Type 0); same as _HPP */
struct hpx_type0 {};

static struct hpx_type0 pci_default_type0 =;

static void program_hpx_type0(struct pci_dev *dev, struct hpx_type0 *hpx)
{}

static acpi_status decode_type0_hpx_record(union acpi_object *record,
					   struct hpx_type0 *hpx0)
{}

/* _HPX PCI-X Setting Record (Type 1) */
struct hpx_type1 {};

static void program_hpx_type1(struct pci_dev *dev, struct hpx_type1 *hpx)
{}

static acpi_status decode_type1_hpx_record(union acpi_object *record,
					   struct hpx_type1 *hpx1)
{}

static bool pcie_root_rcb_set(struct pci_dev *dev)
{}

/* _HPX PCI Express Setting Record (Type 2) */
struct hpx_type2 {};

static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx)
{}

static acpi_status decode_type2_hpx_record(union acpi_object *record,
					   struct hpx_type2 *hpx2)
{}

/* _HPX PCI Express Setting Record (Type 3) */
struct hpx_type3 {};

enum hpx_type3_dev_type {};

static u16 hpx3_device_type(struct pci_dev *dev)
{}

enum hpx_type3_fn_type {};

static u8 hpx3_function_type(struct pci_dev *dev)
{}

static bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id)
{}

enum hpx_type3_cfg_loc {};

static void program_hpx_type3_register(struct pci_dev *dev,
				       const struct hpx_type3 *reg)
{}

static void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx)
{}

static void parse_hpx3_register(struct hpx_type3 *hpx3_reg,
				union acpi_object *reg_fields)
{}

static acpi_status program_type3_hpx_record(struct pci_dev *dev,
					   union acpi_object *record)
{}

static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle)
{}

static acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle)
{}

/* pci_acpi_program_hp_params
 *
 * @dev - the pci_dev for which we want parameters
 */
int pci_acpi_program_hp_params(struct pci_dev *dev)
{}

/**
 * pciehp_is_native - Check whether a hotplug port is handled by the OS
 * @bridge: Hotplug port to check
 *
 * Returns true if the given @bridge is handled by the native PCIe hotplug
 * driver.
 */
bool pciehp_is_native(struct pci_dev *bridge)
{}

/**
 * shpchp_is_native - Check whether a hotplug port is handled by the OS
 * @bridge: Hotplug port to check
 *
 * Returns true if the given @bridge is handled by the native SHPC hotplug
 * driver.
 */
bool shpchp_is_native(struct pci_dev *bridge)
{}

/**
 * pci_acpi_wake_bus - Root bus wakeup notification fork function.
 * @context: Device wakeup context.
 */
static void pci_acpi_wake_bus(struct acpi_device_wakeup_context *context)
{}

/**
 * pci_acpi_wake_dev - PCI device wakeup notification work function.
 * @context: Device wakeup context.
 */
static void pci_acpi_wake_dev(struct acpi_device_wakeup_context *context)
{}

/**
 * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus.
 * @dev: PCI root bridge ACPI device.
 */
acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev)
{}

/**
 * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device.
 * @dev: ACPI device to add the notifier for.
 * @pci_dev: PCI device to check for the PME status if an event is signaled.
 */
acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
				     struct pci_dev *pci_dev)
{}

/*
 * _SxD returns the D-state with the highest power
 * (lowest D-state number) supported in the S-state "x".
 *
 * If the devices does not have a _PRW
 * (Power Resources for Wake) supporting system wakeup from "x"
 * then the OS is free to choose a lower power (higher number
 * D-state) than the return value from _SxD.
 *
 * But if _PRW is enabled at S-state "x", the OS
 * must not choose a power lower than _SxD --
 * unless the device has an _SxW method specifying
 * the lowest power (highest D-state number) the device
 * may enter while still able to wake the system.
 *
 * ie. depending on global OS policy:
 *
 * if (_PRW at S-state x)
 *	choose from highest power _SxD to lowest power _SxW
 * else // no _PRW at S-state x
 *	choose highest power _SxD or any lower power
 */

pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
{}

static struct acpi_device *acpi_pci_find_companion(struct device *dev);

void pci_set_acpi_fwnode(struct pci_dev *dev)
{}

/**
 * pci_dev_acpi_reset - do a function level reset using _RST method
 * @dev: device to reset
 * @probe: if true, return 0 if device supports _RST
 */
int pci_dev_acpi_reset(struct pci_dev *dev, bool probe)
{}

bool acpi_pci_power_manageable(struct pci_dev *dev)
{}

bool acpi_pci_bridge_d3(struct pci_dev *dev)
{}

static void acpi_pci_config_space_access(struct pci_dev *dev, bool enable)
{}

int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{}

pci_power_t acpi_pci_get_power_state(struct pci_dev *dev)
{}

void acpi_pci_refresh_power_state(struct pci_dev *dev)
{}

static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable)
{}

int acpi_pci_wakeup(struct pci_dev *dev, bool enable)
{}

bool acpi_pci_need_resume(struct pci_dev *dev)
{}

void acpi_pci_add_bus(struct pci_bus *bus)
{}

void acpi_pci_remove_bus(struct pci_bus *bus)
{}

/* ACPI bus type */


static DECLARE_RWSEM(pci_acpi_companion_lookup_sem);
static struct acpi_device *(*pci_acpi_find_companion_hook)(struct pci_dev *);

/**
 * pci_acpi_set_companion_lookup_hook - Set ACPI companion lookup callback.
 * @func: ACPI companion lookup callback pointer or NULL.
 *
 * Set a special ACPI companion lookup callback for PCI devices whose companion
 * objects in the ACPI namespace have _ADR with non-standard bus-device-function
 * encodings.
 *
 * Return 0 on success or a negative error code on failure (in which case no
 * changes are made).
 *
 * The caller is responsible for the appropriate ordering of the invocations of
 * this function with respect to the enumeration of the PCI devices needing the
 * callback installed by it.
 */
int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *))
{}
EXPORT_SYMBOL_GPL();

/**
 * pci_acpi_clear_companion_lookup_hook - Clear ACPI companion lookup callback.
 *
 * Clear the special ACPI companion lookup callback previously set by
 * pci_acpi_set_companion_lookup_hook().  Block until the last running instance
 * of the callback returns before clearing it.
 *
 * The caller is responsible for the appropriate ordering of the invocations of
 * this function with respect to the enumeration of the PCI devices needing the
 * callback cleared by it.
 */
void pci_acpi_clear_companion_lookup_hook(void)
{}
EXPORT_SYMBOL_GPL();

static struct acpi_device *acpi_pci_find_companion(struct device *dev)
{}

/**
 * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI
 * @pdev: the PCI device whose delay is to be updated
 * @handle: ACPI handle of this device
 *
 * Update the d3hot_delay and d3cold_delay of a PCI device from the ACPI _DSM
 * control method of either the device itself or the PCI host bridge.
 *
 * Function 8, "Reset Delay," applies to the entire hierarchy below a PCI
 * host bridge.  If it returns one, the OS may assume that all devices in
 * the hierarchy have already completed power-on reset delays.
 *
 * Function 9, "Device Readiness Durations," applies only to the object
 * where it is located.  It returns delay durations required after various
 * events if the device requires less time than the spec requires.  Delays
 * from this function take precedence over the Reset Delay function.
 *
 * These _DSM functions are defined by the draft ECN of January 28, 2014,
 * titled "ACPI additions for FW latency optimizations."
 */
static void pci_acpi_optimize_delay(struct pci_dev *pdev,
				    acpi_handle handle)
{}

static void pci_acpi_set_external_facing(struct pci_dev *dev)
{}

void pci_acpi_setup(struct device *dev, struct acpi_device *adev)
{}

void pci_acpi_cleanup(struct device *dev, struct acpi_device *adev)
{}

static struct fwnode_handle *(*pci_msi_get_fwnode_cb)(struct device *dev);

/**
 * pci_msi_register_fwnode_provider - Register callback to retrieve fwnode
 * @fn:       Callback matching a device to a fwnode that identifies a PCI
 *            MSI domain.
 *
 * This should be called by irqchip driver, which is the parent of
 * the MSI domain to provide callback interface to query fwnode.
 */
void
pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *))
{}

/**
 * pci_host_bridge_acpi_msi_domain - Retrieve MSI domain of a PCI host bridge
 * @bus:      The PCI host bridge bus.
 *
 * This function uses the callback function registered by
 * pci_msi_register_fwnode_provider() to retrieve the irq_domain with
 * type DOMAIN_BUS_PCI_MSI of the specified host bridge bus.
 * This returns NULL on error or when the domain is not found.
 */
struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
{}

static int __init acpi_pci_init(void)
{}
arch_initcall(acpi_pci_init);