diff options
Diffstat (limited to 'arch/x86/kernel/pci-gart_64.c')
-rw-r--r-- | arch/x86/kernel/pci-gart_64.c | 125 |
1 files changed, 67 insertions, 58 deletions
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 1a895a582534..145f1c83369f 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c | |||
@@ -27,8 +27,8 @@ | |||
27 | #include <linux/scatterlist.h> | 27 | #include <linux/scatterlist.h> |
28 | #include <linux/iommu-helper.h> | 28 | #include <linux/iommu-helper.h> |
29 | #include <linux/sysdev.h> | 29 | #include <linux/sysdev.h> |
30 | #include <linux/io.h> | ||
30 | #include <asm/atomic.h> | 31 | #include <asm/atomic.h> |
31 | #include <asm/io.h> | ||
32 | #include <asm/mtrr.h> | 32 | #include <asm/mtrr.h> |
33 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
34 | #include <asm/proto.h> | 34 | #include <asm/proto.h> |
@@ -80,7 +80,7 @@ AGPEXTERN int agp_memory_reserved; | |||
80 | AGPEXTERN __u32 *agp_gatt_table; | 80 | AGPEXTERN __u32 *agp_gatt_table; |
81 | 81 | ||
82 | static unsigned long next_bit; /* protected by iommu_bitmap_lock */ | 82 | static unsigned long next_bit; /* protected by iommu_bitmap_lock */ |
83 | static int need_flush; /* global flush state. set for each gart wrap */ | 83 | static bool need_flush; /* global flush state. set for each gart wrap */ |
84 | 84 | ||
85 | static unsigned long alloc_iommu(struct device *dev, int size, | 85 | static unsigned long alloc_iommu(struct device *dev, int size, |
86 | unsigned long align_mask) | 86 | unsigned long align_mask) |
@@ -98,7 +98,7 @@ static unsigned long alloc_iommu(struct device *dev, int size, | |||
98 | offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit, | 98 | offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit, |
99 | size, base_index, boundary_size, align_mask); | 99 | size, base_index, boundary_size, align_mask); |
100 | if (offset == -1) { | 100 | if (offset == -1) { |
101 | need_flush = 1; | 101 | need_flush = true; |
102 | offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0, | 102 | offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0, |
103 | size, base_index, boundary_size, | 103 | size, base_index, boundary_size, |
104 | align_mask); | 104 | align_mask); |
@@ -107,11 +107,11 @@ static unsigned long alloc_iommu(struct device *dev, int size, | |||
107 | next_bit = offset+size; | 107 | next_bit = offset+size; |
108 | if (next_bit >= iommu_pages) { | 108 | if (next_bit >= iommu_pages) { |
109 | next_bit = 0; | 109 | next_bit = 0; |
110 | need_flush = 1; | 110 | need_flush = true; |
111 | } | 111 | } |
112 | } | 112 | } |
113 | if (iommu_fullflush) | 113 | if (iommu_fullflush) |
114 | need_flush = 1; | 114 | need_flush = true; |
115 | spin_unlock_irqrestore(&iommu_bitmap_lock, flags); | 115 | spin_unlock_irqrestore(&iommu_bitmap_lock, flags); |
116 | 116 | ||
117 | return offset; | 117 | return offset; |
@@ -136,7 +136,7 @@ static void flush_gart(void) | |||
136 | spin_lock_irqsave(&iommu_bitmap_lock, flags); | 136 | spin_lock_irqsave(&iommu_bitmap_lock, flags); |
137 | if (need_flush) { | 137 | if (need_flush) { |
138 | k8_flush_garts(); | 138 | k8_flush_garts(); |
139 | need_flush = 0; | 139 | need_flush = false; |
140 | } | 140 | } |
141 | spin_unlock_irqrestore(&iommu_bitmap_lock, flags); | 141 | spin_unlock_irqrestore(&iommu_bitmap_lock, flags); |
142 | } | 142 | } |
@@ -175,7 +175,8 @@ static void dump_leak(void) | |||
175 | iommu_leak_pages); | 175 | iommu_leak_pages); |
176 | for (i = 0; i < iommu_leak_pages; i += 2) { | 176 | for (i = 0; i < iommu_leak_pages; i += 2) { |
177 | printk(KERN_DEBUG "%lu: ", iommu_pages-i); | 177 | printk(KERN_DEBUG "%lu: ", iommu_pages-i); |
178 | printk_address((unsigned long) iommu_leak_tab[iommu_pages-i], 0); | 178 | printk_address((unsigned long) iommu_leak_tab[iommu_pages-i], |
179 | 0); | ||
179 | printk(KERN_CONT "%c", (i+1)%2 == 0 ? '\n' : ' '); | 180 | printk(KERN_CONT "%c", (i+1)%2 == 0 ? '\n' : ' '); |
180 | } | 181 | } |
181 | printk(KERN_DEBUG "\n"); | 182 | printk(KERN_DEBUG "\n"); |
@@ -214,24 +215,14 @@ static void iommu_full(struct device *dev, size_t size, int dir) | |||
214 | static inline int | 215 | static inline int |
215 | need_iommu(struct device *dev, unsigned long addr, size_t size) | 216 | need_iommu(struct device *dev, unsigned long addr, size_t size) |
216 | { | 217 | { |
217 | u64 mask = *dev->dma_mask; | 218 | return force_iommu || |
218 | int high = addr + size > mask; | 219 | !is_buffer_dma_capable(*dev->dma_mask, addr, size); |
219 | int mmu = high; | ||
220 | |||
221 | if (force_iommu) | ||
222 | mmu = 1; | ||
223 | |||
224 | return mmu; | ||
225 | } | 220 | } |
226 | 221 | ||
227 | static inline int | 222 | static inline int |
228 | nonforced_iommu(struct device *dev, unsigned long addr, size_t size) | 223 | nonforced_iommu(struct device *dev, unsigned long addr, size_t size) |
229 | { | 224 | { |
230 | u64 mask = *dev->dma_mask; | 225 | return !is_buffer_dma_capable(*dev->dma_mask, addr, size); |
231 | int high = addr + size > mask; | ||
232 | int mmu = high; | ||
233 | |||
234 | return mmu; | ||
235 | } | 226 | } |
236 | 227 | ||
237 | /* Map a single continuous physical area into the IOMMU. | 228 | /* Map a single continuous physical area into the IOMMU. |
@@ -261,20 +252,6 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, | |||
261 | return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK); | 252 | return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK); |
262 | } | 253 | } |
263 | 254 | ||
264 | static dma_addr_t | ||
265 | gart_map_simple(struct device *dev, phys_addr_t paddr, size_t size, int dir) | ||
266 | { | ||
267 | dma_addr_t map; | ||
268 | unsigned long align_mask; | ||
269 | |||
270 | align_mask = (1UL << get_order(size)) - 1; | ||
271 | map = dma_map_area(dev, paddr, size, dir, align_mask); | ||
272 | |||
273 | flush_gart(); | ||
274 | |||
275 | return map; | ||
276 | } | ||
277 | |||
278 | /* Map a single area into the IOMMU */ | 255 | /* Map a single area into the IOMMU */ |
279 | static dma_addr_t | 256 | static dma_addr_t |
280 | gart_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir) | 257 | gart_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir) |
@@ -282,7 +259,7 @@ gart_map_single(struct device *dev, phys_addr_t paddr, size_t size, int dir) | |||
282 | unsigned long bus; | 259 | unsigned long bus; |
283 | 260 | ||
284 | if (!dev) | 261 | if (!dev) |
285 | dev = &fallback_dev; | 262 | dev = &x86_dma_fallback_dev; |
286 | 263 | ||
287 | if (!need_iommu(dev, paddr, size)) | 264 | if (!need_iommu(dev, paddr, size)) |
288 | return paddr; | 265 | return paddr; |
@@ -434,7 +411,7 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) | |||
434 | return 0; | 411 | return 0; |
435 | 412 | ||
436 | if (!dev) | 413 | if (!dev) |
437 | dev = &fallback_dev; | 414 | dev = &x86_dma_fallback_dev; |
438 | 415 | ||
439 | out = 0; | 416 | out = 0; |
440 | start = 0; | 417 | start = 0; |
@@ -506,6 +483,46 @@ error: | |||
506 | return 0; | 483 | return 0; |
507 | } | 484 | } |
508 | 485 | ||
486 | /* allocate and map a coherent mapping */ | ||
487 | static void * | ||
488 | gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, | ||
489 | gfp_t flag) | ||
490 | { | ||
491 | dma_addr_t paddr; | ||
492 | unsigned long align_mask; | ||
493 | struct page *page; | ||
494 | |||
495 | if (force_iommu && !(flag & GFP_DMA)) { | ||
496 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); | ||
497 | page = alloc_pages(flag | __GFP_ZERO, get_order(size)); | ||
498 | if (!page) | ||
499 | return NULL; | ||
500 | |||
501 | align_mask = (1UL << get_order(size)) - 1; | ||
502 | paddr = dma_map_area(dev, page_to_phys(page), size, | ||
503 | DMA_BIDIRECTIONAL, align_mask); | ||
504 | |||
505 | flush_gart(); | ||
506 | if (paddr != bad_dma_address) { | ||
507 | *dma_addr = paddr; | ||
508 | return page_address(page); | ||
509 | } | ||
510 | __free_pages(page, get_order(size)); | ||
511 | } else | ||
512 | return dma_generic_alloc_coherent(dev, size, dma_addr, flag); | ||
513 | |||
514 | return NULL; | ||
515 | } | ||
516 | |||
517 | /* free a coherent mapping */ | ||
518 | static void | ||
519 | gart_free_coherent(struct device *dev, size_t size, void *vaddr, | ||
520 | dma_addr_t dma_addr) | ||
521 | { | ||
522 | gart_unmap_single(dev, dma_addr, size, DMA_BIDIRECTIONAL); | ||
523 | free_pages((unsigned long)vaddr, get_order(size)); | ||
524 | } | ||
525 | |||
509 | static int no_agp; | 526 | static int no_agp; |
510 | 527 | ||
511 | static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size) | 528 | static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size) |
@@ -656,13 +673,13 @@ static __init int init_k8_gatt(struct agp_kern_info *info) | |||
656 | info->aper_size = aper_size >> 20; | 673 | info->aper_size = aper_size >> 20; |
657 | 674 | ||
658 | gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32); | 675 | gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32); |
659 | gatt = (void *)__get_free_pages(GFP_KERNEL, get_order(gatt_size)); | 676 | gatt = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, |
677 | get_order(gatt_size)); | ||
660 | if (!gatt) | 678 | if (!gatt) |
661 | panic("Cannot allocate GATT table"); | 679 | panic("Cannot allocate GATT table"); |
662 | if (set_memory_uc((unsigned long)gatt, gatt_size >> PAGE_SHIFT)) | 680 | if (set_memory_uc((unsigned long)gatt, gatt_size >> PAGE_SHIFT)) |
663 | panic("Could not set GART PTEs to uncacheable pages"); | 681 | panic("Could not set GART PTEs to uncacheable pages"); |
664 | 682 | ||
665 | memset(gatt, 0, gatt_size); | ||
666 | agp_gatt_table = gatt; | 683 | agp_gatt_table = gatt; |
667 | 684 | ||
668 | enable_gart_translations(); | 685 | enable_gart_translations(); |
@@ -671,7 +688,8 @@ static __init int init_k8_gatt(struct agp_kern_info *info) | |||
671 | if (!error) | 688 | if (!error) |
672 | error = sysdev_register(&device_gart); | 689 | error = sysdev_register(&device_gart); |
673 | if (error) | 690 | if (error) |
674 | panic("Could not register gart_sysdev -- would corrupt data on next suspend"); | 691 | panic("Could not register gart_sysdev -- " |
692 | "would corrupt data on next suspend"); | ||
675 | 693 | ||
676 | flush_gart(); | 694 | flush_gart(); |
677 | 695 | ||
@@ -687,20 +705,13 @@ static __init int init_k8_gatt(struct agp_kern_info *info) | |||
687 | return -1; | 705 | return -1; |
688 | } | 706 | } |
689 | 707 | ||
690 | extern int agp_amd64_init(void); | ||
691 | |||
692 | static struct dma_mapping_ops gart_dma_ops = { | 708 | static struct dma_mapping_ops gart_dma_ops = { |
693 | .map_single = gart_map_single, | 709 | .map_single = gart_map_single, |
694 | .map_simple = gart_map_simple, | ||
695 | .unmap_single = gart_unmap_single, | 710 | .unmap_single = gart_unmap_single, |
696 | .sync_single_for_cpu = NULL, | ||
697 | .sync_single_for_device = NULL, | ||
698 | .sync_single_range_for_cpu = NULL, | ||
699 | .sync_single_range_for_device = NULL, | ||
700 | .sync_sg_for_cpu = NULL, | ||
701 | .sync_sg_for_device = NULL, | ||
702 | .map_sg = gart_map_sg, | 711 | .map_sg = gart_map_sg, |
703 | .unmap_sg = gart_unmap_sg, | 712 | .unmap_sg = gart_unmap_sg, |
713 | .alloc_coherent = gart_alloc_coherent, | ||
714 | .free_coherent = gart_free_coherent, | ||
704 | }; | 715 | }; |
705 | 716 | ||
706 | void gart_iommu_shutdown(void) | 717 | void gart_iommu_shutdown(void) |
@@ -760,8 +771,8 @@ void __init gart_iommu_init(void) | |||
760 | (no_agp && init_k8_gatt(&info) < 0)) { | 771 | (no_agp && init_k8_gatt(&info) < 0)) { |
761 | if (max_pfn > MAX_DMA32_PFN) { | 772 | if (max_pfn > MAX_DMA32_PFN) { |
762 | printk(KERN_WARNING "More than 4GB of memory " | 773 | printk(KERN_WARNING "More than 4GB of memory " |
763 | "but GART IOMMU not available.\n" | 774 | "but GART IOMMU not available.\n"); |
764 | KERN_WARNING "falling back to iommu=soft.\n"); | 775 | printk(KERN_WARNING "falling back to iommu=soft.\n"); |
765 | } | 776 | } |
766 | return; | 777 | return; |
767 | } | 778 | } |
@@ -779,19 +790,16 @@ void __init gart_iommu_init(void) | |||
779 | iommu_size = check_iommu_size(info.aper_base, aper_size); | 790 | iommu_size = check_iommu_size(info.aper_base, aper_size); |
780 | iommu_pages = iommu_size >> PAGE_SHIFT; | 791 | iommu_pages = iommu_size >> PAGE_SHIFT; |
781 | 792 | ||
782 | iommu_gart_bitmap = (void *) __get_free_pages(GFP_KERNEL, | 793 | iommu_gart_bitmap = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, |
783 | get_order(iommu_pages/8)); | 794 | get_order(iommu_pages/8)); |
784 | if (!iommu_gart_bitmap) | 795 | if (!iommu_gart_bitmap) |
785 | panic("Cannot allocate iommu bitmap\n"); | 796 | panic("Cannot allocate iommu bitmap\n"); |
786 | memset(iommu_gart_bitmap, 0, iommu_pages/8); | ||
787 | 797 | ||
788 | #ifdef CONFIG_IOMMU_LEAK | 798 | #ifdef CONFIG_IOMMU_LEAK |
789 | if (leak_trace) { | 799 | if (leak_trace) { |
790 | iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL, | 800 | iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, |
791 | get_order(iommu_pages*sizeof(void *))); | 801 | get_order(iommu_pages*sizeof(void *))); |
792 | if (iommu_leak_tab) | 802 | if (!iommu_leak_tab) |
793 | memset(iommu_leak_tab, 0, iommu_pages * 8); | ||
794 | else | ||
795 | printk(KERN_DEBUG | 803 | printk(KERN_DEBUG |
796 | "PCI-DMA: Cannot allocate leak trace area\n"); | 804 | "PCI-DMA: Cannot allocate leak trace area\n"); |
797 | } | 805 | } |
@@ -801,7 +809,7 @@ void __init gart_iommu_init(void) | |||
801 | * Out of IOMMU space handling. | 809 | * Out of IOMMU space handling. |
802 | * Reserve some invalid pages at the beginning of the GART. | 810 | * Reserve some invalid pages at the beginning of the GART. |
803 | */ | 811 | */ |
804 | set_bit_string(iommu_gart_bitmap, 0, EMERGENCY_PAGES); | 812 | iommu_area_reserve(iommu_gart_bitmap, 0, EMERGENCY_PAGES); |
805 | 813 | ||
806 | agp_memory_reserved = iommu_size; | 814 | agp_memory_reserved = iommu_size; |
807 | printk(KERN_INFO | 815 | printk(KERN_INFO |
@@ -859,7 +867,8 @@ void __init gart_parse_options(char *p) | |||
859 | if (!strncmp(p, "leak", 4)) { | 867 | if (!strncmp(p, "leak", 4)) { |
860 | leak_trace = 1; | 868 | leak_trace = 1; |
861 | p += 4; | 869 | p += 4; |
862 | if (*p == '=') ++p; | 870 | if (*p == '=') |
871 | ++p; | ||
863 | if (isdigit(*p) && get_option(&p, &arg)) | 872 | if (isdigit(*p) && get_option(&p, &arg)) |
864 | iommu_leak_pages = arg; | 873 | iommu_leak_pages = arg; |
865 | } | 874 | } |