diff options
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 125 |
1 files changed, 80 insertions, 45 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e578d34095e9..b9fecc25d213 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -399,8 +399,8 @@ found: return 1; } -static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, - u8 pos, int cap, int *ttl) +static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, + u8 pos, int cap, int *ttl) { u8 id; u16 ent; @@ -423,22 +423,22 @@ static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, return 0; } -static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, - u8 pos, int cap) +static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, + u8 pos, int cap) { int ttl = PCI_FIND_CAP_TTL; return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl); } -int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) +u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) { return __pci_find_next_cap(dev->bus, dev->devfn, pos + PCI_CAP_LIST_NEXT, cap); } EXPORT_SYMBOL_GPL(pci_find_next_capability); -static int __pci_bus_find_cap_start(struct pci_bus *bus, +static u8 __pci_bus_find_cap_start(struct pci_bus *bus, unsigned int devfn, u8 hdr_type) { u16 status; @@ -477,9 +477,9 @@ static int __pci_bus_find_cap_start(struct pci_bus *bus, * %PCI_CAP_ID_PCIX PCI-X * %PCI_CAP_ID_EXP PCI Express */ -int pci_find_capability(struct pci_dev *dev, int cap) +u8 pci_find_capability(struct pci_dev *dev, int cap) { - int pos; + u8 pos; pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); if (pos) @@ -502,10 +502,9 @@ EXPORT_SYMBOL(pci_find_capability); * device's PCI configuration space or 0 in case the device does not * support it. */ -int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) +u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) { - int pos; - u8 hdr_type; + u8 hdr_type, pos; pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type); @@ -528,11 +527,11 @@ EXPORT_SYMBOL(pci_bus_find_capability); * not support it. Some capabilities can occur several times, e.g., the * vendor-specific capability, and this provides a way to find them all. */ -int pci_find_next_ext_capability(struct pci_dev *dev, int start, int cap) +u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap) { u32 header; int ttl; - int pos = PCI_CFG_SPACE_SIZE; + u16 pos = PCI_CFG_SPACE_SIZE; /* minimum 8 bytes per capability */ ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; @@ -583,7 +582,7 @@ EXPORT_SYMBOL_GPL(pci_find_next_ext_capability); * %PCI_EXT_CAP_ID_DSN Device Serial Number * %PCI_EXT_CAP_ID_PWR Power Budgeting */ -int pci_find_ext_capability(struct pci_dev *dev, int cap) +u16 pci_find_ext_capability(struct pci_dev *dev, int cap) { return pci_find_next_ext_capability(dev, 0, cap); } @@ -623,7 +622,7 @@ u64 pci_get_dsn(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_get_dsn); -static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) +static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) { int rc, ttl = PCI_FIND_CAP_TTL; u8 cap, mask; @@ -650,11 +649,12 @@ static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) return 0; } + /** - * pci_find_next_ht_capability - query a device's Hypertransport capabilities + * pci_find_next_ht_capability - query a device's HyperTransport capabilities * @dev: PCI device to query * @pos: Position from which to continue searching - * @ht_cap: Hypertransport capability code + * @ht_cap: HyperTransport capability code * * To be used in conjunction with pci_find_ht_capability() to search for * all capabilities matching @ht_cap. @pos should always be a value returned @@ -663,26 +663,26 @@ static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) * NB. To be 100% safe against broken PCI devices, the caller should take * steps to avoid an infinite loop. */ -int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap) +u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap) { return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap); } EXPORT_SYMBOL_GPL(pci_find_next_ht_capability); /** - * pci_find_ht_capability - query a device's Hypertransport capabilities + * pci_find_ht_capability - query a device's HyperTransport capabilities * @dev: PCI device to query - * @ht_cap: Hypertransport capability code + * @ht_cap: HyperTransport capability code * - * Tell if a device supports a given Hypertransport capability. + * Tell if a device supports a given HyperTransport capability. * Returns an address within the device's PCI configuration space * or 0 in case the device does not support the request capability. * The address points to the PCI capability, of type PCI_CAP_ID_HT, - * which has a Hypertransport capability matching @ht_cap. + * which has a HyperTransport capability matching @ht_cap. */ -int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) +u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap) { - int pos; + u8 pos; pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); if (pos) @@ -1174,26 +1174,20 @@ int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state) } EXPORT_SYMBOL_GPL(pci_platform_power_transition); -/** - * pci_wakeup - Wake up a PCI device - * @pci_dev: Device to handle. - * @ign: ignored parameter - */ -static int pci_wakeup(struct pci_dev *pci_dev, void *ign) +static int pci_resume_one(struct pci_dev *pci_dev, void *ign) { - pci_wakeup_event(pci_dev); pm_request_resume(&pci_dev->dev); return 0; } /** - * pci_wakeup_bus - Walk given bus and wake up devices on it + * pci_resume_bus - Walk given bus and runtime resume devices on it * @bus: Top bus of the subtree to walk. */ -void pci_wakeup_bus(struct pci_bus *bus) +void pci_resume_bus(struct pci_bus *bus) { if (bus) - pci_walk_bus(bus, pci_wakeup, NULL); + pci_walk_bus(bus, pci_resume_one, NULL); } static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) @@ -1256,7 +1250,7 @@ int pci_power_up(struct pci_dev *dev) * may be powered on into D0uninitialized state, resume them to * give them a chance to suspend again */ - pci_wakeup_bus(dev->subordinate); + pci_resume_bus(dev->subordinate); } return pci_raw_set_power_state(dev, PCI_D0); @@ -1564,8 +1558,10 @@ int pci_save_state(struct pci_dev *dev) return i; pci_save_ltr_state(dev); + pci_save_aspm_l1ss_state(dev); pci_save_dpc_state(dev); pci_save_aer_state(dev); + pci_save_ptm_state(dev); return pci_save_vc_state(dev); } EXPORT_SYMBOL(pci_save_state); @@ -1669,6 +1665,7 @@ void pci_restore_state(struct pci_dev *dev) * LTR itself (in the PCIe capability). */ pci_restore_ltr_state(dev); + pci_restore_aspm_l1ss_state(dev); pci_restore_pcie_state(dev); pci_restore_pasid_state(dev); @@ -1677,6 +1674,7 @@ void pci_restore_state(struct pci_dev *dev) pci_restore_vc_state(dev); pci_restore_rebar_state(dev); pci_restore_dpc_state(dev); + pci_restore_ptm_state(dev); pci_aer_clear_status(dev); pci_restore_aer_state(dev); @@ -2606,12 +2604,24 @@ int pci_prepare_to_sleep(struct pci_dev *dev) if (target_state == PCI_POWER_ERROR) return -EIO; + /* + * There are systems (for example, Intel mobile chips since Coffee + * Lake) where the power drawn while suspended can be significantly + * reduced by disabling PTM on PCIe root ports as this allows the + * port to enter a lower-power PM state and the SoC to reach a + * lower-power idle state as a whole. + */ + if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) + pci_disable_ptm(dev); + pci_enable_wake(dev, target_state, wakeup); error = pci_set_power_state(dev, target_state); - if (error) + if (error) { pci_enable_wake(dev, target_state, false); + pci_restore_ptm_state(dev); + } return error; } @@ -2649,12 +2659,23 @@ int pci_finish_runtime_suspend(struct pci_dev *dev) dev->runtime_d3cold = target_state == PCI_D3cold; + /* + * There are systems (for example, Intel mobile chips since Coffee + * Lake) where the power drawn while suspended can be significantly + * reduced by disabling PTM on PCIe root ports as this allows the + * port to enter a lower-power PM state and the SoC to reach a + * lower-power idle state as a whole. + */ + if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) + pci_disable_ptm(dev); + __pci_enable_wake(dev, target_state, pci_dev_run_wake(dev)); error = pci_set_power_state(dev, target_state); if (error) { pci_enable_wake(dev, target_state, false); + pci_restore_ptm_state(dev); dev->runtime_d3cold = false; } @@ -3332,6 +3353,11 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev) if (error) pci_err(dev, "unable to allocate suspend buffer for LTR\n"); + error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS, + 2 * sizeof(u32)); + if (error) + pci_err(dev, "unable to allocate suspend buffer for ASPM-L1SS\n"); + pci_allocate_vc_save_buffers(dev); } @@ -3480,7 +3506,7 @@ bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags) } /** - * pci_acs_path_enable - test ACS flags from start to end in a hierarchy + * pci_acs_path_enabled - test ACS flags from start to end in a hierarchy * @start: starting downstream device * @end: ending upstream device or NULL to search to the root bus * @acs_flags: required flags @@ -4188,7 +4214,14 @@ void __iomem *devm_pci_remap_cfg_resource(struct device *dev, } size = resource_size(res); - name = res->name ?: dev_name(dev); + + if (res->name) + name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev), + res->name); + else + name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL); + if (!name) + return IOMEM_ERR_PTR(-ENOMEM); if (!devm_request_mem_region(dev, res->start, size, name)) { dev_err(dev, "can't request region for resource %pR\n", res); @@ -4317,7 +4350,7 @@ int pci_set_cacheline_size(struct pci_dev *dev) if (cacheline_size == pci_cache_line_size) return 0; - pci_info(dev, "cache line size of %d is not supported\n", + pci_dbg(dev, "cache line size of %d is not supported\n", pci_cache_line_size << 2); return -EINVAL; @@ -6202,19 +6235,21 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev, while (*p) { count = 0; if (sscanf(p, "%d%n", &align_order, &count) == 1 && - p[count] == '@') { + p[count] == '@') { p += count + 1; + if (align_order > 63) { + pr_err("PCI: Invalid requested alignment (order %d)\n", + align_order); + align_order = PAGE_SHIFT; + } } else { - align_order = -1; + align_order = PAGE_SHIFT; } ret = pci_dev_str_match(dev, p, &p); if (ret == 1) { *resize = true; - if (align_order == -1) - align = PAGE_SIZE; - else - align = 1 << align_order; + align = 1ULL << align_order; break; } else if (ret < 0) { pr_err("PCI: Can't parse resource_alignment parameter: %s\n", |