|
9 | 9 |
|
10 | 10 | #include <linux/kernel.h> |
11 | 11 | #include <linux/delay.h> |
| 12 | +#include <linux/dmi.h> |
12 | 13 | #include <linux/init.h> |
13 | 14 | #include <linux/of.h> |
14 | 15 | #include <linux/of_pci.h> |
@@ -101,6 +102,21 @@ unsigned int pcibios_max_latency = 255; |
101 | 102 | /* If set, the PCIe ARI capability will not be used. */ |
102 | 103 | static bool pcie_ari_disabled; |
103 | 104 |
|
| 105 | +/* Disable bridge_d3 for all PCIe ports */ |
| 106 | +static bool pci_bridge_d3_disable; |
| 107 | +/* Force bridge_d3 for all PCIe ports */ |
| 108 | +static bool pci_bridge_d3_force; |
| 109 | + |
| 110 | +static int __init pcie_port_pm_setup(char *str) |
| 111 | +{ |
| 112 | + if (!strcmp(str, "off")) |
| 113 | + pci_bridge_d3_disable = true; |
| 114 | + else if (!strcmp(str, "force")) |
| 115 | + pci_bridge_d3_force = true; |
| 116 | + return 1; |
| 117 | +} |
| 118 | +__setup("pcie_port_pm=", pcie_port_pm_setup); |
| 119 | + |
104 | 120 | /** |
105 | 121 | * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children |
106 | 122 | * @bus: pointer to PCI bus structure to search |
@@ -2155,6 +2171,164 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev) |
2155 | 2171 | pm_runtime_put_sync(parent); |
2156 | 2172 | } |
2157 | 2173 |
|
| 2174 | +/** |
| 2175 | + * pci_bridge_d3_possible - Is it possible to put the bridge into D3 |
| 2176 | + * @bridge: Bridge to check |
| 2177 | + * |
| 2178 | + * This function checks if it is possible to move the bridge to D3. |
| 2179 | + * Currently we only allow D3 for recent enough PCIe ports. |
| 2180 | + */ |
| 2181 | +static bool pci_bridge_d3_possible(struct pci_dev *bridge) |
| 2182 | +{ |
| 2183 | + unsigned int year; |
| 2184 | + |
| 2185 | + if (!pci_is_pcie(bridge)) |
| 2186 | + return false; |
| 2187 | + |
| 2188 | + switch (pci_pcie_type(bridge)) { |
| 2189 | + case PCI_EXP_TYPE_ROOT_PORT: |
| 2190 | + case PCI_EXP_TYPE_UPSTREAM: |
| 2191 | + case PCI_EXP_TYPE_DOWNSTREAM: |
| 2192 | + if (pci_bridge_d3_disable) |
| 2193 | + return false; |
| 2194 | + if (pci_bridge_d3_force) |
| 2195 | + return true; |
| 2196 | + |
| 2197 | + /* |
| 2198 | + * It should be safe to put PCIe ports from 2015 or newer |
| 2199 | + * to D3. |
| 2200 | + */ |
| 2201 | + if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && |
| 2202 | + year >= 2015) { |
| 2203 | + return true; |
| 2204 | + } |
| 2205 | + break; |
| 2206 | + } |
| 2207 | + |
| 2208 | + return false; |
| 2209 | +} |
| 2210 | + |
| 2211 | +static int pci_dev_check_d3cold(struct pci_dev *dev, void *data) |
| 2212 | +{ |
| 2213 | + bool *d3cold_ok = data; |
| 2214 | + bool no_d3cold; |
| 2215 | + |
| 2216 | + /* |
| 2217 | + * The device needs to be allowed to go D3cold and if it is wake |
| 2218 | + * capable to do so from D3cold. |
| 2219 | + */ |
| 2220 | + no_d3cold = dev->no_d3cold || !dev->d3cold_allowed || |
| 2221 | + (device_may_wakeup(&dev->dev) && !pci_pme_capable(dev, PCI_D3cold)) || |
| 2222 | + !pci_power_manageable(dev); |
| 2223 | + |
| 2224 | + *d3cold_ok = !no_d3cold; |
| 2225 | + |
| 2226 | + return no_d3cold; |
| 2227 | +} |
| 2228 | + |
| 2229 | +/* |
| 2230 | + * pci_bridge_d3_update - Update bridge D3 capabilities |
| 2231 | + * @dev: PCI device which is changed |
| 2232 | + * @remove: Is the device being removed |
| 2233 | + * |
| 2234 | + * Update upstream bridge PM capabilities accordingly depending on if the |
| 2235 | + * device PM configuration was changed or the device is being removed. The |
| 2236 | + * change is also propagated upstream. |
| 2237 | + */ |
| 2238 | +static void pci_bridge_d3_update(struct pci_dev *dev, bool remove) |
| 2239 | +{ |
| 2240 | + struct pci_dev *bridge; |
| 2241 | + bool d3cold_ok = true; |
| 2242 | + |
| 2243 | + bridge = pci_upstream_bridge(dev); |
| 2244 | + if (!bridge || !pci_bridge_d3_possible(bridge)) |
| 2245 | + return; |
| 2246 | + |
| 2247 | + pci_dev_get(bridge); |
| 2248 | + /* |
| 2249 | + * If the device is removed we do not care about its D3cold |
| 2250 | + * capabilities. |
| 2251 | + */ |
| 2252 | + if (!remove) |
| 2253 | + pci_dev_check_d3cold(dev, &d3cold_ok); |
| 2254 | + |
| 2255 | + if (d3cold_ok) { |
| 2256 | + /* |
| 2257 | + * We need to go through all children to find out if all of |
| 2258 | + * them can still go to D3cold. |
| 2259 | + */ |
| 2260 | + pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold, |
| 2261 | + &d3cold_ok); |
| 2262 | + } |
| 2263 | + |
| 2264 | + if (bridge->bridge_d3 != d3cold_ok) { |
| 2265 | + bridge->bridge_d3 = d3cold_ok; |
| 2266 | + /* Propagate change to upstream bridges */ |
| 2267 | + pci_bridge_d3_update(bridge, false); |
| 2268 | + } |
| 2269 | + |
| 2270 | + pci_dev_put(bridge); |
| 2271 | +} |
| 2272 | + |
| 2273 | +/** |
| 2274 | + * pci_bridge_d3_device_changed - Update bridge D3 capabilities on change |
| 2275 | + * @dev: PCI device that was changed |
| 2276 | + * |
| 2277 | + * If a device is added or its PM configuration, such as is it allowed to |
| 2278 | + * enter D3cold, is changed this function updates upstream bridge PM |
| 2279 | + * capabilities accordingly. |
| 2280 | + */ |
| 2281 | +void pci_bridge_d3_device_changed(struct pci_dev *dev) |
| 2282 | +{ |
| 2283 | + pci_bridge_d3_update(dev, false); |
| 2284 | +} |
| 2285 | + |
| 2286 | +/** |
| 2287 | + * pci_bridge_d3_device_removed - Update bridge D3 capabilities on remove |
| 2288 | + * @dev: PCI device being removed |
| 2289 | + * |
| 2290 | + * Function updates upstream bridge PM capabilities based on other devices |
| 2291 | + * still left on the bus. |
| 2292 | + */ |
| 2293 | +void pci_bridge_d3_device_removed(struct pci_dev *dev) |
| 2294 | +{ |
| 2295 | + pci_bridge_d3_update(dev, true); |
| 2296 | +} |
| 2297 | + |
| 2298 | +/** |
| 2299 | + * pci_d3cold_enable - Enable D3cold for device |
| 2300 | + * @dev: PCI device to handle |
| 2301 | + * |
| 2302 | + * This function can be used in drivers to enable D3cold from the device |
| 2303 | + * they handle. It also updates upstream PCI bridge PM capabilities |
| 2304 | + * accordingly. |
| 2305 | + */ |
| 2306 | +void pci_d3cold_enable(struct pci_dev *dev) |
| 2307 | +{ |
| 2308 | + if (dev->no_d3cold) { |
| 2309 | + dev->no_d3cold = false; |
| 2310 | + pci_bridge_d3_device_changed(dev); |
| 2311 | + } |
| 2312 | +} |
| 2313 | +EXPORT_SYMBOL_GPL(pci_d3cold_enable); |
| 2314 | + |
| 2315 | +/** |
| 2316 | + * pci_d3cold_disable - Disable D3cold for device |
| 2317 | + * @dev: PCI device to handle |
| 2318 | + * |
| 2319 | + * This function can be used in drivers to disable D3cold from the device |
| 2320 | + * they handle. It also updates upstream PCI bridge PM capabilities |
| 2321 | + * accordingly. |
| 2322 | + */ |
| 2323 | +void pci_d3cold_disable(struct pci_dev *dev) |
| 2324 | +{ |
| 2325 | + if (!dev->no_d3cold) { |
| 2326 | + dev->no_d3cold = true; |
| 2327 | + pci_bridge_d3_device_changed(dev); |
| 2328 | + } |
| 2329 | +} |
| 2330 | +EXPORT_SYMBOL_GPL(pci_d3cold_disable); |
| 2331 | + |
2158 | 2332 | /** |
2159 | 2333 | * pci_pm_init - Initialize PM functions of given PCI device |
2160 | 2334 | * @dev: PCI device to handle. |
@@ -2189,6 +2363,7 @@ void pci_pm_init(struct pci_dev *dev) |
2189 | 2363 | dev->pm_cap = pm; |
2190 | 2364 | dev->d3_delay = PCI_PM_D3_WAIT; |
2191 | 2365 | dev->d3cold_delay = PCI_PM_D3COLD_WAIT; |
| 2366 | + dev->bridge_d3 = pci_bridge_d3_possible(dev); |
2192 | 2367 | dev->d3cold_allowed = true; |
2193 | 2368 |
|
2194 | 2369 | dev->d1_support = false; |
|
0 commit comments