diff options
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 9f79dd6d51ab..a544997399b3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -432,10 +432,12 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) | |||
432 | case PM_EVENT_ON: | 432 | case PM_EVENT_ON: |
433 | return PCI_D0; | 433 | return PCI_D0; |
434 | case PM_EVENT_FREEZE: | 434 | case PM_EVENT_FREEZE: |
435 | case PM_EVENT_PRETHAW: | ||
436 | /* REVISIT both freeze and pre-thaw "should" use D0 */ | ||
435 | case PM_EVENT_SUSPEND: | 437 | case PM_EVENT_SUSPEND: |
436 | return PCI_D3hot; | 438 | return PCI_D3hot; |
437 | default: | 439 | default: |
438 | printk("They asked me for state %d\n", state.event); | 440 | printk("Unrecognized suspend event %d\n", state.event); |
439 | BUG(); | 441 | BUG(); |
440 | } | 442 | } |
441 | return PCI_D0; | 443 | return PCI_D0; |
@@ -443,6 +445,51 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) | |||
443 | 445 | ||
444 | EXPORT_SYMBOL(pci_choose_state); | 446 | EXPORT_SYMBOL(pci_choose_state); |
445 | 447 | ||
448 | static int pci_save_pcie_state(struct pci_dev *dev) | ||
449 | { | ||
450 | int pos, i = 0; | ||
451 | struct pci_cap_saved_state *save_state; | ||
452 | u16 *cap; | ||
453 | |||
454 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | ||
455 | if (pos <= 0) | ||
456 | return 0; | ||
457 | |||
458 | save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL); | ||
459 | if (!save_state) { | ||
460 | dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); | ||
461 | return -ENOMEM; | ||
462 | } | ||
463 | cap = (u16 *)&save_state->data[0]; | ||
464 | |||
465 | pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]); | ||
466 | pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); | ||
467 | pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); | ||
468 | pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); | ||
469 | pci_add_saved_cap(dev, save_state); | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static void pci_restore_pcie_state(struct pci_dev *dev) | ||
474 | { | ||
475 | int i = 0, pos; | ||
476 | struct pci_cap_saved_state *save_state; | ||
477 | u16 *cap; | ||
478 | |||
479 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); | ||
480 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | ||
481 | if (!save_state || pos <= 0) | ||
482 | return; | ||
483 | cap = (u16 *)&save_state->data[0]; | ||
484 | |||
485 | pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]); | ||
486 | pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]); | ||
487 | pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]); | ||
488 | pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]); | ||
489 | pci_remove_saved_cap(save_state); | ||
490 | kfree(save_state); | ||
491 | } | ||
492 | |||
446 | /** | 493 | /** |
447 | * pci_save_state - save the PCI configuration space of a device before suspending | 494 | * pci_save_state - save the PCI configuration space of a device before suspending |
448 | * @dev: - PCI device that we're dealing with | 495 | * @dev: - PCI device that we're dealing with |
@@ -458,6 +505,8 @@ pci_save_state(struct pci_dev *dev) | |||
458 | return i; | 505 | return i; |
459 | if ((i = pci_save_msix_state(dev)) != 0) | 506 | if ((i = pci_save_msix_state(dev)) != 0) |
460 | return i; | 507 | return i; |
508 | if ((i = pci_save_pcie_state(dev)) != 0) | ||
509 | return i; | ||
461 | return 0; | 510 | return 0; |
462 | } | 511 | } |
463 | 512 | ||
@@ -471,6 +520,9 @@ pci_restore_state(struct pci_dev *dev) | |||
471 | int i; | 520 | int i; |
472 | int val; | 521 | int val; |
473 | 522 | ||
523 | /* PCI Express register must be restored first */ | ||
524 | pci_restore_pcie_state(dev); | ||
525 | |||
474 | /* | 526 | /* |
475 | * The Base Address register should be programmed before the command | 527 | * The Base Address register should be programmed before the command |
476 | * register(s) | 528 | * register(s) |
@@ -953,13 +1005,12 @@ static int __devinit pci_setup(char *str) | |||
953 | } | 1005 | } |
954 | str = k; | 1006 | str = k; |
955 | } | 1007 | } |
956 | return 1; | 1008 | return 0; |
957 | } | 1009 | } |
1010 | early_param("pci", pci_setup); | ||
958 | 1011 | ||
959 | device_initcall(pci_init); | 1012 | device_initcall(pci_init); |
960 | 1013 | ||
961 | __setup("pci=", pci_setup); | ||
962 | |||
963 | #if defined(CONFIG_ISA) || defined(CONFIG_EISA) | 1014 | #if defined(CONFIG_ISA) || defined(CONFIG_EISA) |
964 | /* FIXME: Some boxes have multiple ISA bridges! */ | 1015 | /* FIXME: Some boxes have multiple ISA bridges! */ |
965 | struct pci_dev *isa_bridge; | 1016 | struct pci_dev *isa_bridge; |