blob: c56e9ee64964df91f8c27fbc681472716c109572 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Dynamic DMA mapping support for AMD Hammer.
3 *
4 * Use the integrated AGP GART in the Hammer northbridge as an IOMMU for PCI.
5 * This allows to use PCI devices that only support 32bit addresses on systems
6 * with more than 4GB.
7 *
8 * See Documentation/DMA-mapping.txt for the interface specification.
9 *
10 * Copyright 2002 Andi Kleen, SuSE Labs.
Andi Kleenff7f3642007-10-17 18:04:37 +020011 * Subject to the GNU General Public License v2 only.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
13
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/types.h>
15#include <linux/ctype.h>
16#include <linux/agp_backend.h>
17#include <linux/init.h>
18#include <linux/mm.h>
19#include <linux/string.h>
20#include <linux/spinlock.h>
21#include <linux/pci.h>
22#include <linux/module.h>
23#include <linux/topology.h>
24#include <linux/interrupt.h>
25#include <linux/bitops.h>
Christoph Hellwig1eeb66a2007-05-08 00:27:03 -070026#include <linux/kdebug.h>
Jens Axboe9ee1bea2007-10-04 09:35:37 +020027#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <asm/atomic.h>
29#include <asm/io.h>
30#include <asm/mtrr.h>
31#include <asm/pgtable.h>
32#include <asm/proto.h>
Yinghai Luf2cf8e02007-07-21 17:11:31 +020033#include <asm/iommu.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/cacheflush.h>
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +010035#include <asm/swiotlb.h>
36#include <asm/dma.h>
Andi Kleena32073b2006-06-26 13:56:40 +020037#include <asm/k8.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39unsigned long iommu_bus_base; /* GART remapping area (physical) */
40static unsigned long iommu_size; /* size of remapping area bytes */
41static unsigned long iommu_pages; /* .. and in pages */
42
43u32 *iommu_gatt_base; /* Remapping table */
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045/* If this is disabled the IOMMU will use an optimized flushing strategy
46 of only flushing when an mapping is reused. With it true the GART is flushed
47 for every mapping. Problem is that doing the lazy flush seems to trigger
48 bugs with some popular PCI cards, in particular 3ware (but has been also
49 also seen with Qlogic at least). */
50int iommu_fullflush = 1;
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052/* Allocation bitmap for the remapping area */
53static DEFINE_SPINLOCK(iommu_bitmap_lock);
54static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
55
56static u32 gart_unmapped_entry;
57
58#define GPTE_VALID 1
59#define GPTE_COHERENT 2
60#define GPTE_ENCODE(x) \
61 (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT)
62#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28))
63
64#define to_pages(addr,size) \
65 (round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT)
66
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#define EMERGENCY_PAGES 32 /* = 128KB */
68
69#ifdef CONFIG_AGP
70#define AGPEXTERN extern
71#else
72#define AGPEXTERN
73#endif
74
75/* backdoor interface to AGP driver */
76AGPEXTERN int agp_memory_reserved;
77AGPEXTERN __u32 *agp_gatt_table;
78
79static unsigned long next_bit; /* protected by iommu_bitmap_lock */
80static int need_flush; /* global flush state. set for each gart wrap */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82static unsigned long alloc_iommu(int size)
83{
84 unsigned long offset, flags;
85
86 spin_lock_irqsave(&iommu_bitmap_lock, flags);
87 offset = find_next_zero_string(iommu_gart_bitmap,next_bit,iommu_pages,size);
88 if (offset == -1) {
89 need_flush = 1;
Mike Waychisonf5adc9c2006-06-26 13:56:31 +020090 offset = find_next_zero_string(iommu_gart_bitmap,0,iommu_pages,size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 }
92 if (offset != -1) {
93 set_bit_string(iommu_gart_bitmap, offset, size);
94 next_bit = offset+size;
95 if (next_bit >= iommu_pages) {
96 next_bit = 0;
97 need_flush = 1;
98 }
99 }
100 if (iommu_fullflush)
101 need_flush = 1;
102 spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
103 return offset;
104}
105
106static void free_iommu(unsigned long offset, int size)
107{
108 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 spin_lock_irqsave(&iommu_bitmap_lock, flags);
110 __clear_bit_string(iommu_gart_bitmap, offset, size);
111 spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
112}
113
114/*
115 * Use global flush state to avoid races with multiple flushers.
116 */
Andi Kleena32073b2006-06-26 13:56:40 +0200117static void flush_gart(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118{
119 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 spin_lock_irqsave(&iommu_bitmap_lock, flags);
Andi Kleena32073b2006-06-26 13:56:40 +0200121 if (need_flush) {
122 k8_flush_garts();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 need_flush = 0;
124 }
125 spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
126}
127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128#ifdef CONFIG_IOMMU_LEAK
129
130#define SET_LEAK(x) if (iommu_leak_tab) \
131 iommu_leak_tab[x] = __builtin_return_address(0);
132#define CLEAR_LEAK(x) if (iommu_leak_tab) \
133 iommu_leak_tab[x] = NULL;
134
135/* Debugging aid for drivers that don't free their IOMMU tables */
136static void **iommu_leak_tab;
137static int leak_trace;
138int iommu_leak_pages = 20;
139void dump_leak(void)
140{
141 int i;
142 static int dump;
143 if (dump || !iommu_leak_tab) return;
144 dump = 1;
145 show_stack(NULL,NULL);
146 /* Very crude. dump some from the end of the table too */
147 printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_pages);
148 for (i = 0; i < iommu_leak_pages; i+=2) {
149 printk("%lu: ", iommu_pages-i);
150 printk_address((unsigned long) iommu_leak_tab[iommu_pages-i]);
151 printk("%c", (i+1)%2 == 0 ? '\n' : ' ');
152 }
153 printk("\n");
154}
155#else
156#define SET_LEAK(x)
157#define CLEAR_LEAK(x)
158#endif
159
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100160static void iommu_full(struct device *dev, size_t size, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161{
162 /*
163 * Ran out of IOMMU space for this operation. This is very bad.
164 * Unfortunately the drivers cannot handle this operation properly.
165 * Return some non mapped prereserved space in the aperture and
166 * let the Northbridge deal with it. This will result in garbage
167 * in the IO operation. When the size exceeds the prereserved space
168 * memory corruption will occur or random memory will be DMAed
169 * out. Hopefully no network devices use single mappings that big.
170 */
171
172 printk(KERN_ERR
173 "PCI-DMA: Out of IOMMU space for %lu bytes at device %s\n",
174 size, dev->bus_id);
175
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100176 if (size > PAGE_SIZE*EMERGENCY_PAGES) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL)
178 panic("PCI-DMA: Memory would be corrupted\n");
179 if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL)
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100180 panic(KERN_ERR "PCI-DMA: Random memory would be DMAed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 }
182
183#ifdef CONFIG_IOMMU_LEAK
184 dump_leak();
185#endif
186}
187
188static inline int need_iommu(struct device *dev, unsigned long addr, size_t size)
189{
190 u64 mask = *dev->dma_mask;
Andi Kleen00edefa2007-02-13 13:26:24 +0100191 int high = addr + size > mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 int mmu = high;
193 if (force_iommu)
194 mmu = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 return mmu;
196}
197
198static inline int nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
199{
200 u64 mask = *dev->dma_mask;
Andi Kleen00edefa2007-02-13 13:26:24 +0100201 int high = addr + size > mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 int mmu = high;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 return mmu;
204}
205
206/* Map a single continuous physical area into the IOMMU.
207 * Caller needs to check if the iommu is needed and flush.
208 */
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100209static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
210 size_t size, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
212 unsigned long npages = to_pages(phys_mem, size);
213 unsigned long iommu_page = alloc_iommu(npages);
214 int i;
215 if (iommu_page == -1) {
216 if (!nonforced_iommu(dev, phys_mem, size))
217 return phys_mem;
218 if (panic_on_overflow)
219 panic("dma_map_area overflow %lu bytes\n", size);
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100220 iommu_full(dev, size, dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 return bad_dma_address;
222 }
223
224 for (i = 0; i < npages; i++) {
225 iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem);
226 SET_LEAK(iommu_page + i);
227 phys_mem += PAGE_SIZE;
228 }
229 return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK);
230}
231
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100232static dma_addr_t gart_map_simple(struct device *dev, char *buf,
233 size_t size, int dir)
234{
235 dma_addr_t map = dma_map_area(dev, virt_to_bus(buf), size, dir);
Andi Kleena32073b2006-06-26 13:56:40 +0200236 flush_gart();
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100237 return map;
238}
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240/* Map a single area into the IOMMU */
Yinghai Lu1048fa52007-07-21 17:11:23 +0200241static dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242{
243 unsigned long phys_mem, bus;
244
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 if (!dev)
246 dev = &fallback_dev;
247
248 phys_mem = virt_to_phys(addr);
249 if (!need_iommu(dev, phys_mem, size))
250 return phys_mem;
251
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100252 bus = gart_map_simple(dev, addr, size, dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 return bus;
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100254}
255
256/*
Jon Mason7c2d9cd2006-06-26 13:56:37 +0200257 * Free a DMA mapping.
258 */
Yinghai Lu1048fa52007-07-21 17:11:23 +0200259static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
Jon Mason7c2d9cd2006-06-26 13:56:37 +0200260 size_t size, int direction)
261{
262 unsigned long iommu_page;
263 int npages;
264 int i;
265
266 if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE ||
267 dma_addr >= iommu_bus_base + iommu_size)
268 return;
269 iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;
270 npages = to_pages(dma_addr, size);
271 for (i = 0; i < npages; i++) {
272 iommu_gatt_base[iommu_page + i] = gart_unmapped_entry;
273 CLEAR_LEAK(iommu_page + i);
274 }
275 free_iommu(iommu_page, npages);
276}
277
278/*
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100279 * Wrapper for pci_unmap_single working with scatterlists.
280 */
Yinghai Lu1048fa52007-07-21 17:11:23 +0200281static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100282{
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200283 struct scatterlist *s;
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100284 int i;
285
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200286 for_each_sg(sg, s, nents, i) {
Jon Mason60b08c62006-02-26 04:18:22 +0100287 if (!s->dma_length || !s->length)
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100288 break;
Jon Mason7c2d9cd2006-06-26 13:56:37 +0200289 gart_unmap_single(dev, s->dma_address, s->dma_length, dir);
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100290 }
291}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
293/* Fallback for dma_map_sg in case of overflow */
294static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,
295 int nents, int dir)
296{
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200297 struct scatterlist *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 int i;
299
300#ifdef CONFIG_IOMMU_DEBUG
301 printk(KERN_DEBUG "dma_map_sg overflow\n");
302#endif
303
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200304 for_each_sg(sg, s, nents, i) {
Jens Axboe58b053e2007-10-22 20:02:46 +0200305 unsigned long addr = sg_phys(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 if (nonforced_iommu(dev, addr, s->length)) {
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100307 addr = dma_map_area(dev, addr, s->length, dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (addr == bad_dma_address) {
309 if (i > 0)
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100310 gart_unmap_sg(dev, sg, i, dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 nents = 0;
312 sg[0].dma_length = 0;
313 break;
314 }
315 }
316 s->dma_address = addr;
317 s->dma_length = s->length;
318 }
Andi Kleena32073b2006-06-26 13:56:40 +0200319 flush_gart();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 return nents;
321}
322
323/* Map multiple scatterlist entries continuous into the first. */
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200324static int __dma_map_cont(struct scatterlist *start, int nelems,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 struct scatterlist *sout, unsigned long pages)
326{
327 unsigned long iommu_start = alloc_iommu(pages);
328 unsigned long iommu_page = iommu_start;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200329 struct scatterlist *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 int i;
331
332 if (iommu_start == -1)
333 return -1;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200334
335 for_each_sg(start, s, nelems, i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 unsigned long pages, addr;
337 unsigned long phys_addr = s->dma_address;
338
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200339 BUG_ON(s != start && s->offset);
340 if (s == start) {
Jon Mason60b08c62006-02-26 04:18:22 +0100341 *sout = *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 sout->dma_address = iommu_bus_base;
343 sout->dma_address += iommu_page*PAGE_SIZE + s->offset;
344 sout->dma_length = s->length;
345 } else {
346 sout->dma_length += s->length;
347 }
348
349 addr = phys_addr;
350 pages = to_pages(s->offset, s->length);
351 while (pages--) {
352 iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr);
353 SET_LEAK(iommu_page);
354 addr += PAGE_SIZE;
355 iommu_page++;
Andi Kleen0d5410642006-02-12 14:34:59 -0800356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
358 BUG_ON(iommu_page - iommu_start != pages);
359 return 0;
360}
361
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200362static inline int dma_map_cont(struct scatterlist *start, int nelems,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 struct scatterlist *sout,
364 unsigned long pages, int need)
365{
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200366 if (!need) {
367 BUG_ON(nelems != 1);
368 *sout = *start;
369 sout->dma_length = start->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 return 0;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200371 }
372 return __dma_map_cont(start, nelems, sout, pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
375/*
376 * DMA map all entries in a scatterlist.
377 * Merge chunks that have page aligned sizes into a continuous mapping.
378 */
Andi Kleenff7f3642007-10-17 18:04:37 +0200379static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents,
380 int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
382 int i;
383 int out;
384 int start;
385 unsigned long pages = 0;
386 int need = 0, nextneed;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200387 struct scatterlist *s, *ps, *start_sg, *sgmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 if (nents == 0)
390 return 0;
391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 if (!dev)
393 dev = &fallback_dev;
394
395 out = 0;
396 start = 0;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200397 start_sg = sgmap = sg;
398 ps = NULL; /* shut up gcc */
399 for_each_sg(sg, s, nents, i) {
Jens Axboe58b053e2007-10-22 20:02:46 +0200400 dma_addr_t addr = sg_phys(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 s->dma_address = addr;
402 BUG_ON(s->length == 0);
403
404 nextneed = need_iommu(dev, addr, s->length);
405
406 /* Handle the previous not yet processed entries */
407 if (i > start) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 /* Can only merge when the last chunk ends on a page
409 boundary and the new one doesn't have an offset. */
410 if (!iommu_merge || !nextneed || !need || s->offset ||
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200411 (ps->offset + ps->length) % PAGE_SIZE) {
412 if (dma_map_cont(start_sg, i - start, sgmap,
413 pages, need) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 goto error;
415 out++;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200416 sgmap = sg_next(sgmap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 pages = 0;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200418 start = i;
419 start_sg = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 }
421 }
422
423 need = nextneed;
424 pages += to_pages(s->offset, s->length);
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200425 ps = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 }
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200427 if (dma_map_cont(start_sg, i - start, sgmap, pages, need) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 goto error;
429 out++;
Andi Kleena32073b2006-06-26 13:56:40 +0200430 flush_gart();
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200431 if (out < nents) {
432 sgmap = sg_next(sgmap);
433 sgmap->dma_length = 0;
434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 return out;
436
437error:
Andi Kleena32073b2006-06-26 13:56:40 +0200438 flush_gart();
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100439 gart_unmap_sg(dev, sg, nents, dir);
Kevin VanMarena1002a42006-02-03 21:51:32 +0100440 /* When it was forced or merged try again in a dumb way */
441 if (force_iommu || iommu_merge) {
442 out = dma_map_sg_nonforce(dev, sg, nents, dir);
443 if (out > 0)
444 return out;
445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 if (panic_on_overflow)
447 panic("dma_map_sg: overflow on %lu pages\n", pages);
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100448 iommu_full(dev, pages << PAGE_SHIFT, dir);
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200449 for_each_sg(sg, s, nents, i)
450 s->dma_address = bad_dma_address;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 return 0;
452}
453
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100454static int no_agp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
457{
458 unsigned long a;
459 if (!iommu_size) {
460 iommu_size = aper_size;
461 if (!no_agp)
462 iommu_size /= 2;
463 }
464
465 a = aper + iommu_size;
466 iommu_size -= round_up(a, LARGE_PAGE_SIZE) - a;
467
468 if (iommu_size < 64*1024*1024)
469 printk(KERN_WARNING
470 "PCI-DMA: Warning: Small IOMMU %luMB. Consider increasing the AGP aperture in BIOS\n",iommu_size>>20);
471
472 return iommu_size;
473}
474
475static __init unsigned read_aperture(struct pci_dev *dev, u32 *size)
476{
477 unsigned aper_size = 0, aper_base_32;
478 u64 aper_base;
479 unsigned aper_order;
480
481 pci_read_config_dword(dev, 0x94, &aper_base_32);
482 pci_read_config_dword(dev, 0x90, &aper_order);
483 aper_order = (aper_order >> 1) & 7;
484
485 aper_base = aper_base_32 & 0x7fff;
486 aper_base <<= 25;
487
488 aper_size = (32 * 1024 * 1024) << aper_order;
Andrew Hastings547c5352007-05-11 11:23:19 +0200489 if (aper_base + aper_size > 0x100000000UL || !aper_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 aper_base = 0;
491
492 *size = aper_size;
493 return aper_base;
494}
495
496/*
497 * Private Northbridge GATT initialization in case we cannot use the
498 * AGP driver for some reason.
499 */
500static __init int init_k8_gatt(struct agp_kern_info *info)
501{
502 struct pci_dev *dev;
503 void *gatt;
504 unsigned aper_base, new_aper_base;
505 unsigned aper_size, gatt_size, new_aper_size;
Andi Kleena32073b2006-06-26 13:56:40 +0200506 int i;
507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
509 aper_size = aper_base = info->aper_size = 0;
Andi Kleena32073b2006-06-26 13:56:40 +0200510 dev = NULL;
511 for (i = 0; i < num_k8_northbridges; i++) {
512 dev = k8_northbridges[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 new_aper_base = read_aperture(dev, &new_aper_size);
514 if (!new_aper_base)
515 goto nommu;
516
517 if (!aper_base) {
518 aper_size = new_aper_size;
519 aper_base = new_aper_base;
520 }
521 if (aper_size != new_aper_size || aper_base != new_aper_base)
522 goto nommu;
523 }
524 if (!aper_base)
525 goto nommu;
526 info->aper_base = aper_base;
527 info->aper_size = aper_size>>20;
528
529 gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32);
530 gatt = (void *)__get_free_pages(GFP_KERNEL, get_order(gatt_size));
531 if (!gatt)
Joachim Deguaracf6387d2007-04-24 13:05:36 +0200532 panic("Cannot allocate GATT table");
533 if (change_page_attr_addr((unsigned long)gatt, gatt_size >> PAGE_SHIFT, PAGE_KERNEL_NOCACHE))
534 panic("Could not set GART PTEs to uncacheable pages");
535 global_flush_tlb();
536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 memset(gatt, 0, gatt_size);
538 agp_gatt_table = gatt;
Andi Kleena32073b2006-06-26 13:56:40 +0200539
540 for (i = 0; i < num_k8_northbridges; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 u32 ctl;
542 u32 gatt_reg;
543
Andi Kleena32073b2006-06-26 13:56:40 +0200544 dev = k8_northbridges[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 gatt_reg = __pa(gatt) >> 12;
546 gatt_reg <<= 4;
547 pci_write_config_dword(dev, 0x98, gatt_reg);
548 pci_read_config_dword(dev, 0x90, &ctl);
549
550 ctl |= 1;
551 ctl &= ~((1<<4) | (1<<5));
552
553 pci_write_config_dword(dev, 0x90, ctl);
554 }
Andi Kleena32073b2006-06-26 13:56:40 +0200555 flush_gart();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557 printk("PCI-DMA: aperture base @ %x size %u KB\n",aper_base, aper_size>>10);
558 return 0;
559
560 nommu:
561 /* Should not happen anymore */
562 printk(KERN_ERR "PCI-DMA: More than 4GB of RAM and no IOMMU\n"
Andi Kleenf46ace62006-01-11 22:43:27 +0100563 KERN_ERR "PCI-DMA: 32bit PCI IO may malfunction.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 return -1;
565}
566
567extern int agp_amd64_init(void);
568
Stephen Hemmingere6584502007-05-02 19:27:06 +0200569static const struct dma_mapping_ops gart_dma_ops = {
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100570 .mapping_error = NULL,
571 .map_single = gart_map_single,
572 .map_simple = gart_map_simple,
573 .unmap_single = gart_unmap_single,
574 .sync_single_for_cpu = NULL,
575 .sync_single_for_device = NULL,
576 .sync_single_range_for_cpu = NULL,
577 .sync_single_range_for_device = NULL,
578 .sync_sg_for_cpu = NULL,
579 .sync_sg_for_device = NULL,
580 .map_sg = gart_map_sg,
581 .unmap_sg = gart_unmap_sg,
582};
583
Yinghai Lubc2cea62007-07-21 17:11:28 +0200584void gart_iommu_shutdown(void)
585{
586 struct pci_dev *dev;
587 int i;
588
589 if (no_agp && (dma_ops != &gart_dma_ops))
590 return;
591
592 for (i = 0; i < num_k8_northbridges; i++) {
593 u32 ctl;
594
595 dev = k8_northbridges[i];
596 pci_read_config_dword(dev, 0x90, &ctl);
597
598 ctl &= ~1;
599
600 pci_write_config_dword(dev, 0x90, ctl);
601 }
602}
603
Jon Mason0dc243a2006-06-26 13:58:11 +0200604void __init gart_iommu_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
606 struct agp_kern_info info;
607 unsigned long aper_size;
608 unsigned long iommu_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 unsigned long scratch;
610 long i;
611
Andi Kleena32073b2006-06-26 13:56:40 +0200612 if (cache_k8_northbridges() < 0 || num_k8_northbridges == 0) {
613 printk(KERN_INFO "PCI-GART: No AMD northbridge found.\n");
Jon Mason0dc243a2006-06-26 13:58:11 +0200614 return;
Andi Kleena32073b2006-06-26 13:56:40 +0200615 }
616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617#ifndef CONFIG_AGP_AMD64
618 no_agp = 1;
619#else
620 /* Makefile puts PCI initialization via subsys_initcall first. */
621 /* Add other K8 AGP bridge drivers here */
622 no_agp = no_agp ||
623 (agp_amd64_init() < 0) ||
624 (agp_copy_info(agp_bridge, &info) < 0);
625#endif
626
Jon Mason60b08c62006-02-26 04:18:22 +0100627 if (swiotlb)
Jon Mason0dc243a2006-06-26 13:58:11 +0200628 return;
Jon Mason60b08c62006-02-26 04:18:22 +0100629
Jon Mason8d4f6b92006-06-26 13:58:05 +0200630 /* Did we detect a different HW IOMMU? */
631 if (iommu_detected && !iommu_aperture)
Jon Mason0dc243a2006-06-26 13:58:11 +0200632 return;
Jon Mason8d4f6b92006-06-26 13:58:05 +0200633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 if (no_iommu ||
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100635 (!force_iommu && end_pfn <= MAX_DMA32_PFN) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 !iommu_aperture ||
637 (no_agp && init_k8_gatt(&info) < 0)) {
Jon Mason5b7b6442006-02-03 21:51:59 +0100638 if (end_pfn > MAX_DMA32_PFN) {
639 printk(KERN_ERR "WARNING more than 4GB of memory "
Andi Kleen3807fd42006-12-07 02:14:13 +0100640 "but GART IOMMU not available.\n"
Andi Kleendc9a7192006-05-30 22:47:48 +0200641 KERN_ERR "WARNING 32bit PCI may malfunction.\n");
Jon Mason5b7b6442006-02-03 21:51:59 +0100642 }
Jon Mason0dc243a2006-06-26 13:58:11 +0200643 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
645
Jon Mason5b7b6442006-02-03 21:51:59 +0100646 printk(KERN_INFO "PCI-DMA: using GART IOMMU.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 aper_size = info.aper_size * 1024 * 1024;
648 iommu_size = check_iommu_size(info.aper_base, aper_size);
649 iommu_pages = iommu_size >> PAGE_SHIFT;
650
651 iommu_gart_bitmap = (void*)__get_free_pages(GFP_KERNEL,
652 get_order(iommu_pages/8));
653 if (!iommu_gart_bitmap)
654 panic("Cannot allocate iommu bitmap\n");
655 memset(iommu_gart_bitmap, 0, iommu_pages/8);
656
657#ifdef CONFIG_IOMMU_LEAK
658 if (leak_trace) {
659 iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL,
660 get_order(iommu_pages*sizeof(void *)));
661 if (iommu_leak_tab)
662 memset(iommu_leak_tab, 0, iommu_pages * 8);
663 else
664 printk("PCI-DMA: Cannot allocate leak trace area\n");
665 }
666#endif
667
668 /*
669 * Out of IOMMU space handling.
670 * Reserve some invalid pages at the beginning of the GART.
671 */
672 set_bit_string(iommu_gart_bitmap, 0, EMERGENCY_PAGES);
673
674 agp_memory_reserved = iommu_size;
675 printk(KERN_INFO
676 "PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n",
677 iommu_size>>20);
678
679 iommu_start = aper_size - iommu_size;
680 iommu_bus_base = info.aper_base + iommu_start;
681 bad_dma_address = iommu_bus_base;
682 iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT);
683
684 /*
685 * Unmap the IOMMU part of the GART. The alias of the page is
686 * always mapped with cache enabled and there is no full cache
687 * coherency across the GART remapping. The unmapping avoids
688 * automatic prefetches from the CPU allocating cache lines in
689 * there. All CPU accesses are done via the direct mapping to
690 * the backing memory. The GART address is only used by PCI
691 * devices.
692 */
693 clear_kernel_mapping((unsigned long)__va(iommu_bus_base), iommu_size);
694
695 /*
696 * Try to workaround a bug (thanks to BenH)
697 * Set unmapped entries to a scratch page instead of 0.
698 * Any prefetches that hit unmapped entries won't get an bus abort
699 * then.
700 */
701 scratch = get_zeroed_page(GFP_KERNEL);
702 if (!scratch)
703 panic("Cannot allocate iommu scratch page");
704 gart_unmapped_entry = GPTE_ENCODE(__pa(scratch));
705 for (i = EMERGENCY_PAGES; i < iommu_pages; i++)
706 iommu_gatt_base[i] = gart_unmapped_entry;
707
Andi Kleena32073b2006-06-26 13:56:40 +0200708 flush_gart();
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100709 dma_ops = &gart_dma_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710}
711
Sam Ravnborg43999d92007-03-16 21:07:36 +0100712void __init gart_parse_options(char *p)
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100713{
714 int arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716#ifdef CONFIG_IOMMU_LEAK
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100717 if (!strncmp(p,"leak",4)) {
718 leak_trace = 1;
719 p += 4;
720 if (*p == '=') ++p;
721 if (isdigit(*p) && get_option(&p, &arg))
722 iommu_leak_pages = arg;
723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724#endif
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100725 if (isdigit(*p) && get_option(&p, &arg))
726 iommu_size = arg;
727 if (!strncmp(p, "fullflush",8))
728 iommu_fullflush = 1;
729 if (!strncmp(p, "nofullflush",11))
730 iommu_fullflush = 0;
731 if (!strncmp(p,"noagp",5))
732 no_agp = 1;
733 if (!strncmp(p, "noaperture",10))
734 fix_aperture = 0;
735 /* duplicated from pci-dma.c */
736 if (!strncmp(p,"force",5))
737 iommu_aperture_allowed = 1;
738 if (!strncmp(p,"allowed",7))
739 iommu_aperture_allowed = 1;
740 if (!strncmp(p, "memaper", 7)) {
741 fallback_aper_force = 1;
742 p += 7;
743 if (*p == '=') {
744 ++p;
745 if (get_option(&p, &arg))
746 fallback_aper_order = arg;
747 }
748 }
749}