Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5468d5a6 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/misc' into next

* pci/misc:
  PCI: Read capability list as dwords, not bytes
  PCI: Don't clear ASPM bits when the FADT declares it's unsupported
  PCI: Clarify policy for vendor IDs in pci.txt
  PCI/ACPI: Optimize device state transition delays
  PCI: Export pci_find_host_bridge() for use inside PCI core
  PCI: Make a shareable UUID for PCI firmware ACPI _DSM
  PCI: Fix typo in Thunderbolt kernel message
parents 4dd1f579 55db3208
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -564,14 +564,14 @@ to be handled by platform and generic code, not individual drivers.
8. Vendor and device identifications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

One is not required to add new device ids to include/linux/pci_ids.h.
Please add PCI_VENDOR_ID_xxx for vendors and a hex constant for device ids.
Do not add new device or vendor IDs to include/linux/pci_ids.h unless they
are shared across multiple drivers.  You can add private definitions in
your driver if they're helpful, or just use plain hex constants.

PCI_VENDOR_ID_xxx constants are re-used. The device ids are arbitrary
hex numbers (vendor controlled) and normally used only in a single
location, the pci_device_id table.
The device IDs are arbitrary hex numbers (vendor controlled) and normally used
only in a single location, the pci_device_id table.

Please DO submit new vendor/device ids to pciids.sourceforge.net project.
Please DO submit new vendor/device IDs to http://pciids.sourceforge.net/.



+8 −11
Original line number Diff line number Diff line
@@ -423,8 +423,7 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req)
}
EXPORT_SYMBOL(acpi_pci_osc_control_set);

static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
				 int *clear_aspm)
static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
{
	u32 support, control, requested;
	acpi_status status;
@@ -495,10 +494,12 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
		decode_osc_control(root, "OS now controls", control);
		if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
			/*
			 * We have ASPM control, but the FADT indicates
			 * that it's unsupported. Clear it.
			 * We have ASPM control, but the FADT indicates that
			 * it's unsupported. Leave existing configuration
			 * intact and prevent the OS from touching it.
			 */
			*clear_aspm = 1;
			dev_info(&device->dev, "FADT indicates ASPM is unsupported, using BIOS configuration\n");
			*no_aspm = 1;
		}
	} else {
		decode_osc_control(root, "OS requested", requested);
@@ -525,7 +526,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
	int result;
	struct acpi_pci_root *root;
	acpi_handle handle = device->handle;
	int no_aspm = 0, clear_aspm = 0;
	int no_aspm = 0;
	bool hotadd = system_state != SYSTEM_BOOTING;

	root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
@@ -584,7 +585,7 @@ static int acpi_pci_root_add(struct acpi_device *device,

	root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle);

	negotiate_os_control(root, &no_aspm, &clear_aspm);
	negotiate_os_control(root, &no_aspm);

	/*
	 * TBD: Need PCI interface for enumeration/configuration of roots.
@@ -607,10 +608,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
		goto remove_dmar;
	}

	if (clear_aspm) {
		dev_info(&device->dev, "Disabling ASPM (FADT indicates it is unsupported)\n");
		pcie_clear_aspm(root->bus);
	}
	if (no_aspm)
		pcie_no_aspm();

+3 −3
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
	return bus;
}

static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus)
{
	struct pci_bus *root_bus = find_pci_root_bus(bus);

@@ -48,7 +48,7 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
			     struct resource *res)
{
	struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
	struct resource_entry *window;
	resource_size_t offset = 0;

@@ -73,7 +73,7 @@ static bool region_contains(struct pci_bus_region *region1,
void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
			     struct pci_bus_region *region)
{
	struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
	struct resource_entry *window;
	resource_size_t offset = 0;

+83 −0
Original line number Diff line number Diff line
@@ -18,6 +18,15 @@
#include <linux/pm_qos.h>
#include "pci.h"

/*
 * The UUID is defined in the PCI Firmware Specification available here:
 * https://www.pcisig.com/members/downloads/pcifw_r3_1_13Dec10.pdf
 */
const u8 pci_acpi_dsm_uuid[] = {
	0xd0, 0x37, 0xc9, 0xe5, 0x53, 0x35, 0x7a, 0x4d,
	0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d
};

phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
{
	acpi_status status = AE_NOT_EXIST;
@@ -528,11 +537,32 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {

void acpi_pci_add_bus(struct pci_bus *bus)
{
	union acpi_object *obj;
	struct pci_host_bridge *bridge;

	if (acpi_pci_disabled || !bus->bridge)
		return;

	acpi_pci_slot_enumerate(bus);
	acpiphp_enumerate_slots(bus);

	/*
	 * For a host bridge, check its _DSM for function 8 and if
	 * that is available, mark it in pci_host_bridge.
	 */
	if (!pci_is_root_bus(bus))
		return;

	obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), pci_acpi_dsm_uuid, 3,
				RESET_DELAY_DSM, NULL);
	if (!obj)
		return;

	if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) {
		bridge = pci_find_host_bridge(bus);
		bridge->ignore_reset_delay = 1;
	}
	ACPI_FREE(obj);
}

void acpi_pci_remove_bus(struct pci_bus *bus)
@@ -558,6 +588,57 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
				      check_children);
}

/**
 * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI
 * @pdev: the PCI device whose delay is to be updated
 * @adev: the companion ACPI device of this PCI device
 *
 * Update the d3_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)
{
	struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
	int value;
	union acpi_object *obj, *elements;

	if (bridge->ignore_reset_delay)
		pdev->d3cold_delay = 0;

	obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 3,
				FUNCTION_DELAY_DSM, NULL);
	if (!obj)
		return;

	if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) {
		elements = obj->package.elements;
		if (elements[0].type == ACPI_TYPE_INTEGER) {
			value = (int)elements[0].integer.value / 1000;
			if (value < PCI_PM_D3COLD_WAIT)
				pdev->d3cold_delay = value;
		}
		if (elements[3].type == ACPI_TYPE_INTEGER) {
			value = (int)elements[3].integer.value / 1000;
			if (value < PCI_PM_D3_WAIT)
				pdev->d3_delay = value;
		}
	}
	ACPI_FREE(obj);
}

static void pci_acpi_setup(struct device *dev)
{
	struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -566,6 +647,8 @@ static void pci_acpi_setup(struct device *dev)
	if (!adev)
		return;

	pci_acpi_optimize_delay(pci_dev, adev->handle);

	pci_acpi_add_pm_notifier(adev, pci_dev);
	if (!adev->wakeup.flags.valid)
		return;
+2 −9
Original line number Diff line number Diff line
@@ -31,8 +31,6 @@
#include <linux/pci-acpi.h>
#include "pci.h"

#define	DEVICE_LABEL_DSM	0x07

#ifdef CONFIG_DMI
enum smbios_attr_enum {
	SMBIOS_ATTR_NONE = 0,
@@ -148,11 +146,6 @@ static inline void pci_remove_smbiosname_file(struct pci_dev *pdev)
#endif

#ifdef CONFIG_ACPI
static const char device_label_dsm_uuid[] = {
	0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D,
	0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D
};

enum acpi_attr_enum {
	ACPI_ATTR_LABEL_SHOW,
	ACPI_ATTR_INDEX_SHOW,
@@ -179,7 +172,7 @@ static int dsm_get_label(struct device *dev, char *buf,
	if (!handle)
		return -1;

	obj = acpi_evaluate_dsm(handle, device_label_dsm_uuid, 0x2,
	obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 0x2,
				DEVICE_LABEL_DSM, NULL);
	if (!obj)
		return -1;
@@ -219,7 +212,7 @@ static bool device_has_dsm(struct device *dev)
	if (!handle)
		return false;

	return !!acpi_check_dsm(handle, device_label_dsm_uuid, 0x2,
	return !!acpi_check_dsm(handle, pci_acpi_dsm_uuid, 0x2,
				1 << DEVICE_LABEL_DSM);
}

Loading