diff options
-rw-r--r-- | drivers/pci/pci-driver.c | 94 |
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 | ||
303 | static 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 | */ |
322 | static int pci_default_pm_resume(struct pci_dev *pci_dev) | 330 | static 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 | */ | ||
340 | static 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 | ||
434 | static int pci_pm_suspend_noirq(struct device *dev) | 450 | static 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 | ||
469 | static int pci_pm_resume_noirq(struct device *dev) | 490 | static 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 | ||
518 | static int pci_pm_freeze_noirq(struct device *dev) | 540 | static 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 | ||
535 | static int pci_pm_thaw(struct device *dev) | 560 | static 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 | ||
551 | static int pci_pm_thaw_noirq(struct device *dev) | 577 | static 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 | ||
567 | static int pci_pm_poweroff(struct device *dev) | 594 | static 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 | ||