diff options
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r-- | drivers/pci/pci-driver.c | 132 |
1 files changed, 77 insertions, 55 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index b4cdd690ae71..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); |
@@ -434,7 +450,7 @@ static int pci_pm_suspend(struct device *dev) | |||
434 | static int pci_pm_suspend_noirq(struct device *dev) | 450 | static int pci_pm_suspend_noirq(struct device *dev) |
435 | { | 451 | { |
436 | struct pci_dev *pci_dev = to_pci_dev(dev); | 452 | struct pci_dev *pci_dev = to_pci_dev(dev); |
437 | struct pci_driver *drv = pci_dev->driver; | 453 | struct device_driver *drv = dev->driver; |
438 | int error = 0; | 454 | int error = 0; |
439 | 455 | ||
440 | if (drv && drv->pm) { | 456 | if (drv && drv->pm) { |
@@ -442,8 +458,10 @@ static int pci_pm_suspend_noirq(struct device *dev) | |||
442 | error = drv->pm->suspend_noirq(dev); | 458 | error = drv->pm->suspend_noirq(dev); |
443 | suspend_report_result(drv->pm->suspend_noirq, error); | 459 | suspend_report_result(drv->pm->suspend_noirq, error); |
444 | } | 460 | } |
445 | } else { | 461 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
446 | 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); | ||
447 | } | 465 | } |
448 | 466 | ||
449 | return error; | 467 | return error; |
@@ -453,15 +471,17 @@ static int pci_pm_resume(struct device *dev) | |||
453 | { | 471 | { |
454 | struct pci_dev *pci_dev = to_pci_dev(dev); | 472 | struct pci_dev *pci_dev = to_pci_dev(dev); |
455 | struct device_driver *drv = dev->driver; | 473 | struct device_driver *drv = dev->driver; |
456 | int error; | 474 | int error = 0; |
457 | 475 | ||
458 | pci_fixup_device(pci_fixup_resume, pci_dev); | 476 | pci_fixup_device(pci_fixup_resume, pci_dev); |
459 | 477 | ||
460 | if (drv && drv->pm) { | 478 | if (drv && drv->pm) { |
461 | error = drv->pm->resume ? drv->pm->resume(dev) : | 479 | if (drv->pm->resume) |
462 | pci_default_pm_resume(pci_dev); | 480 | error = drv->pm->resume(dev); |
463 | } else { | 481 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
464 | error = pci_legacy_resume(dev); | 482 | error = pci_legacy_resume(dev); |
483 | } else { | ||
484 | error = pci_default_pm_resume_late(pci_dev); | ||
465 | } | 485 | } |
466 | 486 | ||
467 | return error; | 487 | return error; |
@@ -470,16 +490,18 @@ static int pci_pm_resume(struct device *dev) | |||
470 | static int pci_pm_resume_noirq(struct device *dev) | 490 | static int pci_pm_resume_noirq(struct device *dev) |
471 | { | 491 | { |
472 | struct pci_dev *pci_dev = to_pci_dev(dev); | 492 | struct pci_dev *pci_dev = to_pci_dev(dev); |
473 | struct pci_driver *drv = pci_dev->driver; | 493 | struct device_driver *drv = dev->driver; |
474 | int error = 0; | 494 | int error = 0; |
475 | 495 | ||
476 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 496 | pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev)); |
477 | 497 | ||
478 | if (drv && drv->pm) { | 498 | if (drv && drv->pm) { |
479 | if (drv->pm->resume_noirq) | 499 | if (drv->pm->resume_noirq) |
480 | error = drv->pm->resume_noirq(dev); | 500 | error = drv->pm->resume_noirq(dev); |
481 | } else { | 501 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
482 | error = pci_legacy_resume_early(dev); | 502 | error = pci_legacy_resume_early(dev); |
503 | } else { | ||
504 | pci_default_pm_resume_early(pci_dev); | ||
483 | } | 505 | } |
484 | 506 | ||
485 | return error; | 507 | return error; |
@@ -506,10 +528,8 @@ static int pci_pm_freeze(struct device *dev) | |||
506 | if (drv->pm->freeze) { | 528 | if (drv->pm->freeze) { |
507 | error = drv->pm->freeze(dev); | 529 | error = drv->pm->freeze(dev); |
508 | suspend_report_result(drv->pm->freeze, error); | 530 | suspend_report_result(drv->pm->freeze, error); |
509 | } else { | ||
510 | pci_default_pm_suspend(pci_dev); | ||
511 | } | 531 | } |
512 | } else { | 532 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
513 | error = pci_legacy_suspend(dev, PMSG_FREEZE); | 533 | error = pci_legacy_suspend(dev, PMSG_FREEZE); |
514 | pci_fixup_device(pci_fixup_suspend, pci_dev); | 534 | pci_fixup_device(pci_fixup_suspend, pci_dev); |
515 | } | 535 | } |
@@ -520,7 +540,7 @@ static int pci_pm_freeze(struct device *dev) | |||
520 | static int pci_pm_freeze_noirq(struct device *dev) | 540 | static int pci_pm_freeze_noirq(struct device *dev) |
521 | { | 541 | { |
522 | struct pci_dev *pci_dev = to_pci_dev(dev); | 542 | struct pci_dev *pci_dev = to_pci_dev(dev); |
523 | struct pci_driver *drv = pci_dev->driver; | 543 | struct device_driver *drv = dev->driver; |
524 | int error = 0; | 544 | int error = 0; |
525 | 545 | ||
526 | if (drv && drv->pm) { | 546 | if (drv && drv->pm) { |
@@ -528,8 +548,10 @@ static int pci_pm_freeze_noirq(struct device *dev) | |||
528 | error = drv->pm->freeze_noirq(dev); | 548 | error = drv->pm->freeze_noirq(dev); |
529 | suspend_report_result(drv->pm->freeze_noirq, error); | 549 | suspend_report_result(drv->pm->freeze_noirq, error); |
530 | } | 550 | } |
531 | } else { | 551 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
532 | 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); | ||
533 | } | 555 | } |
534 | 556 | ||
535 | return error; | 557 | return error; |
@@ -537,14 +559,15 @@ static int pci_pm_freeze_noirq(struct device *dev) | |||
537 | 559 | ||
538 | static int pci_pm_thaw(struct device *dev) | 560 | static int pci_pm_thaw(struct device *dev) |
539 | { | 561 | { |
562 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
540 | struct device_driver *drv = dev->driver; | 563 | struct device_driver *drv = dev->driver; |
541 | int error = 0; | 564 | int error = 0; |
542 | 565 | ||
543 | if (drv && drv->pm) { | 566 | if (drv && drv->pm) { |
544 | if (drv->pm->thaw) | 567 | if (drv->pm->thaw) |
545 | error = drv->pm->thaw(dev); | 568 | error = drv->pm->thaw(dev); |
546 | } else { | 569 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
547 | pci_fixup_device(pci_fixup_resume, to_pci_dev(dev)); | 570 | pci_fixup_device(pci_fixup_resume, pci_dev); |
548 | error = pci_legacy_resume(dev); | 571 | error = pci_legacy_resume(dev); |
549 | } | 572 | } |
550 | 573 | ||
@@ -554,14 +577,14 @@ static int pci_pm_thaw(struct device *dev) | |||
554 | static int pci_pm_thaw_noirq(struct device *dev) | 577 | static int pci_pm_thaw_noirq(struct device *dev) |
555 | { | 578 | { |
556 | struct pci_dev *pci_dev = to_pci_dev(dev); | 579 | struct pci_dev *pci_dev = to_pci_dev(dev); |
557 | struct pci_driver *drv = pci_dev->driver; | 580 | struct device_driver *drv = dev->driver; |
558 | int error = 0; | 581 | int error = 0; |
559 | 582 | ||
560 | if (drv && drv->pm) { | 583 | if (drv && drv->pm) { |
561 | if (drv->pm->thaw_noirq) | 584 | if (drv->pm->thaw_noirq) |
562 | error = drv->pm->thaw_noirq(dev); | 585 | error = drv->pm->thaw_noirq(dev); |
563 | } else { | 586 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
564 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 587 | pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev)); |
565 | error = pci_legacy_resume_early(dev); | 588 | error = pci_legacy_resume_early(dev); |
566 | } | 589 | } |
567 | 590 | ||
@@ -570,17 +593,18 @@ static int pci_pm_thaw_noirq(struct device *dev) | |||
570 | 593 | ||
571 | static int pci_pm_poweroff(struct device *dev) | 594 | static int pci_pm_poweroff(struct device *dev) |
572 | { | 595 | { |
596 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
573 | struct device_driver *drv = dev->driver; | 597 | struct device_driver *drv = dev->driver; |
574 | int error = 0; | 598 | int error = 0; |
575 | 599 | ||
576 | pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev)); | 600 | pci_fixup_device(pci_fixup_suspend, pci_dev); |
577 | 601 | ||
578 | if (drv && drv->pm) { | 602 | if (drv && drv->pm) { |
579 | if (drv->pm->poweroff) { | 603 | if (drv->pm->poweroff) { |
580 | error = drv->pm->poweroff(dev); | 604 | error = drv->pm->poweroff(dev); |
581 | suspend_report_result(drv->pm->poweroff, error); | 605 | suspend_report_result(drv->pm->poweroff, error); |
582 | } | 606 | } |
583 | } else { | 607 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
584 | error = pci_legacy_suspend(dev, PMSG_HIBERNATE); | 608 | error = pci_legacy_suspend(dev, PMSG_HIBERNATE); |
585 | } | 609 | } |
586 | 610 | ||
@@ -589,8 +613,7 @@ static int pci_pm_poweroff(struct device *dev) | |||
589 | 613 | ||
590 | static int pci_pm_poweroff_noirq(struct device *dev) | 614 | static int pci_pm_poweroff_noirq(struct device *dev) |
591 | { | 615 | { |
592 | struct pci_dev *pci_dev = to_pci_dev(dev); | 616 | struct device_driver *drv = dev->driver; |
593 | struct pci_driver *drv = pci_dev->driver; | ||
594 | int error = 0; | 617 | int error = 0; |
595 | 618 | ||
596 | if (drv && drv->pm) { | 619 | if (drv && drv->pm) { |
@@ -598,7 +621,7 @@ static int pci_pm_poweroff_noirq(struct device *dev) | |||
598 | error = drv->pm->poweroff_noirq(dev); | 621 | error = drv->pm->poweroff_noirq(dev); |
599 | suspend_report_result(drv->pm->poweroff_noirq, error); | 622 | suspend_report_result(drv->pm->poweroff_noirq, error); |
600 | } | 623 | } |
601 | } else { | 624 | } else if (pci_has_legacy_pm_support(to_pci_dev(dev))) { |
602 | error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE); | 625 | error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE); |
603 | } | 626 | } |
604 | 627 | ||
@@ -609,13 +632,15 @@ static int pci_pm_restore(struct device *dev) | |||
609 | { | 632 | { |
610 | struct pci_dev *pci_dev = to_pci_dev(dev); | 633 | struct pci_dev *pci_dev = to_pci_dev(dev); |
611 | struct device_driver *drv = dev->driver; | 634 | struct device_driver *drv = dev->driver; |
612 | int error; | 635 | int error = 0; |
613 | 636 | ||
614 | if (drv && drv->pm) { | 637 | if (drv && drv->pm) { |
615 | error = drv->pm->restore ? drv->pm->restore(dev) : | 638 | if (drv->pm->restore) |
616 | pci_default_pm_resume(pci_dev); | 639 | error = drv->pm->restore(dev); |
617 | } else { | 640 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
618 | error = pci_legacy_resume(dev); | 641 | error = pci_legacy_resume(dev); |
642 | } else { | ||
643 | error = pci_default_pm_resume_late(pci_dev); | ||
619 | } | 644 | } |
620 | pci_fixup_device(pci_fixup_resume, pci_dev); | 645 | pci_fixup_device(pci_fixup_resume, pci_dev); |
621 | 646 | ||
@@ -625,7 +650,7 @@ static int pci_pm_restore(struct device *dev) | |||
625 | static int pci_pm_restore_noirq(struct device *dev) | 650 | static int pci_pm_restore_noirq(struct device *dev) |
626 | { | 651 | { |
627 | struct pci_dev *pci_dev = to_pci_dev(dev); | 652 | struct pci_dev *pci_dev = to_pci_dev(dev); |
628 | struct pci_driver *drv = pci_dev->driver; | 653 | struct device_driver *drv = dev->driver; |
629 | int error = 0; | 654 | int error = 0; |
630 | 655 | ||
631 | pci_fixup_device(pci_fixup_resume, pci_dev); | 656 | pci_fixup_device(pci_fixup_resume, pci_dev); |
@@ -633,8 +658,10 @@ static int pci_pm_restore_noirq(struct device *dev) | |||
633 | if (drv && drv->pm) { | 658 | if (drv && drv->pm) { |
634 | if (drv->pm->restore_noirq) | 659 | if (drv->pm->restore_noirq) |
635 | error = drv->pm->restore_noirq(dev); | 660 | error = drv->pm->restore_noirq(dev); |
636 | } else { | 661 | } else if (pci_has_legacy_pm_support(pci_dev)) { |
637 | error = pci_legacy_resume_early(dev); | 662 | error = pci_legacy_resume_early(dev); |
663 | } else { | ||
664 | pci_default_pm_resume_early(pci_dev); | ||
638 | } | 665 | } |
639 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 666 | pci_fixup_device(pci_fixup_resume_early, pci_dev); |
640 | 667 | ||
@@ -654,17 +681,15 @@ static int pci_pm_restore_noirq(struct device *dev) | |||
654 | 681 | ||
655 | #endif /* !CONFIG_HIBERNATION */ | 682 | #endif /* !CONFIG_HIBERNATION */ |
656 | 683 | ||
657 | struct pm_ext_ops pci_pm_ops = { | 684 | struct dev_pm_ops pci_dev_pm_ops = { |
658 | .base = { | 685 | .prepare = pci_pm_prepare, |
659 | .prepare = pci_pm_prepare, | 686 | .complete = pci_pm_complete, |
660 | .complete = pci_pm_complete, | 687 | .suspend = pci_pm_suspend, |
661 | .suspend = pci_pm_suspend, | 688 | .resume = pci_pm_resume, |
662 | .resume = pci_pm_resume, | 689 | .freeze = pci_pm_freeze, |
663 | .freeze = pci_pm_freeze, | 690 | .thaw = pci_pm_thaw, |
664 | .thaw = pci_pm_thaw, | 691 | .poweroff = pci_pm_poweroff, |
665 | .poweroff = pci_pm_poweroff, | 692 | .restore = pci_pm_restore, |
666 | .restore = pci_pm_restore, | ||
667 | }, | ||
668 | .suspend_noirq = pci_pm_suspend_noirq, | 693 | .suspend_noirq = pci_pm_suspend_noirq, |
669 | .resume_noirq = pci_pm_resume_noirq, | 694 | .resume_noirq = pci_pm_resume_noirq, |
670 | .freeze_noirq = pci_pm_freeze_noirq, | 695 | .freeze_noirq = pci_pm_freeze_noirq, |
@@ -673,7 +698,7 @@ struct pm_ext_ops pci_pm_ops = { | |||
673 | .restore_noirq = pci_pm_restore_noirq, | 698 | .restore_noirq = pci_pm_restore_noirq, |
674 | }; | 699 | }; |
675 | 700 | ||
676 | #define PCI_PM_OPS_PTR &pci_pm_ops | 701 | #define PCI_PM_OPS_PTR (&pci_dev_pm_ops) |
677 | 702 | ||
678 | #else /* !CONFIG_PM_SLEEP */ | 703 | #else /* !CONFIG_PM_SLEEP */ |
679 | 704 | ||
@@ -703,9 +728,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, | |||
703 | drv->driver.owner = owner; | 728 | drv->driver.owner = owner; |
704 | drv->driver.mod_name = mod_name; | 729 | drv->driver.mod_name = mod_name; |
705 | 730 | ||
706 | if (drv->pm) | ||
707 | drv->driver.pm = &drv->pm->base; | ||
708 | |||
709 | spin_lock_init(&drv->dynids.lock); | 731 | spin_lock_init(&drv->dynids.lock); |
710 | INIT_LIST_HEAD(&drv->dynids.list); | 732 | INIT_LIST_HEAD(&drv->dynids.list); |
711 | 733 | ||