blob: 06bcba536045ae5ca038ffa9ac3f6c16b6b26a2e [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>
Joerg Roedel395624f2007-10-24 12:49:47 +020033#include <asm/gart.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
Joerg Roedel79da0872007-10-24 12:49:49 +020039static unsigned long iommu_bus_base; /* GART remapping area (physical) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070040static unsigned long iommu_size; /* size of remapping area bytes */
41static unsigned long iommu_pages; /* .. and in pages */
42
Joerg Roedel79da0872007-10-24 12:49:49 +020043static u32 *iommu_gatt_base; /* Remapping table */
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
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;
Joerg Roedel79da0872007-10-24 12:49:49 +0200138static int iommu_leak_pages = 20;
139static void dump_leak(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
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) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 sout->dma_address = iommu_bus_base;
342 sout->dma_address += iommu_page*PAGE_SIZE + s->offset;
343 sout->dma_length = s->length;
344 } else {
345 sout->dma_length += s->length;
346 }
347
348 addr = phys_addr;
349 pages = to_pages(s->offset, s->length);
350 while (pages--) {
351 iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr);
352 SET_LEAK(iommu_page);
353 addr += PAGE_SIZE;
354 iommu_page++;
Andi Kleen0d5410642006-02-12 14:34:59 -0800355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
357 BUG_ON(iommu_page - iommu_start != pages);
358 return 0;
359}
360
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200361static inline int dma_map_cont(struct scatterlist *start, int nelems,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 struct scatterlist *sout,
363 unsigned long pages, int need)
364{
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200365 if (!need) {
366 BUG_ON(nelems != 1);
FUJITA Tomonorie88a39d2007-10-25 09:13:32 +0200367 sout->dma_address = start->dma_address;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200368 sout->dma_length = start->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 return 0;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200370 }
371 return __dma_map_cont(start, nelems, sout, pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372}
373
374/*
375 * DMA map all entries in a scatterlist.
376 * Merge chunks that have page aligned sizes into a continuous mapping.
377 */
Andi Kleenff7f3642007-10-17 18:04:37 +0200378static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents,
379 int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 int i;
382 int out;
383 int start;
384 unsigned long pages = 0;
385 int need = 0, nextneed;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200386 struct scatterlist *s, *ps, *start_sg, *sgmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (nents == 0)
389 return 0;
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (!dev)
392 dev = &fallback_dev;
393
394 out = 0;
395 start = 0;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200396 start_sg = sgmap = sg;
397 ps = NULL; /* shut up gcc */
398 for_each_sg(sg, s, nents, i) {
Jens Axboe58b053e2007-10-22 20:02:46 +0200399 dma_addr_t addr = sg_phys(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 s->dma_address = addr;
401 BUG_ON(s->length == 0);
402
403 nextneed = need_iommu(dev, addr, s->length);
404
405 /* Handle the previous not yet processed entries */
406 if (i > start) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 /* Can only merge when the last chunk ends on a page
408 boundary and the new one doesn't have an offset. */
409 if (!iommu_merge || !nextneed || !need || s->offset ||
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200410 (ps->offset + ps->length) % PAGE_SIZE) {
411 if (dma_map_cont(start_sg, i - start, sgmap,
412 pages, need) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 goto error;
414 out++;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200415 sgmap = sg_next(sgmap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 pages = 0;
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200417 start = i;
418 start_sg = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 }
420 }
421
422 need = nextneed;
423 pages += to_pages(s->offset, s->length);
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200424 ps = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 }
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200426 if (dma_map_cont(start_sg, i - start, sgmap, pages, need) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 goto error;
428 out++;
Andi Kleena32073b2006-06-26 13:56:40 +0200429 flush_gart();
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200430 if (out < nents) {
431 sgmap = sg_next(sgmap);
432 sgmap->dma_length = 0;
433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 return out;
435
436error:
Andi Kleena32073b2006-06-26 13:56:40 +0200437 flush_gart();
FUJITA Tomonori53369402007-10-26 13:56:24 +0200438 gart_unmap_sg(dev, sg, out, dir);
Kevin VanMarena1002a42006-02-03 21:51:32 +0100439 /* When it was forced or merged try again in a dumb way */
440 if (force_iommu || iommu_merge) {
441 out = dma_map_sg_nonforce(dev, sg, nents, dir);
442 if (out > 0)
443 return out;
444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 if (panic_on_overflow)
446 panic("dma_map_sg: overflow on %lu pages\n", pages);
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100447 iommu_full(dev, pages << PAGE_SHIFT, dir);
Jens Axboe9ee1bea2007-10-04 09:35:37 +0200448 for_each_sg(sg, s, nents, i)
449 s->dma_address = bad_dma_address;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return 0;
451}
452
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100453static int no_agp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
456{
457 unsigned long a;
458 if (!iommu_size) {
459 iommu_size = aper_size;
460 if (!no_agp)
461 iommu_size /= 2;
462 }
463
464 a = aper + iommu_size;
465 iommu_size -= round_up(a, LARGE_PAGE_SIZE) - a;
466
467 if (iommu_size < 64*1024*1024)
468 printk(KERN_WARNING
469 "PCI-DMA: Warning: Small IOMMU %luMB. Consider increasing the AGP aperture in BIOS\n",iommu_size>>20);
470
471 return iommu_size;
472}
473
474static __init unsigned read_aperture(struct pci_dev *dev, u32 *size)
475{
476 unsigned aper_size = 0, aper_base_32;
477 u64 aper_base;
478 unsigned aper_order;
479
480 pci_read_config_dword(dev, 0x94, &aper_base_32);
481 pci_read_config_dword(dev, 0x90, &aper_order);
482 aper_order = (aper_order >> 1) & 7;
483
484 aper_base = aper_base_32 & 0x7fff;
485 aper_base <<= 25;
486
487 aper_size = (32 * 1024 * 1024) << aper_order;
Andrew Hastings547c5352007-05-11 11:23:19 +0200488 if (aper_base + aper_size > 0x100000000UL || !aper_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 aper_base = 0;
490
491 *size = aper_size;
492 return aper_base;
493}
494
495/*
496 * Private Northbridge GATT initialization in case we cannot use the
497 * AGP driver for some reason.
498 */
499static __init int init_k8_gatt(struct agp_kern_info *info)
500{
501 struct pci_dev *dev;
502 void *gatt;
503 unsigned aper_base, new_aper_base;
504 unsigned aper_size, gatt_size, new_aper_size;
Andi Kleena32073b2006-06-26 13:56:40 +0200505 int i;
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
508 aper_size = aper_base = info->aper_size = 0;
Andi Kleena32073b2006-06-26 13:56:40 +0200509 dev = NULL;
510 for (i = 0; i < num_k8_northbridges; i++) {
511 dev = k8_northbridges[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 new_aper_base = read_aperture(dev, &new_aper_size);
513 if (!new_aper_base)
514 goto nommu;
515
516 if (!aper_base) {
517 aper_size = new_aper_size;
518 aper_base = new_aper_base;
519 }
520 if (aper_size != new_aper_size || aper_base != new_aper_base)
521 goto nommu;
522 }
523 if (!aper_base)
524 goto nommu;
525 info->aper_base = aper_base;
526 info->aper_size = aper_size>>20;
527
528 gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32);
529 gatt = (void *)__get_free_pages(GFP_KERNEL, get_order(gatt_size));
530 if (!gatt)
Joachim Deguaracf6387d2007-04-24 13:05:36 +0200531 panic("Cannot allocate GATT table");
532 if (change_page_attr_addr((unsigned long)gatt, gatt_size >> PAGE_SHIFT, PAGE_KERNEL_NOCACHE))
533 panic("Could not set GART PTEs to uncacheable pages");
534 global_flush_tlb();
535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 memset(gatt, 0, gatt_size);
537 agp_gatt_table = gatt;
Andi Kleena32073b2006-06-26 13:56:40 +0200538
539 for (i = 0; i < num_k8_northbridges; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 u32 ctl;
541 u32 gatt_reg;
542
Andi Kleena32073b2006-06-26 13:56:40 +0200543 dev = k8_northbridges[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 gatt_reg = __pa(gatt) >> 12;
545 gatt_reg <<= 4;
546 pci_write_config_dword(dev, 0x98, gatt_reg);
547 pci_read_config_dword(dev, 0x90, &ctl);
548
549 ctl |= 1;
550 ctl &= ~((1<<4) | (1<<5));
551
552 pci_write_config_dword(dev, 0x90, ctl);
553 }
Andi Kleena32073b2006-06-26 13:56:40 +0200554 flush_gart();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 printk("PCI-DMA: aperture base @ %x size %u KB\n",aper_base, aper_size>>10);
557 return 0;
558
559 nommu:
560 /* Should not happen anymore */
561 printk(KERN_ERR "PCI-DMA: More than 4GB of RAM and no IOMMU\n"
Andi Kleenf46ace62006-01-11 22:43:27 +0100562 KERN_ERR "PCI-DMA: 32bit PCI IO may malfunction.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 return -1;
564}
565
566extern int agp_amd64_init(void);
567
Stephen Hemmingere6584502007-05-02 19:27:06 +0200568static const struct dma_mapping_ops gart_dma_ops = {
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100569 .mapping_error = NULL,
570 .map_single = gart_map_single,
571 .map_simple = gart_map_simple,
572 .unmap_single = gart_unmap_single,
573 .sync_single_for_cpu = NULL,
574 .sync_single_for_device = NULL,
575 .sync_single_range_for_cpu = NULL,
576 .sync_single_range_for_device = NULL,
577 .sync_sg_for_cpu = NULL,
578 .sync_sg_for_device = NULL,
579 .map_sg = gart_map_sg,
580 .unmap_sg = gart_unmap_sg,
581};
582
Yinghai Lubc2cea62007-07-21 17:11:28 +0200583void gart_iommu_shutdown(void)
584{
585 struct pci_dev *dev;
586 int i;
587
588 if (no_agp && (dma_ops != &gart_dma_ops))
589 return;
590
591 for (i = 0; i < num_k8_northbridges; i++) {
592 u32 ctl;
593
594 dev = k8_northbridges[i];
595 pci_read_config_dword(dev, 0x90, &ctl);
596
597 ctl &= ~1;
598
599 pci_write_config_dword(dev, 0x90, ctl);
600 }
601}
602
Jon Mason0dc243a2006-06-26 13:58:11 +0200603void __init gart_iommu_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
605 struct agp_kern_info info;
606 unsigned long aper_size;
607 unsigned long iommu_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 unsigned long scratch;
609 long i;
610
Andi Kleena32073b2006-06-26 13:56:40 +0200611 if (cache_k8_northbridges() < 0 || num_k8_northbridges == 0) {
612 printk(KERN_INFO "PCI-GART: No AMD northbridge found.\n");
Jon Mason0dc243a2006-06-26 13:58:11 +0200613 return;
Andi Kleena32073b2006-06-26 13:56:40 +0200614 }
615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616#ifndef CONFIG_AGP_AMD64
617 no_agp = 1;
618#else
619 /* Makefile puts PCI initialization via subsys_initcall first. */
620 /* Add other K8 AGP bridge drivers here */
621 no_agp = no_agp ||
622 (agp_amd64_init() < 0) ||
623 (agp_copy_info(agp_bridge, &info) < 0);
624#endif
625
Jon Mason60b08c62006-02-26 04:18:22 +0100626 if (swiotlb)
Jon Mason0dc243a2006-06-26 13:58:11 +0200627 return;
Jon Mason60b08c62006-02-26 04:18:22 +0100628
Jon Mason8d4f6b92006-06-26 13:58:05 +0200629 /* Did we detect a different HW IOMMU? */
Joerg Roedel0440d4c2007-10-24 12:49:50 +0200630 if (iommu_detected && !gart_iommu_aperture)
Jon Mason0dc243a2006-06-26 13:58:11 +0200631 return;
Jon Mason8d4f6b92006-06-26 13:58:05 +0200632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 if (no_iommu ||
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100634 (!force_iommu && end_pfn <= MAX_DMA32_PFN) ||
Joerg Roedel0440d4c2007-10-24 12:49:50 +0200635 !gart_iommu_aperture ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 (no_agp && init_k8_gatt(&info) < 0)) {
Jon Mason5b7b6442006-02-03 21:51:59 +0100637 if (end_pfn > MAX_DMA32_PFN) {
638 printk(KERN_ERR "WARNING more than 4GB of memory "
Andi Kleen3807fd42006-12-07 02:14:13 +0100639 "but GART IOMMU not available.\n"
Andi Kleendc9a7192006-05-30 22:47:48 +0200640 KERN_ERR "WARNING 32bit PCI may malfunction.\n");
Jon Mason5b7b6442006-02-03 21:51:59 +0100641 }
Jon Mason0dc243a2006-06-26 13:58:11 +0200642 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644
Jon Mason5b7b6442006-02-03 21:51:59 +0100645 printk(KERN_INFO "PCI-DMA: using GART IOMMU.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 aper_size = info.aper_size * 1024 * 1024;
647 iommu_size = check_iommu_size(info.aper_base, aper_size);
648 iommu_pages = iommu_size >> PAGE_SHIFT;
649
650 iommu_gart_bitmap = (void*)__get_free_pages(GFP_KERNEL,
651 get_order(iommu_pages/8));
652 if (!iommu_gart_bitmap)
653 panic("Cannot allocate iommu bitmap\n");
654 memset(iommu_gart_bitmap, 0, iommu_pages/8);
655
656#ifdef CONFIG_IOMMU_LEAK
657 if (leak_trace) {
658 iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL,
659 get_order(iommu_pages*sizeof(void *)));
660 if (iommu_leak_tab)
661 memset(iommu_leak_tab, 0, iommu_pages * 8);
662 else
663 printk("PCI-DMA: Cannot allocate leak trace area\n");
664 }
665#endif
666
667 /*
668 * Out of IOMMU space handling.
669 * Reserve some invalid pages at the beginning of the GART.
670 */
671 set_bit_string(iommu_gart_bitmap, 0, EMERGENCY_PAGES);
672
673 agp_memory_reserved = iommu_size;
674 printk(KERN_INFO
675 "PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n",
676 iommu_size>>20);
677
678 iommu_start = aper_size - iommu_size;
679 iommu_bus_base = info.aper_base + iommu_start;
680 bad_dma_address = iommu_bus_base;
681 iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT);
682
683 /*
684 * Unmap the IOMMU part of the GART. The alias of the page is
685 * always mapped with cache enabled and there is no full cache
686 * coherency across the GART remapping. The unmapping avoids
687 * automatic prefetches from the CPU allocating cache lines in
688 * there. All CPU accesses are done via the direct mapping to
689 * the backing memory. The GART address is only used by PCI
690 * devices.
691 */
692 clear_kernel_mapping((unsigned long)__va(iommu_bus_base), iommu_size);
693
694 /*
695 * Try to workaround a bug (thanks to BenH)
696 * Set unmapped entries to a scratch page instead of 0.
697 * Any prefetches that hit unmapped entries won't get an bus abort
698 * then.
699 */
700 scratch = get_zeroed_page(GFP_KERNEL);
701 if (!scratch)
702 panic("Cannot allocate iommu scratch page");
703 gart_unmapped_entry = GPTE_ENCODE(__pa(scratch));
704 for (i = EMERGENCY_PAGES; i < iommu_pages; i++)
705 iommu_gatt_base[i] = gart_unmapped_entry;
706
Andi Kleena32073b2006-06-26 13:56:40 +0200707 flush_gart();
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100708 dma_ops = &gart_dma_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
710
Sam Ravnborg43999d92007-03-16 21:07:36 +0100711void __init gart_parse_options(char *p)
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100712{
713 int arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715#ifdef CONFIG_IOMMU_LEAK
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100716 if (!strncmp(p,"leak",4)) {
717 leak_trace = 1;
718 p += 4;
719 if (*p == '=') ++p;
720 if (isdigit(*p) && get_option(&p, &arg))
721 iommu_leak_pages = arg;
722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723#endif
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100724 if (isdigit(*p) && get_option(&p, &arg))
725 iommu_size = arg;
726 if (!strncmp(p, "fullflush",8))
727 iommu_fullflush = 1;
728 if (!strncmp(p, "nofullflush",11))
729 iommu_fullflush = 0;
730 if (!strncmp(p,"noagp",5))
731 no_agp = 1;
732 if (!strncmp(p, "noaperture",10))
733 fix_aperture = 0;
734 /* duplicated from pci-dma.c */
735 if (!strncmp(p,"force",5))
Joerg Roedel0440d4c2007-10-24 12:49:50 +0200736 gart_iommu_aperture_allowed = 1;
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100737 if (!strncmp(p,"allowed",7))
Joerg Roedel0440d4c2007-10-24 12:49:50 +0200738 gart_iommu_aperture_allowed = 1;
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +0100739 if (!strncmp(p, "memaper", 7)) {
740 fallback_aper_force = 1;
741 p += 7;
742 if (*p == '=') {
743 ++p;
744 if (get_option(&p, &arg))
745 fallback_aper_order = arg;
746 }
747 }
748}