Commit f8b9cf0f319af81f617606bdc90a4984ae3b3ca2
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Merge tag '3.6-pci-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas: "Power management - PCI/PM: Enable D3/D3cold by default for most devices - PCI/PM: Keep parent bridge active when probing device - PCI/PM: Fix config reg access for D3cold and bridge suspending - PCI/PM: Add ABI document for sysfs file d3cold_allowed Core - PCI: Don't print anything while decoding is disabled" * tag '3.6-pci-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: PCI: Don't print anything while decoding is disabled PCI/PM: Add ABI document for sysfs file d3cold_allowed PCI/PM: Fix config reg access for D3cold and bridge suspending PCI/PM: Keep parent bridge active when probing device PCI/PM: Enable D3/D3cold by default for most devices
Showing 6 changed files Side-by-side Diff
Documentation/ABI/testing/sysfs-bus-pci
... | ... | @@ -210,4 +210,16 @@ |
210 | 210 | firmware assigned instance number of the PCI |
211 | 211 | device that can help in understanding the firmware |
212 | 212 | intended order of the PCI device. |
213 | + | |
214 | +What: /sys/bus/pci/devices/.../d3cold_allowed | |
215 | +Date: July 2012 | |
216 | +Contact: Huang Ying <ying.huang@intel.com> | |
217 | +Description: | |
218 | + d3cold_allowed is bit to control whether the corresponding PCI | |
219 | + device can be put into D3Cold state. If it is cleared, the | |
220 | + device will never be put into D3Cold state. If it is set, the | |
221 | + device may be put into D3Cold state if other requirements are | |
222 | + satisfied too. Reading this attribute will show the current | |
223 | + value of d3cold_allowed bit. Writing this attribute will set | |
224 | + the value of d3cold_allowed bit. |
drivers/pci/pci-driver.c
... | ... | @@ -280,8 +280,12 @@ |
280 | 280 | { |
281 | 281 | struct drv_dev_and_id *ddi = _ddi; |
282 | 282 | struct device *dev = &ddi->dev->dev; |
283 | + struct device *parent = dev->parent; | |
283 | 284 | int rc; |
284 | 285 | |
286 | + /* The parent bridge must be in active state when probing */ | |
287 | + if (parent) | |
288 | + pm_runtime_get_sync(parent); | |
285 | 289 | /* Unbound PCI devices are always set to disabled and suspended. |
286 | 290 | * During probe, the device is set to enabled and active and the |
287 | 291 | * usage count is incremented. If the driver supports runtime PM, |
... | ... | @@ -298,6 +302,8 @@ |
298 | 302 | pm_runtime_set_suspended(dev); |
299 | 303 | pm_runtime_put_noidle(dev); |
300 | 304 | } |
305 | + if (parent) | |
306 | + pm_runtime_put(parent); | |
301 | 307 | return rc; |
302 | 308 | } |
303 | 309 |
drivers/pci/pci-sysfs.c
... | ... | @@ -458,6 +458,40 @@ |
458 | 458 | } |
459 | 459 | struct device_attribute vga_attr = __ATTR_RO(boot_vga); |
460 | 460 | |
461 | +static void | |
462 | +pci_config_pm_runtime_get(struct pci_dev *pdev) | |
463 | +{ | |
464 | + struct device *dev = &pdev->dev; | |
465 | + struct device *parent = dev->parent; | |
466 | + | |
467 | + if (parent) | |
468 | + pm_runtime_get_sync(parent); | |
469 | + pm_runtime_get_noresume(dev); | |
470 | + /* | |
471 | + * pdev->current_state is set to PCI_D3cold during suspending, | |
472 | + * so wait until suspending completes | |
473 | + */ | |
474 | + pm_runtime_barrier(dev); | |
475 | + /* | |
476 | + * Only need to resume devices in D3cold, because config | |
477 | + * registers are still accessible for devices suspended but | |
478 | + * not in D3cold. | |
479 | + */ | |
480 | + if (pdev->current_state == PCI_D3cold) | |
481 | + pm_runtime_resume(dev); | |
482 | +} | |
483 | + | |
484 | +static void | |
485 | +pci_config_pm_runtime_put(struct pci_dev *pdev) | |
486 | +{ | |
487 | + struct device *dev = &pdev->dev; | |
488 | + struct device *parent = dev->parent; | |
489 | + | |
490 | + pm_runtime_put(dev); | |
491 | + if (parent) | |
492 | + pm_runtime_put_sync(parent); | |
493 | +} | |
494 | + | |
461 | 495 | static ssize_t |
462 | 496 | pci_read_config(struct file *filp, struct kobject *kobj, |
463 | 497 | struct bin_attribute *bin_attr, |
... | ... | @@ -484,6 +518,8 @@ |
484 | 518 | size = count; |
485 | 519 | } |
486 | 520 | |
521 | + pci_config_pm_runtime_get(dev); | |
522 | + | |
487 | 523 | if ((off & 1) && size) { |
488 | 524 | u8 val; |
489 | 525 | pci_user_read_config_byte(dev, off, &val); |
... | ... | @@ -529,6 +565,8 @@ |
529 | 565 | --size; |
530 | 566 | } |
531 | 567 | |
568 | + pci_config_pm_runtime_put(dev); | |
569 | + | |
532 | 570 | return count; |
533 | 571 | } |
534 | 572 | |
... | ... | @@ -549,6 +587,8 @@ |
549 | 587 | count = size; |
550 | 588 | } |
551 | 589 | |
590 | + pci_config_pm_runtime_get(dev); | |
591 | + | |
552 | 592 | if ((off & 1) && size) { |
553 | 593 | pci_user_write_config_byte(dev, off, data[off - init_off]); |
554 | 594 | off++; |
... | ... | @@ -586,6 +626,8 @@ |
586 | 626 | off++; |
587 | 627 | --size; |
588 | 628 | } |
629 | + | |
630 | + pci_config_pm_runtime_put(dev); | |
589 | 631 | |
590 | 632 | return count; |
591 | 633 | } |
drivers/pci/pci.c
drivers/pci/pcie/portdrv_pci.c
... | ... | @@ -140,9 +140,17 @@ |
140 | 140 | { |
141 | 141 | return 0; |
142 | 142 | } |
143 | + | |
144 | +static int pcie_port_runtime_idle(struct device *dev) | |
145 | +{ | |
146 | + /* Delay for a short while to prevent too frequent suspend/resume */ | |
147 | + pm_schedule_suspend(dev, 10); | |
148 | + return -EBUSY; | |
149 | +} | |
143 | 150 | #else |
144 | 151 | #define pcie_port_runtime_suspend NULL |
145 | 152 | #define pcie_port_runtime_resume NULL |
153 | +#define pcie_port_runtime_idle NULL | |
146 | 154 | #endif |
147 | 155 | |
148 | 156 | static const struct dev_pm_ops pcie_portdrv_pm_ops = { |
... | ... | @@ -155,6 +163,7 @@ |
155 | 163 | .resume_noirq = pcie_port_resume_noirq, |
156 | 164 | .runtime_suspend = pcie_port_runtime_suspend, |
157 | 165 | .runtime_resume = pcie_port_runtime_resume, |
166 | + .runtime_idle = pcie_port_runtime_idle, | |
158 | 167 | }; |
159 | 168 | |
160 | 169 | #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) |
... | ... | @@ -200,6 +209,11 @@ |
200 | 209 | return status; |
201 | 210 | |
202 | 211 | pci_save_state(dev); |
212 | + /* | |
213 | + * D3cold may not work properly on some PCIe port, so disable | |
214 | + * it by default. | |
215 | + */ | |
216 | + dev->d3cold_allowed = false; | |
203 | 217 | if (!pci_match_id(port_runtime_pm_black_list, dev)) |
204 | 218 | pm_runtime_put_noidle(&dev->dev); |
205 | 219 |
drivers/pci/probe.c
... | ... | @@ -144,15 +144,13 @@ |
144 | 144 | case PCI_BASE_ADDRESS_MEM_TYPE_32: |
145 | 145 | break; |
146 | 146 | case PCI_BASE_ADDRESS_MEM_TYPE_1M: |
147 | - dev_info(&dev->dev, "1M mem BAR treated as 32-bit BAR\n"); | |
147 | + /* 1M mem BAR treated as 32-bit BAR */ | |
148 | 148 | break; |
149 | 149 | case PCI_BASE_ADDRESS_MEM_TYPE_64: |
150 | 150 | flags |= IORESOURCE_MEM_64; |
151 | 151 | break; |
152 | 152 | default: |
153 | - dev_warn(&dev->dev, | |
154 | - "mem unknown type %x treated as 32-bit BAR\n", | |
155 | - mem_type); | |
153 | + /* mem unknown type treated as 32-bit BAR */ | |
156 | 154 | break; |
157 | 155 | } |
158 | 156 | return flags; |
159 | 157 | |
... | ... | @@ -173,9 +171,11 @@ |
173 | 171 | u32 l, sz, mask; |
174 | 172 | u16 orig_cmd; |
175 | 173 | struct pci_bus_region region; |
174 | + bool bar_too_big = false, bar_disabled = false; | |
176 | 175 | |
177 | 176 | mask = type ? PCI_ROM_ADDRESS_MASK : ~0; |
178 | 177 | |
178 | + /* No printks while decoding is disabled! */ | |
179 | 179 | if (!dev->mmio_always_on) { |
180 | 180 | pci_read_config_word(dev, PCI_COMMAND, &orig_cmd); |
181 | 181 | pci_write_config_word(dev, PCI_COMMAND, |
... | ... | @@ -240,8 +240,7 @@ |
240 | 240 | goto fail; |
241 | 241 | |
242 | 242 | if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { |
243 | - dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", | |
244 | - pos); | |
243 | + bar_too_big = true; | |
245 | 244 | goto fail; |
246 | 245 | } |
247 | 246 | |
248 | 247 | |
... | ... | @@ -252,12 +251,11 @@ |
252 | 251 | region.start = 0; |
253 | 252 | region.end = sz64; |
254 | 253 | pcibios_bus_to_resource(dev, res, ®ion); |
254 | + bar_disabled = true; | |
255 | 255 | } else { |
256 | 256 | region.start = l64; |
257 | 257 | region.end = l64 + sz64; |
258 | 258 | pcibios_bus_to_resource(dev, res, ®ion); |
259 | - dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", | |
260 | - pos, res); | |
261 | 259 | } |
262 | 260 | } else { |
263 | 261 | sz = pci_size(l, sz, mask); |
264 | 262 | |
265 | 263 | |
266 | 264 | |
... | ... | @@ -268,18 +266,23 @@ |
268 | 266 | region.start = l; |
269 | 267 | region.end = l + sz; |
270 | 268 | pcibios_bus_to_resource(dev, res, ®ion); |
271 | - | |
272 | - dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); | |
273 | 269 | } |
274 | 270 | |
275 | - out: | |
271 | + goto out; | |
272 | + | |
273 | + | |
274 | +fail: | |
275 | + res->flags = 0; | |
276 | +out: | |
276 | 277 | if (!dev->mmio_always_on) |
277 | 278 | pci_write_config_word(dev, PCI_COMMAND, orig_cmd); |
278 | 279 | |
280 | + if (bar_too_big) | |
281 | + dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", pos); | |
282 | + if (res->flags && !bar_disabled) | |
283 | + dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); | |
284 | + | |
279 | 285 | return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; |
280 | - fail: | |
281 | - res->flags = 0; | |
282 | - goto out; | |
283 | 286 | } |
284 | 287 | |
285 | 288 | static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) |