diff options
author | Michael S. Tsirkin <mst@mellanox.co.il> | 2006-08-21 09:22:22 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-09-26 20:43:53 -0400 |
commit | b56a5a23bfecd9cac9187164a9d5f22d287c48b9 (patch) | |
tree | b0c713c6a51edb1491fdf6545a5d2742f2f77630 /drivers/pci/pci.c | |
parent | 6d47a5e4c3f8b6458002065d98a9cc6ff90fb597 (diff) |
PCI: Restore PCI Express capability registers after PM event
Restore PCI Express capability registers after PM event.
This includes maxumum MTU for PCI express and other vital data.
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 590f4e6f505d..a544997399b3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -445,6 +445,51 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) | |||
445 | 445 | ||
446 | EXPORT_SYMBOL(pci_choose_state); | 446 | EXPORT_SYMBOL(pci_choose_state); |
447 | 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 | |||
448 | /** | 493 | /** |
449 | * 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 |
450 | * @dev: - PCI device that we're dealing with | 495 | * @dev: - PCI device that we're dealing with |
@@ -460,6 +505,8 @@ pci_save_state(struct pci_dev *dev) | |||
460 | return i; | 505 | return i; |
461 | if ((i = pci_save_msix_state(dev)) != 0) | 506 | if ((i = pci_save_msix_state(dev)) != 0) |
462 | return i; | 507 | return i; |
508 | if ((i = pci_save_pcie_state(dev)) != 0) | ||
509 | return i; | ||
463 | return 0; | 510 | return 0; |
464 | } | 511 | } |
465 | 512 | ||
@@ -473,6 +520,9 @@ pci_restore_state(struct pci_dev *dev) | |||
473 | int i; | 520 | int i; |
474 | int val; | 521 | int val; |
475 | 522 | ||
523 | /* PCI Express register must be restored first */ | ||
524 | pci_restore_pcie_state(dev); | ||
525 | |||
476 | /* | 526 | /* |
477 | * The Base Address register should be programmed before the command | 527 | * The Base Address register should be programmed before the command |
478 | * register(s) | 528 | * register(s) |