forked from Minki/linux
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
This commit is contained in:
commit
5468d5a64b
@ -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/.
|
||||
|
||||
|
||||
|
||||
|
@ -423,8 +423,7 @@ out:
|
||||
}
|
||||
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();
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 id;
|
||||
u16 ent;
|
||||
|
||||
pci_bus_read_config_byte(bus, devfn, pos, &pos);
|
||||
|
||||
while ((*ttl)--) {
|
||||
pci_bus_read_config_byte(bus, devfn, pos, &pos);
|
||||
if (pos < 0x40)
|
||||
break;
|
||||
pos &= ~3;
|
||||
pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID,
|
||||
&id);
|
||||
pci_bus_read_config_word(bus, devfn, pos, &ent);
|
||||
|
||||
id = ent & 0xff;
|
||||
if (id == 0xff)
|
||||
break;
|
||||
if (id == cap)
|
||||
return pos;
|
||||
pos += PCI_CAP_LIST_NEXT;
|
||||
pos = (ent >> 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -321,4 +321,6 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
|
||||
}
|
||||
#endif
|
||||
|
||||
struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
|
||||
|
||||
#endif /* DRIVERS_PCI_H */
|
||||
|
@ -782,24 +782,6 @@ void pci_disable_link_state(struct pci_dev *pdev, int 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)
|
||||
{
|
||||
int i;
|
||||
|
@ -3182,7 +3182,7 @@ static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev)
|
||||
|| nhi->subsystem_vendor != 0x2222
|
||||
|| nhi->subsystem_device != 0x1111)
|
||||
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);
|
||||
out:
|
||||
pci_dev_put(nhi);
|
||||
|
@ -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) { }
|
||||
#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 */
|
||||
static inline void acpi_pci_add_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);
|
||||
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_locked(struct pci_dev *pdev, int state);
|
||||
void pcie_clear_aspm(struct pci_bus *bus);
|
||||
void pcie_no_aspm(void);
|
||||
#else
|
||||
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)
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
@ -406,6 +406,7 @@ struct pci_host_bridge {
|
||||
struct list_head windows; /* resource_entry */
|
||||
void (*release_fn)(struct pci_host_bridge *);
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user