aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-12-07 18:34:57 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-06 13:44:32 -0500
commit355a72d75b3b4f4877db4c9070c798238028ecb5 (patch)
treefb59e5585c8e5e86a602c4d67ebe21669971024b /drivers
parentcd3772e6898c6386f21d2958346d6dd57d4204f5 (diff)
PCI: Rework default handling of suspend and resume
Rework the handling of suspend and resume of PCI devices which have no drivers or the drivers of which do not provide any suspend-resume callbacks in such a way that their standard PCI configuration registers will be saved and restored with interrupts disabled. This should prevent such devices, including PCI bridges, from being resumed too late to be able to function correctly during the resume of the other PCI devices that may depend on them. Also, to remove one possible source of future confusion, drop the default handling of suspend and resume for PCI devices with drivers providing the 'pm' object introduced by the new suspend-resume framework (there are no such PCI drivers at the moment). This patch addresses the regression from 2.6.26 tracked as http://bugzilla.kernel.org/show_bug.cgi?id=12121 . Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/pci-driver.c94
1 files changed, 63 insertions, 31 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 4042d211c3e5..99d867bcf22a 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -300,6 +300,14 @@ static void pci_device_shutdown(struct device *dev)
300 300
301#ifdef CONFIG_PM_SLEEP 301#ifdef CONFIG_PM_SLEEP
302 302
303static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
304{
305 struct pci_driver *drv = pci_dev->driver;
306
307 return drv && (drv->suspend || drv->suspend_late || drv->resume
308 || drv->resume_early);
309}
310
303/* 311/*
304 * Default "suspend" method for devices that have no driver provided suspend, 312 * Default "suspend" method for devices that have no driver provided suspend,
305 * or not even a driver at all. 313 * or not even a driver at all.
@@ -317,14 +325,22 @@ static void pci_default_pm_suspend(struct pci_dev *pci_dev)
317 325
318/* 326/*
319 * Default "resume" method for devices that have no driver provided resume, 327 * Default "resume" method for devices that have no driver provided resume,
320 * or not even a driver at all. 328 * or not even a driver at all (first part).
321 */ 329 */
322static int pci_default_pm_resume(struct pci_dev *pci_dev) 330static void pci_default_pm_resume_early(struct pci_dev *pci_dev)
323{ 331{
324 int retval = 0;
325
326 /* restore the PCI config space */ 332 /* restore the PCI config space */
327 pci_restore_state(pci_dev); 333 pci_restore_state(pci_dev);
334}
335
336/*
337 * Default "resume" method for devices that have no driver provided resume,
338 * or not even a driver at all (second part).
339 */
340static int pci_default_pm_resume_late(struct pci_dev *pci_dev)
341{
342 int retval;
343
328 /* if the device was enabled before suspend, reenable */ 344 /* if the device was enabled before suspend, reenable */
329 retval = pci_reenable_device(pci_dev); 345 retval = pci_reenable_device(pci_dev);
330 /* 346 /*
@@ -371,10 +387,12 @@ static int pci_legacy_resume(struct device *dev)
371 struct pci_dev * pci_dev = to_pci_dev(dev); 387 struct pci_dev * pci_dev = to_pci_dev(dev);
372 struct pci_driver * drv = pci_dev->driver; 388 struct pci_driver * drv = pci_dev->driver;
373 389
374 if (drv && drv->resume) 390 if (drv && drv->resume) {
375 error = drv->resume(pci_dev); 391 error = drv->resume(pci_dev);
376 else 392 } else {
377 error = pci_default_pm_resume(pci_dev); 393 pci_default_pm_resume_early(pci_dev);
394 error = pci_default_pm_resume_late(pci_dev);
395 }
378 return error; 396 return error;
379} 397}
380 398
@@ -420,10 +438,8 @@ static int pci_pm_suspend(struct device *dev)
420 if (drv->pm->suspend) { 438 if (drv->pm->suspend) {
421 error = drv->pm->suspend(dev); 439 error = drv->pm->suspend(dev);
422 suspend_report_result(drv->pm->suspend, error); 440 suspend_report_result(drv->pm->suspend, error);
423 } else {
424 pci_default_pm_suspend(pci_dev);
425 } 441 }
426 } else { 442 } else if (pci_has_legacy_pm_support(pci_dev)) {
427 error = pci_legacy_suspend(dev, PMSG_SUSPEND); 443 error = pci_legacy_suspend(dev, PMSG_SUSPEND);
428 } 444 }
429 pci_fixup_device(pci_fixup_suspend, pci_dev); 445 pci_fixup_device(pci_fixup_suspend, pci_dev);
@@ -433,6 +449,7 @@ static int pci_pm_suspend(struct device *dev)
433 449
434static int pci_pm_suspend_noirq(struct device *dev) 450static int pci_pm_suspend_noirq(struct device *dev)
435{ 451{
452 struct pci_dev *pci_dev = to_pci_dev(dev);
436 struct device_driver *drv = dev->driver; 453 struct device_driver *drv = dev->driver;
437 int error = 0; 454 int error = 0;
438 455
@@ -441,8 +458,10 @@ static int pci_pm_suspend_noirq(struct device *dev)
441 error = drv->pm->suspend_noirq(dev); 458 error = drv->pm->suspend_noirq(dev);
442 suspend_report_result(drv->pm->suspend_noirq, error); 459 suspend_report_result(drv->pm->suspend_noirq, error);
443 } 460 }
444 } else { 461 } else if (pci_has_legacy_pm_support(pci_dev)) {
445 error = pci_legacy_suspend_late(dev, PMSG_SUSPEND); 462 error = pci_legacy_suspend_late(dev, PMSG_SUSPEND);
463 } else {
464 pci_default_pm_suspend(pci_dev);
446 } 465 }
447 466
448 return error; 467 return error;
@@ -452,15 +471,17 @@ static int pci_pm_resume(struct device *dev)
452{ 471{
453 struct pci_dev *pci_dev = to_pci_dev(dev); 472 struct pci_dev *pci_dev = to_pci_dev(dev);
454 struct device_driver *drv = dev->driver; 473 struct device_driver *drv = dev->driver;
455 int error; 474 int error = 0;
456 475
457 pci_fixup_device(pci_fixup_resume, pci_dev); 476 pci_fixup_device(pci_fixup_resume, pci_dev);
458 477
459 if (drv && drv->pm) { 478 if (drv && drv->pm) {
460 error = drv->pm->resume ? drv->pm->resume(dev) : 479 if (drv->pm->resume)
461 pci_default_pm_resume(pci_dev); 480 error = drv->pm->resume(dev);
462 } else { 481 } else if (pci_has_legacy_pm_support(pci_dev)) {
463 error = pci_legacy_resume(dev); 482 error = pci_legacy_resume(dev);
483 } else {
484 error = pci_default_pm_resume_late(pci_dev);
464 } 485 }
465 486
466 return error; 487 return error;
@@ -468,6 +489,7 @@ static int pci_pm_resume(struct device *dev)
468 489
469static int pci_pm_resume_noirq(struct device *dev) 490static int pci_pm_resume_noirq(struct device *dev)
470{ 491{
492 struct pci_dev *pci_dev = to_pci_dev(dev);
471 struct device_driver *drv = dev->driver; 493 struct device_driver *drv = dev->driver;
472 int error = 0; 494 int error = 0;
473 495
@@ -476,8 +498,10 @@ static int pci_pm_resume_noirq(struct device *dev)
476 if (drv && drv->pm) { 498 if (drv && drv->pm) {
477 if (drv->pm->resume_noirq) 499 if (drv->pm->resume_noirq)
478 error = drv->pm->resume_noirq(dev); 500 error = drv->pm->resume_noirq(dev);
479 } else { 501 } else if (pci_has_legacy_pm_support(pci_dev)) {
480 error = pci_legacy_resume_early(dev); 502 error = pci_legacy_resume_early(dev);
503 } else {
504 pci_default_pm_resume_early(pci_dev);
481 } 505 }
482 506
483 return error; 507 return error;
@@ -504,10 +528,8 @@ static int pci_pm_freeze(struct device *dev)
504 if (drv->pm->freeze) { 528 if (drv->pm->freeze) {
505 error = drv->pm->freeze(dev); 529 error = drv->pm->freeze(dev);
506 suspend_report_result(drv->pm->freeze, error); 530 suspend_report_result(drv->pm->freeze, error);
507 } else {
508 pci_default_pm_suspend(pci_dev);
509 } 531 }
510 } else { 532 } else if (pci_has_legacy_pm_support(pci_dev)) {
511 error = pci_legacy_suspend(dev, PMSG_FREEZE); 533 error = pci_legacy_suspend(dev, PMSG_FREEZE);
512 pci_fixup_device(pci_fixup_suspend, pci_dev); 534 pci_fixup_device(pci_fixup_suspend, pci_dev);
513 } 535 }
@@ -517,6 +539,7 @@ static int pci_pm_freeze(struct device *dev)
517 539
518static int pci_pm_freeze_noirq(struct device *dev) 540static int pci_pm_freeze_noirq(struct device *dev)
519{ 541{
542 struct pci_dev *pci_dev = to_pci_dev(dev);
520 struct device_driver *drv = dev->driver; 543 struct device_driver *drv = dev->driver;
521 int error = 0; 544 int error = 0;
522 545
@@ -525,8 +548,10 @@ static int pci_pm_freeze_noirq(struct device *dev)
525 error = drv->pm->freeze_noirq(dev); 548 error = drv->pm->freeze_noirq(dev);
526 suspend_report_result(drv->pm->freeze_noirq, error); 549 suspend_report_result(drv->pm->freeze_noirq, error);
527 } 550 }
528 } else { 551 } else if (pci_has_legacy_pm_support(pci_dev)) {
529 error = pci_legacy_suspend_late(dev, PMSG_FREEZE); 552 error = pci_legacy_suspend_late(dev, PMSG_FREEZE);
553 } else {
554 pci_default_pm_suspend(pci_dev);
530 } 555 }
531 556
532 return error; 557 return error;
@@ -534,14 +559,15 @@ static int pci_pm_freeze_noirq(struct device *dev)
534 559
535static int pci_pm_thaw(struct device *dev) 560static int pci_pm_thaw(struct device *dev)
536{ 561{
562 struct pci_dev *pci_dev = to_pci_dev(dev);
537 struct device_driver *drv = dev->driver; 563 struct device_driver *drv = dev->driver;
538 int error = 0; 564 int error = 0;
539 565
540 if (drv && drv->pm) { 566 if (drv && drv->pm) {
541 if (drv->pm->thaw) 567 if (drv->pm->thaw)
542 error = drv->pm->thaw(dev); 568 error = drv->pm->thaw(dev);
543 } else { 569 } else if (pci_has_legacy_pm_support(pci_dev)) {
544 pci_fixup_device(pci_fixup_resume, to_pci_dev(dev)); 570 pci_fixup_device(pci_fixup_resume, pci_dev);
545 error = pci_legacy_resume(dev); 571 error = pci_legacy_resume(dev);
546 } 572 }
547 573
@@ -550,13 +576,14 @@ static int pci_pm_thaw(struct device *dev)
550 576
551static int pci_pm_thaw_noirq(struct device *dev) 577static int pci_pm_thaw_noirq(struct device *dev)
552{ 578{
579 struct pci_dev *pci_dev = to_pci_dev(dev);
553 struct device_driver *drv = dev->driver; 580 struct device_driver *drv = dev->driver;
554 int error = 0; 581 int error = 0;
555 582
556 if (drv && drv->pm) { 583 if (drv && drv->pm) {
557 if (drv->pm->thaw_noirq) 584 if (drv->pm->thaw_noirq)
558 error = drv->pm->thaw_noirq(dev); 585 error = drv->pm->thaw_noirq(dev);
559 } else { 586 } else if (pci_has_legacy_pm_support(pci_dev)) {
560 pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev)); 587 pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev));
561 error = pci_legacy_resume_early(dev); 588 error = pci_legacy_resume_early(dev);
562 } 589 }
@@ -566,17 +593,18 @@ static int pci_pm_thaw_noirq(struct device *dev)
566 593
567static int pci_pm_poweroff(struct device *dev) 594static int pci_pm_poweroff(struct device *dev)
568{ 595{
596 struct pci_dev *pci_dev = to_pci_dev(dev);
569 struct device_driver *drv = dev->driver; 597 struct device_driver *drv = dev->driver;
570 int error = 0; 598 int error = 0;
571 599
572 pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev)); 600 pci_fixup_device(pci_fixup_suspend, pci_dev);
573 601
574 if (drv && drv->pm) { 602 if (drv && drv->pm) {
575 if (drv->pm->poweroff) { 603 if (drv->pm->poweroff) {
576 error = drv->pm->poweroff(dev); 604 error = drv->pm->poweroff(dev);
577 suspend_report_result(drv->pm->poweroff, error); 605 suspend_report_result(drv->pm->poweroff, error);
578 } 606 }
579 } else { 607 } else if (pci_has_legacy_pm_support(pci_dev)) {
580 error = pci_legacy_suspend(dev, PMSG_HIBERNATE); 608 error = pci_legacy_suspend(dev, PMSG_HIBERNATE);
581 } 609 }
582 610
@@ -593,7 +621,7 @@ static int pci_pm_poweroff_noirq(struct device *dev)
593 error = drv->pm->poweroff_noirq(dev); 621 error = drv->pm->poweroff_noirq(dev);
594 suspend_report_result(drv->pm->poweroff_noirq, error); 622 suspend_report_result(drv->pm->poweroff_noirq, error);
595 } 623 }
596 } else { 624 } else if (pci_has_legacy_pm_support(to_pci_dev(dev))) {
597 error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE); 625 error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
598 } 626 }
599 627
@@ -604,13 +632,15 @@ static int pci_pm_restore(struct device *dev)
604{ 632{
605 struct pci_dev *pci_dev = to_pci_dev(dev); 633 struct pci_dev *pci_dev = to_pci_dev(dev);
606 struct device_driver *drv = dev->driver; 634 struct device_driver *drv = dev->driver;
607 int error; 635 int error = 0;
608 636
609 if (drv && drv->pm) { 637 if (drv && drv->pm) {
610 error = drv->pm->restore ? drv->pm->restore(dev) : 638 if (drv->pm->restore)
611 pci_default_pm_resume(pci_dev); 639 error = drv->pm->restore(dev);
612 } else { 640 } else if (pci_has_legacy_pm_support(pci_dev)) {
613 error = pci_legacy_resume(dev); 641 error = pci_legacy_resume(dev);
642 } else {
643 error = pci_default_pm_resume_late(pci_dev);
614 } 644 }
615 pci_fixup_device(pci_fixup_resume, pci_dev); 645 pci_fixup_device(pci_fixup_resume, pci_dev);
616 646
@@ -628,8 +658,10 @@ static int pci_pm_restore_noirq(struct device *dev)
628 if (drv && drv->pm) { 658 if (drv && drv->pm) {
629 if (drv->pm->restore_noirq) 659 if (drv->pm->restore_noirq)
630 error = drv->pm->restore_noirq(dev); 660 error = drv->pm->restore_noirq(dev);
631 } else { 661 } else if (pci_has_legacy_pm_support(pci_dev)) {
632 error = pci_legacy_resume_early(dev); 662 error = pci_legacy_resume_early(dev);
663 } else {
664 pci_default_pm_resume_early(pci_dev);
633 } 665 }
634 pci_fixup_device(pci_fixup_resume_early, pci_dev); 666 pci_fixup_device(pci_fixup_resume_early, pci_dev);
635 667