diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2008-06-09 18:10:48 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-06-12 08:11:25 -0400 |
commit | 6703f6d10dcd3316e03641a5ecaa6c8a04374d98 (patch) | |
tree | f8c1d9bbc5695979d2ad822a7bccb42f375dc904 /arch | |
parent | bb6dfb32f90094fea647e1f27d994a8b6ddd2766 (diff) |
x86, gart: add resume handling
If GART IOMMU is used on an AMD64 system, the northbridge registers
related to it should be restored during resume so that memory is not
corrupted. Make gart_resume() handle that as appropriate.
Ref. http://lkml.org/lkml/2008/5/25/96 and the following thread.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/aperture_64.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/pci-gart_64.c | 57 |
2 files changed, 54 insertions, 5 deletions
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index eb20f168c0f..3409abb231a 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c | |||
@@ -496,4 +496,6 @@ out: | |||
496 | write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25); | 496 | write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25); |
497 | } | 497 | } |
498 | } | 498 | } |
499 | |||
500 | set_up_gart_resume(aper_order, aper_alloc); | ||
499 | } | 501 | } |
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 3710097f02e..f505c389035 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c | |||
@@ -549,14 +549,63 @@ static __init unsigned read_aperture(struct pci_dev *dev, u32 *size) | |||
549 | return aper_base; | 549 | return aper_base; |
550 | } | 550 | } |
551 | 551 | ||
552 | static void enable_gart_translations(void) | ||
553 | { | ||
554 | int i; | ||
555 | |||
556 | for (i = 0; i < num_k8_northbridges; i++) { | ||
557 | struct pci_dev *dev = k8_northbridges[i]; | ||
558 | |||
559 | enable_gart_translation(dev, __pa(agp_gatt_table)); | ||
560 | } | ||
561 | } | ||
562 | |||
563 | /* | ||
564 | * If fix_up_north_bridges is set, the north bridges have to be fixed up on | ||
565 | * resume in the same way as they are handled in gart_iommu_hole_init(). | ||
566 | */ | ||
567 | static bool fix_up_north_bridges; | ||
568 | static u32 aperture_order; | ||
569 | static u32 aperture_alloc; | ||
570 | |||
571 | void set_up_gart_resume(u32 aper_order, u32 aper_alloc) | ||
572 | { | ||
573 | fix_up_north_bridges = true; | ||
574 | aperture_order = aper_order; | ||
575 | aperture_alloc = aper_alloc; | ||
576 | } | ||
577 | |||
552 | static int gart_resume(struct sys_device *dev) | 578 | static int gart_resume(struct sys_device *dev) |
553 | { | 579 | { |
580 | printk(KERN_INFO "PCI-DMA: Resuming GART IOMMU\n"); | ||
581 | |||
582 | if (fix_up_north_bridges) { | ||
583 | int i; | ||
584 | |||
585 | printk(KERN_INFO "PCI-DMA: Restoring GART aperture settings\n"); | ||
586 | |||
587 | for (i = 0; i < num_k8_northbridges; i++) { | ||
588 | struct pci_dev *dev = k8_northbridges[i]; | ||
589 | |||
590 | /* | ||
591 | * Don't enable translations just yet. That is the next | ||
592 | * step. Restore the pre-suspend aperture settings. | ||
593 | */ | ||
594 | pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, | ||
595 | aperture_order << 1); | ||
596 | pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, | ||
597 | aperture_alloc >> 25); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | enable_gart_translations(); | ||
602 | |||
554 | return 0; | 603 | return 0; |
555 | } | 604 | } |
556 | 605 | ||
557 | static int gart_suspend(struct sys_device *dev, pm_message_t state) | 606 | static int gart_suspend(struct sys_device *dev, pm_message_t state) |
558 | { | 607 | { |
559 | return -EINVAL; | 608 | return 0; |
560 | } | 609 | } |
561 | 610 | ||
562 | static struct sysdev_class gart_sysdev_class = { | 611 | static struct sysdev_class gart_sysdev_class = { |
@@ -614,16 +663,14 @@ static __init int init_k8_gatt(struct agp_kern_info *info) | |||
614 | memset(gatt, 0, gatt_size); | 663 | memset(gatt, 0, gatt_size); |
615 | agp_gatt_table = gatt; | 664 | agp_gatt_table = gatt; |
616 | 665 | ||
617 | for (i = 0; i < num_k8_northbridges; i++) { | 666 | enable_gart_translations(); |
618 | dev = k8_northbridges[i]; | ||
619 | enable_gart_translation(dev, __pa(gatt)); | ||
620 | } | ||
621 | 667 | ||
622 | error = sysdev_class_register(&gart_sysdev_class); | 668 | error = sysdev_class_register(&gart_sysdev_class); |
623 | if (!error) | 669 | if (!error) |
624 | error = sysdev_register(&device_gart); | 670 | error = sysdev_register(&device_gart); |
625 | if (error) | 671 | if (error) |
626 | panic("Could not register gart_sysdev -- would corrupt data on next suspend"); | 672 | panic("Could not register gart_sysdev -- would corrupt data on next suspend"); |
673 | |||
627 | flush_gart(); | 674 | flush_gart(); |
628 | 675 | ||
629 | printk(KERN_INFO "PCI-DMA: aperture base @ %x size %u KB\n", | 676 | printk(KERN_INFO "PCI-DMA: aperture base @ %x size %u KB\n", |