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

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
...@@ -564,14 +564,14 @@ to be handled by platform and generic code, not individual drivers. ...@@ -564,14 +564,14 @@ to be handled by platform and generic code, not individual drivers.
8. Vendor and device identifications 8. Vendor and device identifications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
One is not required to add new device ids to include/linux/pci_ids.h. Do not add new device or vendor IDs to include/linux/pci_ids.h unless they
Please add PCI_VENDOR_ID_xxx for vendors and a hex constant for device ids. 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 The device IDs are arbitrary hex numbers (vendor controlled) and normally used
hex numbers (vendor controlled) and normally used only in a single only in a single location, the pci_device_id table.
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/.
......
...@@ -423,8 +423,7 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req) ...@@ -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); EXPORT_SYMBOL(acpi_pci_osc_control_set);
static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
int *clear_aspm)
{ {
u32 support, control, requested; u32 support, control, requested;
acpi_status status; acpi_status status;
...@@ -495,10 +494,12 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, ...@@ -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); decode_osc_control(root, "OS now controls", control);
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
/* /*
* We have ASPM control, but the FADT indicates * We have ASPM control, but the FADT indicates that
* that it's unsupported. Clear it. * 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 { } else {
decode_osc_control(root, "OS requested", requested); decode_osc_control(root, "OS requested", requested);
...@@ -525,7 +526,7 @@ static int acpi_pci_root_add(struct acpi_device *device, ...@@ -525,7 +526,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
int result; int result;
struct acpi_pci_root *root; struct acpi_pci_root *root;
acpi_handle handle = device->handle; acpi_handle handle = device->handle;
int no_aspm = 0, clear_aspm = 0; int no_aspm = 0;
bool hotadd = system_state != SYSTEM_BOOTING; bool hotadd = system_state != SYSTEM_BOOTING;
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
...@@ -584,7 +585,7 @@ static int acpi_pci_root_add(struct acpi_device *device, ...@@ -584,7 +585,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle); 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. * TBD: Need PCI interface for enumeration/configuration of roots.
...@@ -607,10 +608,6 @@ static int acpi_pci_root_add(struct acpi_device *device, ...@@ -607,10 +608,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
goto remove_dmar; 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) if (no_aspm)
pcie_no_aspm(); pcie_no_aspm();
......
...@@ -16,7 +16,7 @@ static struct pci_bus *find_pci_root_bus(struct pci_bus *bus) ...@@ -16,7 +16,7 @@ static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
return 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); 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, ...@@ -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, void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
struct resource *res) 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; struct resource_entry *window;
resource_size_t offset = 0; resource_size_t offset = 0;
...@@ -73,7 +73,7 @@ static bool region_contains(struct pci_bus_region *region1, ...@@ -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, void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
struct pci_bus_region *region) 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; struct resource_entry *window;
resource_size_t offset = 0; resource_size_t offset = 0;
......
...@@ -18,6 +18,15 @@ ...@@ -18,6 +18,15 @@
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include "pci.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) phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
{ {
acpi_status status = AE_NOT_EXIST; acpi_status status = AE_NOT_EXIST;
...@@ -528,11 +537,32 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = { ...@@ -528,11 +537,32 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
void acpi_pci_add_bus(struct pci_bus *bus) void acpi_pci_add_bus(struct pci_bus *bus)
{ {
union acpi_object *obj;
struct pci_host_bridge *bridge;
if (acpi_pci_disabled || !bus->bridge) if (acpi_pci_disabled || !bus->bridge)
return; return;
acpi_pci_slot_enumerate(bus); acpi_pci_slot_enumerate(bus);
acpiphp_enumerate_slots(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) void acpi_pci_remove_bus(struct pci_bus *bus)
...@@ -558,6 +588,57 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev) ...@@ -558,6 +588,57 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
check_children); 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) static void pci_acpi_setup(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_dev *pci_dev = to_pci_dev(dev);
...@@ -566,6 +647,8 @@ static void pci_acpi_setup(struct device *dev) ...@@ -566,6 +647,8 @@ static void pci_acpi_setup(struct device *dev)
if (!adev) if (!adev)
return; return;
pci_acpi_optimize_delay(pci_dev, adev->handle);
pci_acpi_add_pm_notifier(adev, pci_dev); pci_acpi_add_pm_notifier(adev, pci_dev);
if (!adev->wakeup.flags.valid) if (!adev->wakeup.flags.valid)
return; return;
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
#include <linux/pci-acpi.h> #include <linux/pci-acpi.h>
#include "pci.h" #include "pci.h"
#define DEVICE_LABEL_DSM 0x07
#ifdef CONFIG_DMI #ifdef CONFIG_DMI
enum smbios_attr_enum { enum smbios_attr_enum {
SMBIOS_ATTR_NONE = 0, SMBIOS_ATTR_NONE = 0,
...@@ -148,11 +146,6 @@ static inline void pci_remove_smbiosname_file(struct pci_dev *pdev) ...@@ -148,11 +146,6 @@ static inline void pci_remove_smbiosname_file(struct pci_dev *pdev)
#endif #endif
#ifdef CONFIG_ACPI #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 { enum acpi_attr_enum {
ACPI_ATTR_LABEL_SHOW, ACPI_ATTR_LABEL_SHOW,
ACPI_ATTR_INDEX_SHOW, ACPI_ATTR_INDEX_SHOW,
...@@ -179,7 +172,7 @@ static int dsm_get_label(struct device *dev, char *buf, ...@@ -179,7 +172,7 @@ static int dsm_get_label(struct device *dev, char *buf,
if (!handle) if (!handle)
return -1; 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); DEVICE_LABEL_DSM, NULL);
if (!obj) if (!obj)
return -1; return -1;
...@@ -219,7 +212,7 @@ static bool device_has_dsm(struct device *dev) ...@@ -219,7 +212,7 @@ static bool device_has_dsm(struct device *dev)
if (!handle) if (!handle)
return false; 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); 1 << DEVICE_LABEL_DSM);
} }
......
...@@ -146,19 +146,22 @@ static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, ...@@ -146,19 +146,22 @@ static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
u8 pos, int cap, int *ttl) u8 pos, int cap, int *ttl)
{ {
u8 id; u8 id;
u16 ent;
pci_bus_read_config_byte(bus, devfn, pos, &pos);
while ((*ttl)--) { while ((*ttl)--) {
pci_bus_read_config_byte(bus, devfn, pos, &pos);
if (pos < 0x40) if (pos < 0x40)
break; break;
pos &= ~3; pos &= ~3;
pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, pci_bus_read_config_word(bus, devfn, pos, &ent);
&id);
id = ent & 0xff;
if (id == 0xff) if (id == 0xff)
break; break;
if (id == cap) if (id == cap)
return pos; return pos;
pos += PCI_CAP_LIST_NEXT; pos = (ent >> 8);
} }
return 0; return 0;
} }
......
...@@ -321,4 +321,6 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) ...@@ -321,4 +321,6 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
} }
#endif #endif
struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
#endif /* DRIVERS_PCI_H */ #endif /* DRIVERS_PCI_H */
...@@ -782,24 +782,6 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) ...@@ -782,24 +782,6 @@ void pci_disable_link_state(struct pci_dev *pdev, int state)
} }
EXPORT_SYMBOL(pci_disable_link_state); EXPORT_SYMBOL(pci_disable_link_state);
void pcie_clear_aspm(struct pci_bus *bus)
{
struct pci_dev *child;
if (aspm_force)
return;
/*
* Clear any ASPM setup that the firmware has carried out on this bus
*/
list_for_each_entry(child, &bus->devices, bus_list) {
__pci_disable_link_state(child, PCIE_LINK_STATE_L0S |
PCIE_LINK_STATE_L1 |
PCIE_LINK_STATE_CLKPM,
false, true);
}
}
static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
{ {
int i; int i;
......
...@@ -3182,7 +3182,7 @@ static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev) ...@@ -3182,7 +3182,7 @@ static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev)
|| nhi->subsystem_vendor != 0x2222 || nhi->subsystem_vendor != 0x2222
|| nhi->subsystem_device != 0x1111) || nhi->subsystem_device != 0x1111)
goto out; goto out;
dev_info(&dev->dev, "quirk: wating for thunderbolt to reestablish pci tunnels...\n"); dev_info(&dev->dev, "quirk: waiting for thunderbolt to reestablish PCI tunnels...\n");
device_pm_wait_for_dev(&dev->dev, &nhi->dev); device_pm_wait_for_dev(&dev->dev, &nhi->dev);
out: out:
pci_dev_put(nhi); pci_dev_put(nhi);
......
...@@ -77,6 +77,11 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { } ...@@ -77,6 +77,11 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { } static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
#endif #endif
extern const u8 pci_acpi_dsm_uuid[];
#define DEVICE_LABEL_DSM 0x07
#define RESET_DELAY_DSM 0x08
#define FUNCTION_DELAY_DSM 0x09
#else /* CONFIG_ACPI */ #else /* CONFIG_ACPI */
static inline void acpi_pci_add_bus(struct pci_bus *bus) { } static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
static inline void acpi_pci_remove_bus(struct pci_bus *bus) { } static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
......
...@@ -29,7 +29,6 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev); ...@@ -29,7 +29,6 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev);
void pcie_aspm_powersave_config_link(struct pci_dev *pdev); void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
void pci_disable_link_state(struct pci_dev *pdev, int state); void pci_disable_link_state(struct pci_dev *pdev, int state);
void pci_disable_link_state_locked(struct pci_dev *pdev, int state); void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
void pcie_clear_aspm(struct pci_bus *bus);
void pcie_no_aspm(void); void pcie_no_aspm(void);
#else #else
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
...@@ -47,9 +46,6 @@ static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) ...@@ -47,9 +46,6 @@ static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
static inline void pci_disable_link_state(struct pci_dev *pdev, int state) static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
{ {
} }
static inline void pcie_clear_aspm(struct pci_bus *bus)
{
}
static inline void pcie_no_aspm(void) static inline void pcie_no_aspm(void)
{ {
} }
......
...@@ -406,6 +406,7 @@ struct pci_host_bridge { ...@@ -406,6 +406,7 @@ struct pci_host_bridge {
struct list_head windows; /* resource_entry */ struct list_head windows; /* resource_entry */
void (*release_fn)(struct pci_host_bridge *); void (*release_fn)(struct pci_host_bridge *);
void *release_data; void *release_data;
unsigned int ignore_reset_delay:1; /* for entire hierarchy */
}; };
#define to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev) #define to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment