blob: 22ad8851b3e07aed26093749911a3d041695d568 [file] [log] [blame]
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001/*
2 * Copyright (c) 2006, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
mark gross98bcef52008-02-23 15:23:35 -080017 * Copyright (C) 2006-2008 Intel Corporation
18 * Author: Ashok Raj <ashok.raj@intel.com>
19 * Author: Shaohua Li <shaohua.li@intel.com>
20 * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Fenghua Yu5b6985c2008-10-16 18:02:32 -070021 * Author: Fenghua Yu <fenghua.yu@intel.com>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070022 */
23
24#include <linux/init.h>
25#include <linux/bitmap.h>
mark gross5e0d2a62008-03-04 15:22:08 -080026#include <linux/debugfs.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070027#include <linux/slab.h>
28#include <linux/irq.h>
29#include <linux/interrupt.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070030#include <linux/spinlock.h>
31#include <linux/pci.h>
32#include <linux/dmar.h>
33#include <linux/dma-mapping.h>
34#include <linux/mempool.h>
mark gross5e0d2a62008-03-04 15:22:08 -080035#include <linux/timer.h>
Kay, Allen M38717942008-09-09 18:37:29 +030036#include <linux/iova.h>
37#include <linux/intel-iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070038#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090039#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070040#include "pci.h"
41
Fenghua Yu5b6985c2008-10-16 18:02:32 -070042#define ROOT_SIZE VTD_PAGE_SIZE
43#define CONTEXT_SIZE VTD_PAGE_SIZE
44
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070045#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
46#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
47
48#define IOAPIC_RANGE_START (0xfee00000)
49#define IOAPIC_RANGE_END (0xfeefffff)
50#define IOVA_START_ADDR (0x1000)
51
52#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
53
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070054#define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
55
Mark McLoughlinf27be032008-11-20 15:49:43 +000056#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
57#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
58#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
mark gross5e0d2a62008-03-04 15:22:08 -080059
Mark McLoughlin46b08e12008-11-20 15:49:44 +000060/*
61 * 0: Present
62 * 1-11: Reserved
63 * 12-63: Context Ptr (12 - (haw-1))
64 * 64-127: Reserved
65 */
66struct root_entry {
67 u64 val;
68 u64 rsvd1;
69};
70#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
71static inline bool root_present(struct root_entry *root)
72{
73 return (root->val & 1);
74}
75static inline void set_root_present(struct root_entry *root)
76{
77 root->val |= 1;
78}
79static inline void set_root_value(struct root_entry *root, unsigned long value)
80{
81 root->val |= value & VTD_PAGE_MASK;
82}
83
84static inline struct context_entry *
85get_context_addr_from_root(struct root_entry *root)
86{
87 return (struct context_entry *)
88 (root_present(root)?phys_to_virt(
89 root->val & VTD_PAGE_MASK) :
90 NULL);
91}
92
Mark McLoughlin7a8fc252008-11-20 15:49:45 +000093/*
94 * low 64 bits:
95 * 0: present
96 * 1: fault processing disable
97 * 2-3: translation type
98 * 12-63: address space root
99 * high 64 bits:
100 * 0-2: address width
101 * 3-6: aval
102 * 8-23: domain id
103 */
104struct context_entry {
105 u64 lo;
106 u64 hi;
107};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000108
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000109static inline bool context_present(struct context_entry *context)
110{
111 return (context->lo & 1);
112}
113static inline void context_set_present(struct context_entry *context)
114{
115 context->lo |= 1;
116}
117
118static inline void context_set_fault_enable(struct context_entry *context)
119{
120 context->lo &= (((u64)-1) << 2) | 1;
121}
122
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000123#define CONTEXT_TT_MULTI_LEVEL 0
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000124
125static inline void context_set_translation_type(struct context_entry *context,
126 unsigned long value)
127{
128 context->lo &= (((u64)-1) << 4) | 3;
129 context->lo |= (value & 3) << 2;
130}
131
132static inline void context_set_address_root(struct context_entry *context,
133 unsigned long value)
134{
135 context->lo |= value & VTD_PAGE_MASK;
136}
137
138static inline void context_set_address_width(struct context_entry *context,
139 unsigned long value)
140{
141 context->hi |= value & 7;
142}
143
144static inline void context_set_domain_id(struct context_entry *context,
145 unsigned long value)
146{
147 context->hi |= (value & ((1 << 16) - 1)) << 8;
148}
149
150static inline void context_clear_entry(struct context_entry *context)
151{
152 context->lo = 0;
153 context->hi = 0;
154}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000155
Mark McLoughlin622ba122008-11-20 15:49:46 +0000156/*
157 * 0: readable
158 * 1: writable
159 * 2-6: reserved
160 * 7: super page
161 * 8-11: available
162 * 12-63: Host physcial address
163 */
164struct dma_pte {
165 u64 val;
166};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000167
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000168static inline void dma_clear_pte(struct dma_pte *pte)
169{
170 pte->val = 0;
171}
172
173static inline void dma_set_pte_readable(struct dma_pte *pte)
174{
175 pte->val |= DMA_PTE_READ;
176}
177
178static inline void dma_set_pte_writable(struct dma_pte *pte)
179{
180 pte->val |= DMA_PTE_WRITE;
181}
182
183static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
184{
185 pte->val = (pte->val & ~3) | (prot & 3);
186}
187
188static inline u64 dma_pte_addr(struct dma_pte *pte)
189{
190 return (pte->val & VTD_PAGE_MASK);
191}
192
193static inline void dma_set_pte_addr(struct dma_pte *pte, u64 addr)
194{
195 pte->val |= (addr & VTD_PAGE_MASK);
196}
197
198static inline bool dma_pte_present(struct dma_pte *pte)
199{
200 return (pte->val & 3) != 0;
201}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000202
Weidong Han3b5410e2008-12-08 09:17:15 +0800203/* devices under the same p2p bridge are owned in one domain */
204#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 < 0)
205
Mark McLoughlin99126f72008-11-20 15:49:47 +0000206struct dmar_domain {
207 int id; /* domain id */
208 struct intel_iommu *iommu; /* back pointer to owning iommu */
209
210 struct list_head devices; /* all devices' list */
211 struct iova_domain iovad; /* iova's that belong to this domain */
212
213 struct dma_pte *pgd; /* virtual address */
214 spinlock_t mapping_lock; /* page table lock */
215 int gaw; /* max guest address width */
216
217 /* adjusted guest address width, 0 is level 2 30-bit */
218 int agaw;
219
Weidong Han3b5410e2008-12-08 09:17:15 +0800220 int flags; /* flags to find out type of domain */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000221};
222
Mark McLoughlina647dac2008-11-20 15:49:48 +0000223/* PCI domain-device relationship */
224struct device_domain_info {
225 struct list_head link; /* link to domain siblings */
226 struct list_head global; /* link to global list */
227 u8 bus; /* PCI bus numer */
228 u8 devfn; /* PCI devfn number */
229 struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
230 struct dmar_domain *domain; /* pointer to domain */
231};
232
mark gross5e0d2a62008-03-04 15:22:08 -0800233static void flush_unmaps_timeout(unsigned long data);
234
235DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
236
mark gross80b20dd2008-04-18 13:53:58 -0700237#define HIGH_WATER_MARK 250
238struct deferred_flush_tables {
239 int next;
240 struct iova *iova[HIGH_WATER_MARK];
241 struct dmar_domain *domain[HIGH_WATER_MARK];
242};
243
244static struct deferred_flush_tables *deferred_flush;
245
mark gross5e0d2a62008-03-04 15:22:08 -0800246/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800247static int g_num_of_iommus;
248
249static DEFINE_SPINLOCK(async_umap_flush_lock);
250static LIST_HEAD(unmaps_to_do);
251
252static int timer_on;
253static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800254
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700255static void domain_remove_dev_info(struct dmar_domain *domain);
256
Suresh Siddha2ae21012008-07-10 11:16:43 -0700257int dmar_disabled;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700258static int __initdata dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700259static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800260static int intel_iommu_strict;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700261
262#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
263static DEFINE_SPINLOCK(device_domain_lock);
264static LIST_HEAD(device_domain_list);
265
266static int __init intel_iommu_setup(char *str)
267{
268 if (!str)
269 return -EINVAL;
270 while (*str) {
271 if (!strncmp(str, "off", 3)) {
272 dmar_disabled = 1;
273 printk(KERN_INFO"Intel-IOMMU: disabled\n");
274 } else if (!strncmp(str, "igfx_off", 8)) {
275 dmar_map_gfx = 0;
276 printk(KERN_INFO
277 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700278 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800279 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700280 "Intel-IOMMU: Forcing DAC for PCI devices\n");
281 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800282 } else if (!strncmp(str, "strict", 6)) {
283 printk(KERN_INFO
284 "Intel-IOMMU: disable batched IOTLB flush\n");
285 intel_iommu_strict = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700286 }
287
288 str += strcspn(str, ",");
289 while (*str == ',')
290 str++;
291 }
292 return 0;
293}
294__setup("intel_iommu=", intel_iommu_setup);
295
296static struct kmem_cache *iommu_domain_cache;
297static struct kmem_cache *iommu_devinfo_cache;
298static struct kmem_cache *iommu_iova_cache;
299
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700300static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep)
301{
302 unsigned int flags;
303 void *vaddr;
304
305 /* trying to avoid low memory issues */
306 flags = current->flags & PF_MEMALLOC;
307 current->flags |= PF_MEMALLOC;
308 vaddr = kmem_cache_alloc(cachep, GFP_ATOMIC);
309 current->flags &= (~PF_MEMALLOC | flags);
310 return vaddr;
311}
312
313
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700314static inline void *alloc_pgtable_page(void)
315{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700316 unsigned int flags;
317 void *vaddr;
318
319 /* trying to avoid low memory issues */
320 flags = current->flags & PF_MEMALLOC;
321 current->flags |= PF_MEMALLOC;
322 vaddr = (void *)get_zeroed_page(GFP_ATOMIC);
323 current->flags &= (~PF_MEMALLOC | flags);
324 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700325}
326
327static inline void free_pgtable_page(void *vaddr)
328{
329 free_page((unsigned long)vaddr);
330}
331
332static inline void *alloc_domain_mem(void)
333{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700334 return iommu_kmem_cache_alloc(iommu_domain_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700335}
336
Kay, Allen M38717942008-09-09 18:37:29 +0300337static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700338{
339 kmem_cache_free(iommu_domain_cache, vaddr);
340}
341
342static inline void * alloc_devinfo_mem(void)
343{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700344 return iommu_kmem_cache_alloc(iommu_devinfo_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700345}
346
347static inline void free_devinfo_mem(void *vaddr)
348{
349 kmem_cache_free(iommu_devinfo_cache, vaddr);
350}
351
352struct iova *alloc_iova_mem(void)
353{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700354 return iommu_kmem_cache_alloc(iommu_iova_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700355}
356
357void free_iova_mem(struct iova *iova)
358{
359 kmem_cache_free(iommu_iova_cache, iova);
360}
361
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700362/* Gets context entry for a given bus and devfn */
363static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
364 u8 bus, u8 devfn)
365{
366 struct root_entry *root;
367 struct context_entry *context;
368 unsigned long phy_addr;
369 unsigned long flags;
370
371 spin_lock_irqsave(&iommu->lock, flags);
372 root = &iommu->root_entry[bus];
373 context = get_context_addr_from_root(root);
374 if (!context) {
375 context = (struct context_entry *)alloc_pgtable_page();
376 if (!context) {
377 spin_unlock_irqrestore(&iommu->lock, flags);
378 return NULL;
379 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700380 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700381 phy_addr = virt_to_phys((void *)context);
382 set_root_value(root, phy_addr);
383 set_root_present(root);
384 __iommu_flush_cache(iommu, root, sizeof(*root));
385 }
386 spin_unlock_irqrestore(&iommu->lock, flags);
387 return &context[devfn];
388}
389
390static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
391{
392 struct root_entry *root;
393 struct context_entry *context;
394 int ret;
395 unsigned long flags;
396
397 spin_lock_irqsave(&iommu->lock, flags);
398 root = &iommu->root_entry[bus];
399 context = get_context_addr_from_root(root);
400 if (!context) {
401 ret = 0;
402 goto out;
403 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000404 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700405out:
406 spin_unlock_irqrestore(&iommu->lock, flags);
407 return ret;
408}
409
410static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
411{
412 struct root_entry *root;
413 struct context_entry *context;
414 unsigned long flags;
415
416 spin_lock_irqsave(&iommu->lock, flags);
417 root = &iommu->root_entry[bus];
418 context = get_context_addr_from_root(root);
419 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000420 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700421 __iommu_flush_cache(iommu, &context[devfn], \
422 sizeof(*context));
423 }
424 spin_unlock_irqrestore(&iommu->lock, flags);
425}
426
427static void free_context_table(struct intel_iommu *iommu)
428{
429 struct root_entry *root;
430 int i;
431 unsigned long flags;
432 struct context_entry *context;
433
434 spin_lock_irqsave(&iommu->lock, flags);
435 if (!iommu->root_entry) {
436 goto out;
437 }
438 for (i = 0; i < ROOT_ENTRY_NR; i++) {
439 root = &iommu->root_entry[i];
440 context = get_context_addr_from_root(root);
441 if (context)
442 free_pgtable_page(context);
443 }
444 free_pgtable_page(iommu->root_entry);
445 iommu->root_entry = NULL;
446out:
447 spin_unlock_irqrestore(&iommu->lock, flags);
448}
449
450/* page table handling */
451#define LEVEL_STRIDE (9)
452#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
453
454static inline int agaw_to_level(int agaw)
455{
456 return agaw + 2;
457}
458
459static inline int agaw_to_width(int agaw)
460{
461 return 30 + agaw * LEVEL_STRIDE;
462
463}
464
465static inline int width_to_agaw(int width)
466{
467 return (width - 30) / LEVEL_STRIDE;
468}
469
470static inline unsigned int level_to_offset_bits(int level)
471{
472 return (12 + (level - 1) * LEVEL_STRIDE);
473}
474
475static inline int address_level_offset(u64 addr, int level)
476{
477 return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK);
478}
479
480static inline u64 level_mask(int level)
481{
482 return ((u64)-1 << level_to_offset_bits(level));
483}
484
485static inline u64 level_size(int level)
486{
487 return ((u64)1 << level_to_offset_bits(level));
488}
489
490static inline u64 align_to_level(u64 addr, int level)
491{
492 return ((addr + level_size(level) - 1) & level_mask(level));
493}
494
495static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
496{
497 int addr_width = agaw_to_width(domain->agaw);
498 struct dma_pte *parent, *pte = NULL;
499 int level = agaw_to_level(domain->agaw);
500 int offset;
501 unsigned long flags;
502
503 BUG_ON(!domain->pgd);
504
505 addr &= (((u64)1) << addr_width) - 1;
506 parent = domain->pgd;
507
508 spin_lock_irqsave(&domain->mapping_lock, flags);
509 while (level > 0) {
510 void *tmp_page;
511
512 offset = address_level_offset(addr, level);
513 pte = &parent[offset];
514 if (level == 1)
515 break;
516
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000517 if (!dma_pte_present(pte)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700518 tmp_page = alloc_pgtable_page();
519
520 if (!tmp_page) {
521 spin_unlock_irqrestore(&domain->mapping_lock,
522 flags);
523 return NULL;
524 }
525 __iommu_flush_cache(domain->iommu, tmp_page,
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700526 PAGE_SIZE);
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000527 dma_set_pte_addr(pte, virt_to_phys(tmp_page));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700528 /*
529 * high level table always sets r/w, last level page
530 * table control read/write
531 */
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000532 dma_set_pte_readable(pte);
533 dma_set_pte_writable(pte);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700534 __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
535 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000536 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700537 level--;
538 }
539
540 spin_unlock_irqrestore(&domain->mapping_lock, flags);
541 return pte;
542}
543
544/* return address's pte at specific level */
545static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
546 int level)
547{
548 struct dma_pte *parent, *pte = NULL;
549 int total = agaw_to_level(domain->agaw);
550 int offset;
551
552 parent = domain->pgd;
553 while (level <= total) {
554 offset = address_level_offset(addr, total);
555 pte = &parent[offset];
556 if (level == total)
557 return pte;
558
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000559 if (!dma_pte_present(pte))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700560 break;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000561 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700562 total--;
563 }
564 return NULL;
565}
566
567/* clear one page's page table */
568static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
569{
570 struct dma_pte *pte = NULL;
571
572 /* get last level pte */
573 pte = dma_addr_level_pte(domain, addr, 1);
574
575 if (pte) {
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000576 dma_clear_pte(pte);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700577 __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
578 }
579}
580
581/* clear last level pte, a tlb flush should be followed */
582static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
583{
584 int addr_width = agaw_to_width(domain->agaw);
585
586 start &= (((u64)1) << addr_width) - 1;
587 end &= (((u64)1) << addr_width) - 1;
588 /* in case it's partial page */
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700589 start = PAGE_ALIGN(start);
590 end &= PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700591
592 /* we don't need lock here, nobody else touches the iova range */
593 while (start < end) {
594 dma_pte_clear_one(domain, start);
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700595 start += VTD_PAGE_SIZE;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700596 }
597}
598
599/* free page table pages. last level pte should already be cleared */
600static void dma_pte_free_pagetable(struct dmar_domain *domain,
601 u64 start, u64 end)
602{
603 int addr_width = agaw_to_width(domain->agaw);
604 struct dma_pte *pte;
605 int total = agaw_to_level(domain->agaw);
606 int level;
607 u64 tmp;
608
609 start &= (((u64)1) << addr_width) - 1;
610 end &= (((u64)1) << addr_width) - 1;
611
612 /* we don't need lock here, nobody else touches the iova range */
613 level = 2;
614 while (level <= total) {
615 tmp = align_to_level(start, level);
616 if (tmp >= end || (tmp + level_size(level) > end))
617 return;
618
619 while (tmp < end) {
620 pte = dma_addr_level_pte(domain, tmp, level);
621 if (pte) {
622 free_pgtable_page(
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000623 phys_to_virt(dma_pte_addr(pte)));
624 dma_clear_pte(pte);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700625 __iommu_flush_cache(domain->iommu,
626 pte, sizeof(*pte));
627 }
628 tmp += level_size(level);
629 }
630 level++;
631 }
632 /* free pgd */
633 if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
634 free_pgtable_page(domain->pgd);
635 domain->pgd = NULL;
636 }
637}
638
639/* iommu handling */
640static int iommu_alloc_root_entry(struct intel_iommu *iommu)
641{
642 struct root_entry *root;
643 unsigned long flags;
644
645 root = (struct root_entry *)alloc_pgtable_page();
646 if (!root)
647 return -ENOMEM;
648
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700649 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700650
651 spin_lock_irqsave(&iommu->lock, flags);
652 iommu->root_entry = root;
653 spin_unlock_irqrestore(&iommu->lock, flags);
654
655 return 0;
656}
657
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700658static void iommu_set_root_entry(struct intel_iommu *iommu)
659{
660 void *addr;
661 u32 cmd, sts;
662 unsigned long flag;
663
664 addr = iommu->root_entry;
665
666 spin_lock_irqsave(&iommu->register_lock, flag);
667 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
668
669 cmd = iommu->gcmd | DMA_GCMD_SRTP;
670 writel(cmd, iommu->reg + DMAR_GCMD_REG);
671
672 /* Make sure hardware complete it */
673 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
674 readl, (sts & DMA_GSTS_RTPS), sts);
675
676 spin_unlock_irqrestore(&iommu->register_lock, flag);
677}
678
679static void iommu_flush_write_buffer(struct intel_iommu *iommu)
680{
681 u32 val;
682 unsigned long flag;
683
684 if (!cap_rwbf(iommu->cap))
685 return;
686 val = iommu->gcmd | DMA_GCMD_WBF;
687
688 spin_lock_irqsave(&iommu->register_lock, flag);
689 writel(val, iommu->reg + DMAR_GCMD_REG);
690
691 /* Make sure hardware complete it */
692 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
693 readl, (!(val & DMA_GSTS_WBFS)), val);
694
695 spin_unlock_irqrestore(&iommu->register_lock, flag);
696}
697
698/* return value determine if we need a write buffer flush */
699static int __iommu_flush_context(struct intel_iommu *iommu,
700 u16 did, u16 source_id, u8 function_mask, u64 type,
701 int non_present_entry_flush)
702{
703 u64 val = 0;
704 unsigned long flag;
705
706 /*
707 * In the non-present entry flush case, if hardware doesn't cache
708 * non-present entry we do nothing and if hardware cache non-present
709 * entry, we flush entries of domain 0 (the domain id is used to cache
710 * any non-present entries)
711 */
712 if (non_present_entry_flush) {
713 if (!cap_caching_mode(iommu->cap))
714 return 1;
715 else
716 did = 0;
717 }
718
719 switch (type) {
720 case DMA_CCMD_GLOBAL_INVL:
721 val = DMA_CCMD_GLOBAL_INVL;
722 break;
723 case DMA_CCMD_DOMAIN_INVL:
724 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
725 break;
726 case DMA_CCMD_DEVICE_INVL:
727 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
728 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
729 break;
730 default:
731 BUG();
732 }
733 val |= DMA_CCMD_ICC;
734
735 spin_lock_irqsave(&iommu->register_lock, flag);
736 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
737
738 /* Make sure hardware complete it */
739 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
740 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
741
742 spin_unlock_irqrestore(&iommu->register_lock, flag);
743
Ameya Palande4d235ba2008-10-18 20:27:30 -0700744 /* flush context entry will implicitly flush write buffer */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700745 return 0;
746}
747
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700748/* return value determine if we need a write buffer flush */
749static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
750 u64 addr, unsigned int size_order, u64 type,
751 int non_present_entry_flush)
752{
753 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
754 u64 val = 0, val_iva = 0;
755 unsigned long flag;
756
757 /*
758 * In the non-present entry flush case, if hardware doesn't cache
759 * non-present entry we do nothing and if hardware cache non-present
760 * entry, we flush entries of domain 0 (the domain id is used to cache
761 * any non-present entries)
762 */
763 if (non_present_entry_flush) {
764 if (!cap_caching_mode(iommu->cap))
765 return 1;
766 else
767 did = 0;
768 }
769
770 switch (type) {
771 case DMA_TLB_GLOBAL_FLUSH:
772 /* global flush doesn't need set IVA_REG */
773 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
774 break;
775 case DMA_TLB_DSI_FLUSH:
776 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
777 break;
778 case DMA_TLB_PSI_FLUSH:
779 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
780 /* Note: always flush non-leaf currently */
781 val_iva = size_order | addr;
782 break;
783 default:
784 BUG();
785 }
786 /* Note: set drain read/write */
787#if 0
788 /*
789 * This is probably to be super secure.. Looks like we can
790 * ignore it without any impact.
791 */
792 if (cap_read_drain(iommu->cap))
793 val |= DMA_TLB_READ_DRAIN;
794#endif
795 if (cap_write_drain(iommu->cap))
796 val |= DMA_TLB_WRITE_DRAIN;
797
798 spin_lock_irqsave(&iommu->register_lock, flag);
799 /* Note: Only uses first TLB reg currently */
800 if (val_iva)
801 dmar_writeq(iommu->reg + tlb_offset, val_iva);
802 dmar_writeq(iommu->reg + tlb_offset + 8, val);
803
804 /* Make sure hardware complete it */
805 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
806 dmar_readq, (!(val & DMA_TLB_IVT)), val);
807
808 spin_unlock_irqrestore(&iommu->register_lock, flag);
809
810 /* check IOTLB invalidation granularity */
811 if (DMA_TLB_IAIG(val) == 0)
812 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
813 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
814 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700815 (unsigned long long)DMA_TLB_IIRG(type),
816 (unsigned long long)DMA_TLB_IAIG(val));
Ameya Palande4d235ba2008-10-18 20:27:30 -0700817 /* flush iotlb entry will implicitly flush write buffer */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700818 return 0;
819}
820
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700821static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
822 u64 addr, unsigned int pages, int non_present_entry_flush)
823{
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700824 unsigned int mask;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700825
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700826 BUG_ON(addr & (~VTD_PAGE_MASK));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700827 BUG_ON(pages == 0);
828
829 /* Fallback to domain selective flush if no PSI support */
830 if (!cap_pgsel_inv(iommu->cap))
Youquan Songa77b67d2008-10-16 16:31:56 -0700831 return iommu->flush.flush_iotlb(iommu, did, 0, 0,
832 DMA_TLB_DSI_FLUSH,
833 non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700834
835 /*
836 * PSI requires page size to be 2 ^ x, and the base address is naturally
837 * aligned to the size
838 */
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700839 mask = ilog2(__roundup_pow_of_two(pages));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700840 /* Fallback to domain selective flush if size is too big */
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700841 if (mask > cap_max_amask_val(iommu->cap))
Youquan Songa77b67d2008-10-16 16:31:56 -0700842 return iommu->flush.flush_iotlb(iommu, did, 0, 0,
843 DMA_TLB_DSI_FLUSH, non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700844
Youquan Songa77b67d2008-10-16 16:31:56 -0700845 return iommu->flush.flush_iotlb(iommu, did, addr, mask,
846 DMA_TLB_PSI_FLUSH,
847 non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700848}
849
mark grossf8bab732008-02-08 04:18:38 -0800850static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
851{
852 u32 pmen;
853 unsigned long flags;
854
855 spin_lock_irqsave(&iommu->register_lock, flags);
856 pmen = readl(iommu->reg + DMAR_PMEN_REG);
857 pmen &= ~DMA_PMEN_EPM;
858 writel(pmen, iommu->reg + DMAR_PMEN_REG);
859
860 /* wait for the protected region status bit to clear */
861 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
862 readl, !(pmen & DMA_PMEN_PRS), pmen);
863
864 spin_unlock_irqrestore(&iommu->register_lock, flags);
865}
866
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700867static int iommu_enable_translation(struct intel_iommu *iommu)
868{
869 u32 sts;
870 unsigned long flags;
871
872 spin_lock_irqsave(&iommu->register_lock, flags);
873 writel(iommu->gcmd|DMA_GCMD_TE, iommu->reg + DMAR_GCMD_REG);
874
875 /* Make sure hardware complete it */
876 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
877 readl, (sts & DMA_GSTS_TES), sts);
878
879 iommu->gcmd |= DMA_GCMD_TE;
880 spin_unlock_irqrestore(&iommu->register_lock, flags);
881 return 0;
882}
883
884static int iommu_disable_translation(struct intel_iommu *iommu)
885{
886 u32 sts;
887 unsigned long flag;
888
889 spin_lock_irqsave(&iommu->register_lock, flag);
890 iommu->gcmd &= ~DMA_GCMD_TE;
891 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
892
893 /* Make sure hardware complete it */
894 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
895 readl, (!(sts & DMA_GSTS_TES)), sts);
896
897 spin_unlock_irqrestore(&iommu->register_lock, flag);
898 return 0;
899}
900
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -0700901/* iommu interrupt handling. Most stuff are MSI-like. */
902
mark grossd94afc62008-02-08 04:18:39 -0800903static const char *fault_reason_strings[] =
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -0700904{
905 "Software",
906 "Present bit in root entry is clear",
907 "Present bit in context entry is clear",
908 "Invalid context entry",
909 "Access beyond MGAW",
910 "PTE Write access is not set",
911 "PTE Read access is not set",
912 "Next page table ptr is invalid",
913 "Root table address invalid",
914 "Context table ptr is invalid",
915 "non-zero reserved fields in RTP",
916 "non-zero reserved fields in CTP",
917 "non-zero reserved fields in PTE",
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -0700918};
mark grossf8bab732008-02-08 04:18:38 -0800919#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -0700920
mark grossd94afc62008-02-08 04:18:39 -0800921const char *dmar_get_fault_reason(u8 fault_reason)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -0700922{
mark grossd94afc62008-02-08 04:18:39 -0800923 if (fault_reason > MAX_FAULT_REASON_IDX)
924 return "Unknown";
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -0700925 else
926 return fault_reason_strings[fault_reason];
927}
928
929void dmar_msi_unmask(unsigned int irq)
930{
931 struct intel_iommu *iommu = get_irq_data(irq);
932 unsigned long flag;
933
934 /* unmask it */
935 spin_lock_irqsave(&iommu->register_lock, flag);
936 writel(0, iommu->reg + DMAR_FECTL_REG);
937 /* Read a reg to force flush the post write */
938 readl(iommu->reg + DMAR_FECTL_REG);
939 spin_unlock_irqrestore(&iommu->register_lock, flag);
940}
941
942void dmar_msi_mask(unsigned int irq)
943{
944 unsigned long flag;
945 struct intel_iommu *iommu = get_irq_data(irq);
946
947 /* mask it */
948 spin_lock_irqsave(&iommu->register_lock, flag);
949 writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
950 /* Read a reg to force flush the post write */
951 readl(iommu->reg + DMAR_FECTL_REG);
952 spin_unlock_irqrestore(&iommu->register_lock, flag);
953}
954
955void dmar_msi_write(int irq, struct msi_msg *msg)
956{
957 struct intel_iommu *iommu = get_irq_data(irq);
958 unsigned long flag;
959
960 spin_lock_irqsave(&iommu->register_lock, flag);
961 writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
962 writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
963 writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
964 spin_unlock_irqrestore(&iommu->register_lock, flag);
965}
966
967void dmar_msi_read(int irq, struct msi_msg *msg)
968{
969 struct intel_iommu *iommu = get_irq_data(irq);
970 unsigned long flag;
971
972 spin_lock_irqsave(&iommu->register_lock, flag);
973 msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
974 msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
975 msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
976 spin_unlock_irqrestore(&iommu->register_lock, flag);
977}
978
979static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type,
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700980 u8 fault_reason, u16 source_id, unsigned long long addr)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -0700981{
mark grossd94afc62008-02-08 04:18:39 -0800982 const char *reason;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -0700983
984 reason = dmar_get_fault_reason(fault_reason);
985
986 printk(KERN_ERR
987 "DMAR:[%s] Request device [%02x:%02x.%d] "
988 "fault addr %llx \n"
989 "DMAR:[fault reason %02d] %s\n",
990 (type ? "DMA Read" : "DMA Write"),
991 (source_id >> 8), PCI_SLOT(source_id & 0xFF),
992 PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
993 return 0;
994}
995
996#define PRIMARY_FAULT_REG_LEN (16)
997static irqreturn_t iommu_page_fault(int irq, void *dev_id)
998{
999 struct intel_iommu *iommu = dev_id;
1000 int reg, fault_index;
1001 u32 fault_status;
1002 unsigned long flag;
1003
1004 spin_lock_irqsave(&iommu->register_lock, flag);
1005 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
1006
1007 /* TBD: ignore advanced fault log currently */
1008 if (!(fault_status & DMA_FSTS_PPF))
1009 goto clear_overflow;
1010
1011 fault_index = dma_fsts_fault_record_index(fault_status);
1012 reg = cap_fault_reg_offset(iommu->cap);
1013 while (1) {
1014 u8 fault_reason;
1015 u16 source_id;
1016 u64 guest_addr;
1017 int type;
1018 u32 data;
1019
1020 /* highest 32 bits */
1021 data = readl(iommu->reg + reg +
1022 fault_index * PRIMARY_FAULT_REG_LEN + 12);
1023 if (!(data & DMA_FRCD_F))
1024 break;
1025
1026 fault_reason = dma_frcd_fault_reason(data);
1027 type = dma_frcd_type(data);
1028
1029 data = readl(iommu->reg + reg +
1030 fault_index * PRIMARY_FAULT_REG_LEN + 8);
1031 source_id = dma_frcd_source_id(data);
1032
1033 guest_addr = dmar_readq(iommu->reg + reg +
1034 fault_index * PRIMARY_FAULT_REG_LEN);
1035 guest_addr = dma_frcd_page_addr(guest_addr);
1036 /* clear the fault */
1037 writel(DMA_FRCD_F, iommu->reg + reg +
1038 fault_index * PRIMARY_FAULT_REG_LEN + 12);
1039
1040 spin_unlock_irqrestore(&iommu->register_lock, flag);
1041
1042 iommu_page_fault_do_one(iommu, type, fault_reason,
1043 source_id, guest_addr);
1044
1045 fault_index++;
1046 if (fault_index > cap_num_fault_regs(iommu->cap))
1047 fault_index = 0;
1048 spin_lock_irqsave(&iommu->register_lock, flag);
1049 }
1050clear_overflow:
1051 /* clear primary fault overflow */
1052 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
1053 if (fault_status & DMA_FSTS_PFO)
1054 writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
1055
1056 spin_unlock_irqrestore(&iommu->register_lock, flag);
1057 return IRQ_HANDLED;
1058}
1059
1060int dmar_set_interrupt(struct intel_iommu *iommu)
1061{
1062 int irq, ret;
1063
1064 irq = create_irq();
1065 if (!irq) {
1066 printk(KERN_ERR "IOMMU: no free vectors\n");
1067 return -EINVAL;
1068 }
1069
1070 set_irq_data(irq, iommu);
1071 iommu->irq = irq;
1072
1073 ret = arch_setup_dmar_msi(irq);
1074 if (ret) {
1075 set_irq_data(irq, NULL);
1076 iommu->irq = 0;
1077 destroy_irq(irq);
1078 return 0;
1079 }
1080
1081 /* Force fault register is cleared */
1082 iommu_page_fault(irq, iommu);
1083
1084 ret = request_irq(irq, iommu_page_fault, 0, iommu->name, iommu);
1085 if (ret)
1086 printk(KERN_ERR "IOMMU: can't request irq\n");
1087 return ret;
1088}
1089
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001090static int iommu_init_domains(struct intel_iommu *iommu)
1091{
1092 unsigned long ndomains;
1093 unsigned long nlongs;
1094
1095 ndomains = cap_ndoms(iommu->cap);
1096 pr_debug("Number of Domains supportd <%ld>\n", ndomains);
1097 nlongs = BITS_TO_LONGS(ndomains);
1098
1099 /* TBD: there might be 64K domains,
1100 * consider other allocation for future chip
1101 */
1102 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1103 if (!iommu->domain_ids) {
1104 printk(KERN_ERR "Allocating domain id array failed\n");
1105 return -ENOMEM;
1106 }
1107 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1108 GFP_KERNEL);
1109 if (!iommu->domains) {
1110 printk(KERN_ERR "Allocating domain array failed\n");
1111 kfree(iommu->domain_ids);
1112 return -ENOMEM;
1113 }
1114
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001115 spin_lock_init(&iommu->lock);
1116
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001117 /*
1118 * if Caching mode is set, then invalid translations are tagged
1119 * with domainid 0. Hence we need to pre-allocate it.
1120 */
1121 if (cap_caching_mode(iommu->cap))
1122 set_bit(0, iommu->domain_ids);
1123 return 0;
1124}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001125
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001126
1127static void domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001128
1129void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001130{
1131 struct dmar_domain *domain;
1132 int i;
1133
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001134 i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
1135 for (; i < cap_ndoms(iommu->cap); ) {
1136 domain = iommu->domains[i];
1137 clear_bit(i, iommu->domain_ids);
1138 domain_exit(domain);
1139 i = find_next_bit(iommu->domain_ids,
1140 cap_ndoms(iommu->cap), i+1);
1141 }
1142
1143 if (iommu->gcmd & DMA_GCMD_TE)
1144 iommu_disable_translation(iommu);
1145
1146 if (iommu->irq) {
1147 set_irq_data(iommu->irq, NULL);
1148 /* This will mask the irq */
1149 free_irq(iommu->irq, iommu);
1150 destroy_irq(iommu->irq);
1151 }
1152
1153 kfree(iommu->domains);
1154 kfree(iommu->domain_ids);
1155
1156 /* free context mapping */
1157 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001158}
1159
1160static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
1161{
1162 unsigned long num;
1163 unsigned long ndomains;
1164 struct dmar_domain *domain;
1165 unsigned long flags;
1166
1167 domain = alloc_domain_mem();
1168 if (!domain)
1169 return NULL;
1170
1171 ndomains = cap_ndoms(iommu->cap);
1172
1173 spin_lock_irqsave(&iommu->lock, flags);
1174 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1175 if (num >= ndomains) {
1176 spin_unlock_irqrestore(&iommu->lock, flags);
1177 free_domain_mem(domain);
1178 printk(KERN_ERR "IOMMU: no free domain ids\n");
1179 return NULL;
1180 }
1181
1182 set_bit(num, iommu->domain_ids);
1183 domain->id = num;
1184 domain->iommu = iommu;
Weidong Hand71a2f32008-12-07 21:13:41 +08001185 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001186 iommu->domains[num] = domain;
1187 spin_unlock_irqrestore(&iommu->lock, flags);
1188
1189 return domain;
1190}
1191
1192static void iommu_free_domain(struct dmar_domain *domain)
1193{
1194 unsigned long flags;
1195
1196 spin_lock_irqsave(&domain->iommu->lock, flags);
1197 clear_bit(domain->id, domain->iommu->domain_ids);
1198 spin_unlock_irqrestore(&domain->iommu->lock, flags);
1199}
1200
1201static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001202static struct lock_class_key reserved_alloc_key;
1203static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001204
1205static void dmar_init_reserved_ranges(void)
1206{
1207 struct pci_dev *pdev = NULL;
1208 struct iova *iova;
1209 int i;
1210 u64 addr, size;
1211
David Millerf6611972008-02-06 01:36:23 -08001212 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001213
Mark Gross8a443df2008-03-04 14:59:31 -08001214 lockdep_set_class(&reserved_iova_list.iova_alloc_lock,
1215 &reserved_alloc_key);
1216 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1217 &reserved_rbtree_key);
1218
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001219 /* IOAPIC ranges shouldn't be accessed by DMA */
1220 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1221 IOVA_PFN(IOAPIC_RANGE_END));
1222 if (!iova)
1223 printk(KERN_ERR "Reserve IOAPIC range failed\n");
1224
1225 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1226 for_each_pci_dev(pdev) {
1227 struct resource *r;
1228
1229 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1230 r = &pdev->resource[i];
1231 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1232 continue;
1233 addr = r->start;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001234 addr &= PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001235 size = r->end - addr;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001236 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001237 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
1238 IOVA_PFN(size + addr) - 1);
1239 if (!iova)
1240 printk(KERN_ERR "Reserve iova failed\n");
1241 }
1242 }
1243
1244}
1245
1246static void domain_reserve_special_ranges(struct dmar_domain *domain)
1247{
1248 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1249}
1250
1251static inline int guestwidth_to_adjustwidth(int gaw)
1252{
1253 int agaw;
1254 int r = (gaw - 12) % 9;
1255
1256 if (r == 0)
1257 agaw = gaw;
1258 else
1259 agaw = gaw + 9 - r;
1260 if (agaw > 64)
1261 agaw = 64;
1262 return agaw;
1263}
1264
1265static int domain_init(struct dmar_domain *domain, int guest_width)
1266{
1267 struct intel_iommu *iommu;
1268 int adjust_width, agaw;
1269 unsigned long sagaw;
1270
David Millerf6611972008-02-06 01:36:23 -08001271 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001272 spin_lock_init(&domain->mapping_lock);
1273
1274 domain_reserve_special_ranges(domain);
1275
1276 /* calculate AGAW */
1277 iommu = domain->iommu;
1278 if (guest_width > cap_mgaw(iommu->cap))
1279 guest_width = cap_mgaw(iommu->cap);
1280 domain->gaw = guest_width;
1281 adjust_width = guestwidth_to_adjustwidth(guest_width);
1282 agaw = width_to_agaw(adjust_width);
1283 sagaw = cap_sagaw(iommu->cap);
1284 if (!test_bit(agaw, &sagaw)) {
1285 /* hardware doesn't support it, choose a bigger one */
1286 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1287 agaw = find_next_bit(&sagaw, 5, agaw);
1288 if (agaw >= 5)
1289 return -ENODEV;
1290 }
1291 domain->agaw = agaw;
1292 INIT_LIST_HEAD(&domain->devices);
1293
1294 /* always allocate the top pgd */
1295 domain->pgd = (struct dma_pte *)alloc_pgtable_page();
1296 if (!domain->pgd)
1297 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001298 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001299 return 0;
1300}
1301
1302static void domain_exit(struct dmar_domain *domain)
1303{
1304 u64 end;
1305
1306 /* Domain 0 is reserved, so dont process it */
1307 if (!domain)
1308 return;
1309
1310 domain_remove_dev_info(domain);
1311 /* destroy iovas */
1312 put_iova_domain(&domain->iovad);
1313 end = DOMAIN_MAX_ADDR(domain->gaw);
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001314 end = end & (~PAGE_MASK);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001315
1316 /* clear ptes */
1317 dma_pte_clear_range(domain, 0, end);
1318
1319 /* free page tables */
1320 dma_pte_free_pagetable(domain, 0, end);
1321
1322 iommu_free_domain(domain);
1323 free_domain_mem(domain);
1324}
1325
1326static int domain_context_mapping_one(struct dmar_domain *domain,
1327 u8 bus, u8 devfn)
1328{
1329 struct context_entry *context;
1330 struct intel_iommu *iommu = domain->iommu;
1331 unsigned long flags;
1332
1333 pr_debug("Set context mapping for %02x:%02x.%d\n",
1334 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
1335 BUG_ON(!domain->pgd);
1336 context = device_to_context_entry(iommu, bus, devfn);
1337 if (!context)
1338 return -ENOMEM;
1339 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001340 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001341 spin_unlock_irqrestore(&iommu->lock, flags);
1342 return 0;
1343 }
1344
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001345 context_set_domain_id(context, domain->id);
1346 context_set_address_width(context, domain->agaw);
1347 context_set_address_root(context, virt_to_phys(domain->pgd));
1348 context_set_translation_type(context, CONTEXT_TT_MULTI_LEVEL);
1349 context_set_fault_enable(context);
1350 context_set_present(context);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001351 __iommu_flush_cache(iommu, context, sizeof(*context));
1352
1353 /* it's a non-present to present mapping */
Youquan Songa77b67d2008-10-16 16:31:56 -07001354 if (iommu->flush.flush_context(iommu, domain->id,
1355 (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT,
1356 DMA_CCMD_DEVICE_INVL, 1))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001357 iommu_flush_write_buffer(iommu);
1358 else
Youquan Songa77b67d2008-10-16 16:31:56 -07001359 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH, 0);
1360
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001361 spin_unlock_irqrestore(&iommu->lock, flags);
1362 return 0;
1363}
1364
1365static int
1366domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev)
1367{
1368 int ret;
1369 struct pci_dev *tmp, *parent;
1370
1371 ret = domain_context_mapping_one(domain, pdev->bus->number,
1372 pdev->devfn);
1373 if (ret)
1374 return ret;
1375
1376 /* dependent device mapping */
1377 tmp = pci_find_upstream_pcie_bridge(pdev);
1378 if (!tmp)
1379 return 0;
1380 /* Secondary interface's bus number and devfn 0 */
1381 parent = pdev->bus->self;
1382 while (parent != tmp) {
1383 ret = domain_context_mapping_one(domain, parent->bus->number,
1384 parent->devfn);
1385 if (ret)
1386 return ret;
1387 parent = parent->bus->self;
1388 }
1389 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
1390 return domain_context_mapping_one(domain,
1391 tmp->subordinate->number, 0);
1392 else /* this is a legacy PCI bridge */
1393 return domain_context_mapping_one(domain,
1394 tmp->bus->number, tmp->devfn);
1395}
1396
1397static int domain_context_mapped(struct dmar_domain *domain,
1398 struct pci_dev *pdev)
1399{
1400 int ret;
1401 struct pci_dev *tmp, *parent;
1402
1403 ret = device_context_mapped(domain->iommu,
1404 pdev->bus->number, pdev->devfn);
1405 if (!ret)
1406 return ret;
1407 /* dependent device mapping */
1408 tmp = pci_find_upstream_pcie_bridge(pdev);
1409 if (!tmp)
1410 return ret;
1411 /* Secondary interface's bus number and devfn 0 */
1412 parent = pdev->bus->self;
1413 while (parent != tmp) {
1414 ret = device_context_mapped(domain->iommu, parent->bus->number,
1415 parent->devfn);
1416 if (!ret)
1417 return ret;
1418 parent = parent->bus->self;
1419 }
1420 if (tmp->is_pcie)
1421 return device_context_mapped(domain->iommu,
1422 tmp->subordinate->number, 0);
1423 else
1424 return device_context_mapped(domain->iommu,
1425 tmp->bus->number, tmp->devfn);
1426}
1427
1428static int
1429domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
1430 u64 hpa, size_t size, int prot)
1431{
1432 u64 start_pfn, end_pfn;
1433 struct dma_pte *pte;
1434 int index;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001435 int addr_width = agaw_to_width(domain->agaw);
1436
1437 hpa &= (((u64)1) << addr_width) - 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001438
1439 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1440 return -EINVAL;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001441 iova &= PAGE_MASK;
1442 start_pfn = ((u64)hpa) >> VTD_PAGE_SHIFT;
1443 end_pfn = (VTD_PAGE_ALIGN(((u64)hpa) + size)) >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001444 index = 0;
1445 while (start_pfn < end_pfn) {
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001446 pte = addr_to_dma_pte(domain, iova + VTD_PAGE_SIZE * index);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001447 if (!pte)
1448 return -ENOMEM;
1449 /* We don't need lock here, nobody else
1450 * touches the iova range
1451 */
Mark McLoughlin19c239c2008-11-21 16:56:53 +00001452 BUG_ON(dma_pte_addr(pte));
1453 dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT);
1454 dma_set_pte_prot(pte, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001455 __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
1456 start_pfn++;
1457 index++;
1458 }
1459 return 0;
1460}
1461
1462static void detach_domain_for_dev(struct dmar_domain *domain, u8 bus, u8 devfn)
1463{
1464 clear_context_table(domain->iommu, bus, devfn);
Youquan Songa77b67d2008-10-16 16:31:56 -07001465 domain->iommu->flush.flush_context(domain->iommu, 0, 0, 0,
1466 DMA_CCMD_GLOBAL_INVL, 0);
1467 domain->iommu->flush.flush_iotlb(domain->iommu, 0, 0, 0,
1468 DMA_TLB_GLOBAL_FLUSH, 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001469}
1470
1471static void domain_remove_dev_info(struct dmar_domain *domain)
1472{
1473 struct device_domain_info *info;
1474 unsigned long flags;
1475
1476 spin_lock_irqsave(&device_domain_lock, flags);
1477 while (!list_empty(&domain->devices)) {
1478 info = list_entry(domain->devices.next,
1479 struct device_domain_info, link);
1480 list_del(&info->link);
1481 list_del(&info->global);
1482 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001483 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001484 spin_unlock_irqrestore(&device_domain_lock, flags);
1485
1486 detach_domain_for_dev(info->domain, info->bus, info->devfn);
1487 free_devinfo_mem(info);
1488
1489 spin_lock_irqsave(&device_domain_lock, flags);
1490 }
1491 spin_unlock_irqrestore(&device_domain_lock, flags);
1492}
1493
1494/*
1495 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001496 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001497 */
Kay, Allen M38717942008-09-09 18:37:29 +03001498static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001499find_domain(struct pci_dev *pdev)
1500{
1501 struct device_domain_info *info;
1502
1503 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001504 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001505 if (info)
1506 return info->domain;
1507 return NULL;
1508}
1509
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001510/* domain is initialized */
1511static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1512{
1513 struct dmar_domain *domain, *found = NULL;
1514 struct intel_iommu *iommu;
1515 struct dmar_drhd_unit *drhd;
1516 struct device_domain_info *info, *tmp;
1517 struct pci_dev *dev_tmp;
1518 unsigned long flags;
1519 int bus = 0, devfn = 0;
1520
1521 domain = find_domain(pdev);
1522 if (domain)
1523 return domain;
1524
1525 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1526 if (dev_tmp) {
1527 if (dev_tmp->is_pcie) {
1528 bus = dev_tmp->subordinate->number;
1529 devfn = 0;
1530 } else {
1531 bus = dev_tmp->bus->number;
1532 devfn = dev_tmp->devfn;
1533 }
1534 spin_lock_irqsave(&device_domain_lock, flags);
1535 list_for_each_entry(info, &device_domain_list, global) {
1536 if (info->bus == bus && info->devfn == devfn) {
1537 found = info->domain;
1538 break;
1539 }
1540 }
1541 spin_unlock_irqrestore(&device_domain_lock, flags);
1542 /* pcie-pci bridge already has a domain, uses it */
1543 if (found) {
1544 domain = found;
1545 goto found_domain;
1546 }
1547 }
1548
1549 /* Allocate new domain for the device */
1550 drhd = dmar_find_matched_drhd_unit(pdev);
1551 if (!drhd) {
1552 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
1553 pci_name(pdev));
1554 return NULL;
1555 }
1556 iommu = drhd->iommu;
1557
1558 domain = iommu_alloc_domain(iommu);
1559 if (!domain)
1560 goto error;
1561
1562 if (domain_init(domain, gaw)) {
1563 domain_exit(domain);
1564 goto error;
1565 }
1566
1567 /* register pcie-to-pci device */
1568 if (dev_tmp) {
1569 info = alloc_devinfo_mem();
1570 if (!info) {
1571 domain_exit(domain);
1572 goto error;
1573 }
1574 info->bus = bus;
1575 info->devfn = devfn;
1576 info->dev = NULL;
1577 info->domain = domain;
1578 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08001579 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001580
1581 /* pcie-to-pci bridge already has a domain, uses it */
1582 found = NULL;
1583 spin_lock_irqsave(&device_domain_lock, flags);
1584 list_for_each_entry(tmp, &device_domain_list, global) {
1585 if (tmp->bus == bus && tmp->devfn == devfn) {
1586 found = tmp->domain;
1587 break;
1588 }
1589 }
1590 if (found) {
1591 free_devinfo_mem(info);
1592 domain_exit(domain);
1593 domain = found;
1594 } else {
1595 list_add(&info->link, &domain->devices);
1596 list_add(&info->global, &device_domain_list);
1597 }
1598 spin_unlock_irqrestore(&device_domain_lock, flags);
1599 }
1600
1601found_domain:
1602 info = alloc_devinfo_mem();
1603 if (!info)
1604 goto error;
1605 info->bus = pdev->bus->number;
1606 info->devfn = pdev->devfn;
1607 info->dev = pdev;
1608 info->domain = domain;
1609 spin_lock_irqsave(&device_domain_lock, flags);
1610 /* somebody is fast */
1611 found = find_domain(pdev);
1612 if (found != NULL) {
1613 spin_unlock_irqrestore(&device_domain_lock, flags);
1614 if (found != domain) {
1615 domain_exit(domain);
1616 domain = found;
1617 }
1618 free_devinfo_mem(info);
1619 return domain;
1620 }
1621 list_add(&info->link, &domain->devices);
1622 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001623 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001624 spin_unlock_irqrestore(&device_domain_lock, flags);
1625 return domain;
1626error:
1627 /* recheck it here, maybe others set it */
1628 return find_domain(pdev);
1629}
1630
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001631static int iommu_prepare_identity_map(struct pci_dev *pdev,
1632 unsigned long long start,
1633 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001634{
1635 struct dmar_domain *domain;
1636 unsigned long size;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001637 unsigned long long base;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001638 int ret;
1639
1640 printk(KERN_INFO
1641 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
1642 pci_name(pdev), start, end);
1643 /* page table init */
1644 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
1645 if (!domain)
1646 return -ENOMEM;
1647
1648 /* The address might not be aligned */
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001649 base = start & PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001650 size = end - base;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001651 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001652 if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
1653 IOVA_PFN(base + size) - 1)) {
1654 printk(KERN_ERR "IOMMU: reserve iova failed\n");
1655 ret = -ENOMEM;
1656 goto error;
1657 }
1658
1659 pr_debug("Mapping reserved region %lx@%llx for %s\n",
1660 size, base, pci_name(pdev));
1661 /*
1662 * RMRR range might have overlap with physical memory range,
1663 * clear it first
1664 */
1665 dma_pte_clear_range(domain, base, base + size);
1666
1667 ret = domain_page_mapping(domain, base, base, size,
1668 DMA_PTE_READ|DMA_PTE_WRITE);
1669 if (ret)
1670 goto error;
1671
1672 /* context entry init */
1673 ret = domain_context_mapping(domain, pdev);
1674 if (!ret)
1675 return 0;
1676error:
1677 domain_exit(domain);
1678 return ret;
1679
1680}
1681
1682static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
1683 struct pci_dev *pdev)
1684{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001685 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001686 return 0;
1687 return iommu_prepare_identity_map(pdev, rmrr->base_address,
1688 rmrr->end_address + 1);
1689}
1690
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001691#ifdef CONFIG_DMAR_GFX_WA
Yinghai Lud52d53b2008-06-16 20:10:55 -07001692struct iommu_prepare_data {
1693 struct pci_dev *pdev;
1694 int ret;
1695};
1696
1697static int __init iommu_prepare_work_fn(unsigned long start_pfn,
1698 unsigned long end_pfn, void *datax)
1699{
1700 struct iommu_prepare_data *data;
1701
1702 data = (struct iommu_prepare_data *)datax;
1703
1704 data->ret = iommu_prepare_identity_map(data->pdev,
1705 start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
1706 return data->ret;
1707
1708}
1709
1710static int __init iommu_prepare_with_active_regions(struct pci_dev *pdev)
1711{
1712 int nid;
1713 struct iommu_prepare_data data;
1714
1715 data.pdev = pdev;
1716 data.ret = 0;
1717
1718 for_each_online_node(nid) {
1719 work_with_active_regions(nid, iommu_prepare_work_fn, &data);
1720 if (data.ret)
1721 return data.ret;
1722 }
1723 return data.ret;
1724}
1725
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001726static void __init iommu_prepare_gfx_mapping(void)
1727{
1728 struct pci_dev *pdev = NULL;
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001729 int ret;
1730
1731 for_each_pci_dev(pdev) {
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001732 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001733 !IS_GFX_DEVICE(pdev))
1734 continue;
1735 printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
1736 pci_name(pdev));
Yinghai Lud52d53b2008-06-16 20:10:55 -07001737 ret = iommu_prepare_with_active_regions(pdev);
1738 if (ret)
1739 printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001740 }
1741}
Mark McLoughlin2abd7e12008-11-20 15:49:50 +00001742#else /* !CONFIG_DMAR_GFX_WA */
1743static inline void iommu_prepare_gfx_mapping(void)
1744{
1745 return;
1746}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001747#endif
1748
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07001749#ifdef CONFIG_DMAR_FLOPPY_WA
1750static inline void iommu_prepare_isa(void)
1751{
1752 struct pci_dev *pdev;
1753 int ret;
1754
1755 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
1756 if (!pdev)
1757 return;
1758
1759 printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n");
1760 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
1761
1762 if (ret)
1763 printk("IOMMU: Failed to create 0-64M identity map, "
1764 "floppy might not work\n");
1765
1766}
1767#else
1768static inline void iommu_prepare_isa(void)
1769{
1770 return;
1771}
1772#endif /* !CONFIG_DMAR_FLPY_WA */
1773
Mark McLoughlin519a0542008-11-20 14:21:13 +00001774static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001775{
1776 struct dmar_drhd_unit *drhd;
1777 struct dmar_rmrr_unit *rmrr;
1778 struct pci_dev *pdev;
1779 struct intel_iommu *iommu;
mark gross80b20dd2008-04-18 13:53:58 -07001780 int i, ret, unit = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001781
1782 /*
1783 * for each drhd
1784 * allocate root
1785 * initialize and program root entry to not present
1786 * endfor
1787 */
1788 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08001789 g_num_of_iommus++;
1790 /*
1791 * lock not needed as this is only incremented in the single
1792 * threaded kernel __init code path all other access are read
1793 * only
1794 */
1795 }
1796
mark gross80b20dd2008-04-18 13:53:58 -07001797 deferred_flush = kzalloc(g_num_of_iommus *
1798 sizeof(struct deferred_flush_tables), GFP_KERNEL);
1799 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08001800 ret = -ENOMEM;
1801 goto error;
1802 }
1803
mark gross5e0d2a62008-03-04 15:22:08 -08001804 for_each_drhd_unit(drhd) {
1805 if (drhd->ignored)
1806 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07001807
1808 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001809
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001810 ret = iommu_init_domains(iommu);
1811 if (ret)
1812 goto error;
1813
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001814 /*
1815 * TBD:
1816 * we could share the same root & context tables
1817 * amoung all IOMMU's. Need to Split it later.
1818 */
1819 ret = iommu_alloc_root_entry(iommu);
1820 if (ret) {
1821 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
1822 goto error;
1823 }
1824 }
1825
Youquan Songa77b67d2008-10-16 16:31:56 -07001826 for_each_drhd_unit(drhd) {
1827 if (drhd->ignored)
1828 continue;
1829
1830 iommu = drhd->iommu;
1831 if (dmar_enable_qi(iommu)) {
1832 /*
1833 * Queued Invalidate not enabled, use Register Based
1834 * Invalidate
1835 */
1836 iommu->flush.flush_context = __iommu_flush_context;
1837 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
1838 printk(KERN_INFO "IOMMU 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09001839 "invalidation\n",
1840 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07001841 } else {
1842 iommu->flush.flush_context = qi_flush_context;
1843 iommu->flush.flush_iotlb = qi_flush_iotlb;
1844 printk(KERN_INFO "IOMMU 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09001845 "invalidation\n",
1846 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07001847 }
1848 }
1849
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001850 /*
1851 * For each rmrr
1852 * for each dev attached to rmrr
1853 * do
1854 * locate drhd for dev, alloc domain for dev
1855 * allocate free domain
1856 * allocate page table entries for rmrr
1857 * if context not allocated for bus
1858 * allocate and init context
1859 * set present in root table for this bus
1860 * init context with domain, translation etc
1861 * endfor
1862 * endfor
1863 */
1864 for_each_rmrr_units(rmrr) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001865 for (i = 0; i < rmrr->devices_cnt; i++) {
1866 pdev = rmrr->devices[i];
1867 /* some BIOS lists non-exist devices in DMAR table */
1868 if (!pdev)
1869 continue;
1870 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
1871 if (ret)
1872 printk(KERN_ERR
1873 "IOMMU: mapping reserved region failed\n");
1874 }
1875 }
1876
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001877 iommu_prepare_gfx_mapping();
1878
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07001879 iommu_prepare_isa();
1880
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001881 /*
1882 * for each drhd
1883 * enable fault log
1884 * global invalidate context cache
1885 * global invalidate iotlb
1886 * enable translation
1887 */
1888 for_each_drhd_unit(drhd) {
1889 if (drhd->ignored)
1890 continue;
1891 iommu = drhd->iommu;
1892 sprintf (iommu->name, "dmar%d", unit++);
1893
1894 iommu_flush_write_buffer(iommu);
1895
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001896 ret = dmar_set_interrupt(iommu);
1897 if (ret)
1898 goto error;
1899
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001900 iommu_set_root_entry(iommu);
1901
Youquan Songa77b67d2008-10-16 16:31:56 -07001902 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
1903 0);
1904 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
1905 0);
mark grossf8bab732008-02-08 04:18:38 -08001906 iommu_disable_protect_mem_regions(iommu);
1907
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001908 ret = iommu_enable_translation(iommu);
1909 if (ret)
1910 goto error;
1911 }
1912
1913 return 0;
1914error:
1915 for_each_drhd_unit(drhd) {
1916 if (drhd->ignored)
1917 continue;
1918 iommu = drhd->iommu;
1919 free_iommu(iommu);
1920 }
1921 return ret;
1922}
1923
1924static inline u64 aligned_size(u64 host_addr, size_t size)
1925{
1926 u64 addr;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001927 addr = (host_addr & (~PAGE_MASK)) + size;
1928 return PAGE_ALIGN(addr);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001929}
1930
1931struct iova *
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001932iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001933{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001934 struct iova *piova;
1935
1936 /* Make sure it's in range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001937 end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001938 if (!size || (IOVA_START_ADDR + size > end))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001939 return NULL;
1940
1941 piova = alloc_iova(&domain->iovad,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001942 size >> PAGE_SHIFT, IOVA_PFN(end), 1);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001943 return piova;
1944}
1945
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001946static struct iova *
1947__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09001948 size_t size, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001949{
1950 struct pci_dev *pdev = to_pci_dev(dev);
1951 struct iova *iova = NULL;
1952
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09001953 if (dma_mask <= DMA_32BIT_MASK || dmar_forcedac)
1954 iova = iommu_alloc_iova(domain, size, dma_mask);
1955 else {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001956 /*
1957 * First try to allocate an io virtual address in
1958 * DMA_32BIT_MASK and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08001959 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001960 */
1961 iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
1962 if (!iova)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09001963 iova = iommu_alloc_iova(domain, size, dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001964 }
1965
1966 if (!iova) {
1967 printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev));
1968 return NULL;
1969 }
1970
1971 return iova;
1972}
1973
1974static struct dmar_domain *
1975get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001976{
1977 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001978 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001979
1980 domain = get_domain_for_dev(pdev,
1981 DEFAULT_DOMAIN_ADDRESS_WIDTH);
1982 if (!domain) {
1983 printk(KERN_ERR
1984 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00001985 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001986 }
1987
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001988 /* make sure context mapping is ok */
1989 if (unlikely(!domain_context_mapped(domain, pdev))) {
1990 ret = domain_context_mapping(domain, pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001991 if (ret) {
1992 printk(KERN_ERR
1993 "Domain context map for %s failed",
1994 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00001995 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001996 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001997 }
1998
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07001999 return domain;
2000}
2001
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002002static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2003 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002004{
2005 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002006 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002007 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002008 struct iova *iova;
2009 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002010 int ret;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002011
2012 BUG_ON(dir == DMA_NONE);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002013 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002014 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002015
2016 domain = get_valid_domain_for_dev(pdev);
2017 if (!domain)
2018 return 0;
2019
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002020 size = aligned_size((u64)paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002021
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002022 iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002023 if (!iova)
2024 goto error;
2025
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002026 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002027
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002028 /*
2029 * Check if DMAR supports zero-length reads on write only
2030 * mappings..
2031 */
2032 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
2033 !cap_zlr(domain->iommu->cap))
2034 prot |= DMA_PTE_READ;
2035 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2036 prot |= DMA_PTE_WRITE;
2037 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002038 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002039 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002040 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002041 * is not a big problem
2042 */
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002043 ret = domain_page_mapping(domain, start_paddr,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002044 ((u64)paddr) & PAGE_MASK, size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002045 if (ret)
2046 goto error;
2047
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002048 /* it's a non-present to present mapping */
2049 ret = iommu_flush_iotlb_psi(domain->iommu, domain->id,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002050 start_paddr, size >> VTD_PAGE_SHIFT, 1);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002051 if (ret)
2052 iommu_flush_write_buffer(domain->iommu);
2053
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002054 return start_paddr + ((u64)paddr & (~PAGE_MASK));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002055
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002056error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002057 if (iova)
2058 __free_iova(&domain->iovad, iova);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002059 printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002060 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002061 return 0;
2062}
2063
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002064dma_addr_t intel_map_single(struct device *hwdev, phys_addr_t paddr,
2065 size_t size, int dir)
2066{
2067 return __intel_map_single(hwdev, paddr, size, dir,
2068 to_pci_dev(hwdev)->dma_mask);
2069}
2070
mark gross5e0d2a62008-03-04 15:22:08 -08002071static void flush_unmaps(void)
2072{
mark gross80b20dd2008-04-18 13:53:58 -07002073 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002074
mark gross5e0d2a62008-03-04 15:22:08 -08002075 timer_on = 0;
2076
2077 /* just flush them all */
2078 for (i = 0; i < g_num_of_iommus; i++) {
mark gross80b20dd2008-04-18 13:53:58 -07002079 if (deferred_flush[i].next) {
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002080 struct intel_iommu *iommu =
2081 deferred_flush[i].domain[0]->iommu;
2082
Youquan Songa77b67d2008-10-16 16:31:56 -07002083 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
2084 DMA_TLB_GLOBAL_FLUSH, 0);
mark gross80b20dd2008-04-18 13:53:58 -07002085 for (j = 0; j < deferred_flush[i].next; j++) {
2086 __free_iova(&deferred_flush[i].domain[j]->iovad,
2087 deferred_flush[i].iova[j]);
2088 }
2089 deferred_flush[i].next = 0;
2090 }
mark gross5e0d2a62008-03-04 15:22:08 -08002091 }
2092
mark gross5e0d2a62008-03-04 15:22:08 -08002093 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002094}
2095
2096static void flush_unmaps_timeout(unsigned long data)
2097{
mark gross80b20dd2008-04-18 13:53:58 -07002098 unsigned long flags;
2099
2100 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002101 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002102 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002103}
2104
2105static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2106{
2107 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002108 int next, iommu_id;
mark gross5e0d2a62008-03-04 15:22:08 -08002109
2110 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002111 if (list_size == HIGH_WATER_MARK)
2112 flush_unmaps();
2113
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002114 iommu_id = dom->iommu->seq_id;
2115
mark gross80b20dd2008-04-18 13:53:58 -07002116 next = deferred_flush[iommu_id].next;
2117 deferred_flush[iommu_id].domain[next] = dom;
2118 deferred_flush[iommu_id].iova[next] = iova;
2119 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002120
2121 if (!timer_on) {
2122 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2123 timer_on = 1;
2124 }
2125 list_size++;
2126 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2127}
2128
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002129void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
2130 int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002131{
2132 struct pci_dev *pdev = to_pci_dev(dev);
2133 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002134 unsigned long start_addr;
2135 struct iova *iova;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002136
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002137 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002138 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002139 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002140 BUG_ON(!domain);
2141
2142 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
2143 if (!iova)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002144 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002145
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002146 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002147 size = aligned_size((u64)dev_addr, size);
2148
2149 pr_debug("Device %s unmapping: %lx@%llx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002150 pci_name(pdev), size, (unsigned long long)start_addr);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002151
2152 /* clear the whole page */
2153 dma_pte_clear_range(domain, start_addr, start_addr + size);
2154 /* free page tables */
2155 dma_pte_free_pagetable(domain, start_addr, start_addr + size);
mark gross5e0d2a62008-03-04 15:22:08 -08002156 if (intel_iommu_strict) {
2157 if (iommu_flush_iotlb_psi(domain->iommu,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002158 domain->id, start_addr, size >> VTD_PAGE_SHIFT, 0))
mark gross5e0d2a62008-03-04 15:22:08 -08002159 iommu_flush_write_buffer(domain->iommu);
2160 /* free iova */
2161 __free_iova(&domain->iovad, iova);
2162 } else {
2163 add_unmap(domain, iova);
2164 /*
2165 * queue up the release of the unmap to save the 1/6th of the
2166 * cpu used up by the iotlb flush operation...
2167 */
mark gross5e0d2a62008-03-04 15:22:08 -08002168 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002169}
2170
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002171void *intel_alloc_coherent(struct device *hwdev, size_t size,
2172 dma_addr_t *dma_handle, gfp_t flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002173{
2174 void *vaddr;
2175 int order;
2176
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002177 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002178 order = get_order(size);
2179 flags &= ~(GFP_DMA | GFP_DMA32);
2180
2181 vaddr = (void *)__get_free_pages(flags, order);
2182 if (!vaddr)
2183 return NULL;
2184 memset(vaddr, 0, size);
2185
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002186 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2187 DMA_BIDIRECTIONAL,
2188 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002189 if (*dma_handle)
2190 return vaddr;
2191 free_pages((unsigned long)vaddr, order);
2192 return NULL;
2193}
2194
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002195void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
2196 dma_addr_t dma_handle)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002197{
2198 int order;
2199
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002200 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002201 order = get_order(size);
2202
2203 intel_unmap_single(hwdev, dma_handle, size, DMA_BIDIRECTIONAL);
2204 free_pages((unsigned long)vaddr, order);
2205}
2206
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002207#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg)))
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002208
2209void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
2210 int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002211{
2212 int i;
2213 struct pci_dev *pdev = to_pci_dev(hwdev);
2214 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002215 unsigned long start_addr;
2216 struct iova *iova;
2217 size_t size = 0;
2218 void *addr;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002219 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002220
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002221 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002222 return;
2223
2224 domain = find_domain(pdev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002225
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002226 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002227 if (!iova)
2228 return;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002229 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002230 addr = SG_ENT_VIRT_ADDRESS(sg);
2231 size += aligned_size((u64)addr, sg->length);
2232 }
2233
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002234 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002235
2236 /* clear the whole page */
2237 dma_pte_clear_range(domain, start_addr, start_addr + size);
2238 /* free page tables */
2239 dma_pte_free_pagetable(domain, start_addr, start_addr + size);
2240
2241 if (iommu_flush_iotlb_psi(domain->iommu, domain->id, start_addr,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002242 size >> VTD_PAGE_SHIFT, 0))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002243 iommu_flush_write_buffer(domain->iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002244
2245 /* free iova */
2246 __free_iova(&domain->iovad, iova);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002247}
2248
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002249static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002250 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002251{
2252 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002253 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002254
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002255 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002256 BUG_ON(!sg_page(sg));
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002257 sg->dma_address = virt_to_bus(SG_ENT_VIRT_ADDRESS(sg));
2258 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002259 }
2260 return nelems;
2261}
2262
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002263int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
2264 int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002265{
2266 void *addr;
2267 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002268 struct pci_dev *pdev = to_pci_dev(hwdev);
2269 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002270 size_t size = 0;
2271 int prot = 0;
2272 size_t offset = 0;
2273 struct iova *iova = NULL;
2274 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002275 struct scatterlist *sg;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002276 unsigned long start_addr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002277
2278 BUG_ON(dir == DMA_NONE);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002279 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002280 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002281
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002282 domain = get_valid_domain_for_dev(pdev);
2283 if (!domain)
2284 return 0;
2285
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002286 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002287 addr = SG_ENT_VIRT_ADDRESS(sg);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002288 addr = (void *)virt_to_phys(addr);
2289 size += aligned_size((u64)addr, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002290 }
2291
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002292 iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002293 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002294 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002295 return 0;
2296 }
2297
2298 /*
2299 * Check if DMAR supports zero-length reads on write only
2300 * mappings..
2301 */
2302 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
2303 !cap_zlr(domain->iommu->cap))
2304 prot |= DMA_PTE_READ;
2305 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2306 prot |= DMA_PTE_WRITE;
2307
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002308 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002309 offset = 0;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002310 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002311 addr = SG_ENT_VIRT_ADDRESS(sg);
2312 addr = (void *)virt_to_phys(addr);
2313 size = aligned_size((u64)addr, sg->length);
2314 ret = domain_page_mapping(domain, start_addr + offset,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002315 ((u64)addr) & PAGE_MASK,
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002316 size, prot);
2317 if (ret) {
2318 /* clear the page */
2319 dma_pte_clear_range(domain, start_addr,
2320 start_addr + offset);
2321 /* free page tables */
2322 dma_pte_free_pagetable(domain, start_addr,
2323 start_addr + offset);
2324 /* free iova */
2325 __free_iova(&domain->iovad, iova);
2326 return 0;
2327 }
2328 sg->dma_address = start_addr + offset +
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002329 ((u64)addr & (~PAGE_MASK));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002330 sg->dma_length = sg->length;
2331 offset += size;
2332 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002333
2334 /* it's a non-present to present mapping */
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002335 if (iommu_flush_iotlb_psi(domain->iommu, domain->id,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002336 start_addr, offset >> VTD_PAGE_SHIFT, 1))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002337 iommu_flush_write_buffer(domain->iommu);
2338 return nelems;
2339}
2340
2341static struct dma_mapping_ops intel_dma_ops = {
2342 .alloc_coherent = intel_alloc_coherent,
2343 .free_coherent = intel_free_coherent,
2344 .map_single = intel_map_single,
2345 .unmap_single = intel_unmap_single,
2346 .map_sg = intel_map_sg,
2347 .unmap_sg = intel_unmap_sg,
2348};
2349
2350static inline int iommu_domain_cache_init(void)
2351{
2352 int ret = 0;
2353
2354 iommu_domain_cache = kmem_cache_create("iommu_domain",
2355 sizeof(struct dmar_domain),
2356 0,
2357 SLAB_HWCACHE_ALIGN,
2358
2359 NULL);
2360 if (!iommu_domain_cache) {
2361 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
2362 ret = -ENOMEM;
2363 }
2364
2365 return ret;
2366}
2367
2368static inline int iommu_devinfo_cache_init(void)
2369{
2370 int ret = 0;
2371
2372 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
2373 sizeof(struct device_domain_info),
2374 0,
2375 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002376 NULL);
2377 if (!iommu_devinfo_cache) {
2378 printk(KERN_ERR "Couldn't create devinfo cache\n");
2379 ret = -ENOMEM;
2380 }
2381
2382 return ret;
2383}
2384
2385static inline int iommu_iova_cache_init(void)
2386{
2387 int ret = 0;
2388
2389 iommu_iova_cache = kmem_cache_create("iommu_iova",
2390 sizeof(struct iova),
2391 0,
2392 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002393 NULL);
2394 if (!iommu_iova_cache) {
2395 printk(KERN_ERR "Couldn't create iova cache\n");
2396 ret = -ENOMEM;
2397 }
2398
2399 return ret;
2400}
2401
2402static int __init iommu_init_mempool(void)
2403{
2404 int ret;
2405 ret = iommu_iova_cache_init();
2406 if (ret)
2407 return ret;
2408
2409 ret = iommu_domain_cache_init();
2410 if (ret)
2411 goto domain_error;
2412
2413 ret = iommu_devinfo_cache_init();
2414 if (!ret)
2415 return ret;
2416
2417 kmem_cache_destroy(iommu_domain_cache);
2418domain_error:
2419 kmem_cache_destroy(iommu_iova_cache);
2420
2421 return -ENOMEM;
2422}
2423
2424static void __init iommu_exit_mempool(void)
2425{
2426 kmem_cache_destroy(iommu_devinfo_cache);
2427 kmem_cache_destroy(iommu_domain_cache);
2428 kmem_cache_destroy(iommu_iova_cache);
2429
2430}
2431
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002432static void __init init_no_remapping_devices(void)
2433{
2434 struct dmar_drhd_unit *drhd;
2435
2436 for_each_drhd_unit(drhd) {
2437 if (!drhd->include_all) {
2438 int i;
2439 for (i = 0; i < drhd->devices_cnt; i++)
2440 if (drhd->devices[i] != NULL)
2441 break;
2442 /* ignore DMAR unit if no pci devices exist */
2443 if (i == drhd->devices_cnt)
2444 drhd->ignored = 1;
2445 }
2446 }
2447
2448 if (dmar_map_gfx)
2449 return;
2450
2451 for_each_drhd_unit(drhd) {
2452 int i;
2453 if (drhd->ignored || drhd->include_all)
2454 continue;
2455
2456 for (i = 0; i < drhd->devices_cnt; i++)
2457 if (drhd->devices[i] &&
2458 !IS_GFX_DEVICE(drhd->devices[i]))
2459 break;
2460
2461 if (i < drhd->devices_cnt)
2462 continue;
2463
2464 /* bypass IOMMU if it is just for gfx devices */
2465 drhd->ignored = 1;
2466 for (i = 0; i < drhd->devices_cnt; i++) {
2467 if (!drhd->devices[i])
2468 continue;
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002469 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002470 }
2471 }
2472}
2473
2474int __init intel_iommu_init(void)
2475{
2476 int ret = 0;
2477
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002478 if (dmar_table_init())
2479 return -ENODEV;
2480
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002481 if (dmar_dev_scope_init())
2482 return -ENODEV;
2483
Suresh Siddha2ae21012008-07-10 11:16:43 -07002484 /*
2485 * Check the need for DMA-remapping initialization now.
2486 * Above initialization will also be used by Interrupt-remapping.
2487 */
2488 if (no_iommu || swiotlb || dmar_disabled)
2489 return -ENODEV;
2490
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002491 iommu_init_mempool();
2492 dmar_init_reserved_ranges();
2493
2494 init_no_remapping_devices();
2495
2496 ret = init_dmars();
2497 if (ret) {
2498 printk(KERN_ERR "IOMMU: dmar init failed\n");
2499 put_iova_domain(&reserved_iova_list);
2500 iommu_exit_mempool();
2501 return ret;
2502 }
2503 printk(KERN_INFO
2504 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
2505
mark gross5e0d2a62008-03-04 15:22:08 -08002506 init_timer(&unmap_timer);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002507 force_iommu = 1;
2508 dma_ops = &intel_dma_ops;
2509 return 0;
2510}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07002511
Kay, Allen M38717942008-09-09 18:37:29 +03002512void intel_iommu_domain_exit(struct dmar_domain *domain)
2513{
2514 u64 end;
2515
2516 /* Domain 0 is reserved, so dont process it */
2517 if (!domain)
2518 return;
2519
2520 end = DOMAIN_MAX_ADDR(domain->gaw);
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002521 end = end & (~VTD_PAGE_MASK);
Kay, Allen M38717942008-09-09 18:37:29 +03002522
2523 /* clear ptes */
2524 dma_pte_clear_range(domain, 0, end);
2525
2526 /* free page tables */
2527 dma_pte_free_pagetable(domain, 0, end);
2528
2529 iommu_free_domain(domain);
2530 free_domain_mem(domain);
2531}
2532EXPORT_SYMBOL_GPL(intel_iommu_domain_exit);
2533
2534struct dmar_domain *intel_iommu_domain_alloc(struct pci_dev *pdev)
2535{
2536 struct dmar_drhd_unit *drhd;
2537 struct dmar_domain *domain;
2538 struct intel_iommu *iommu;
2539
2540 drhd = dmar_find_matched_drhd_unit(pdev);
2541 if (!drhd) {
2542 printk(KERN_ERR "intel_iommu_domain_alloc: drhd == NULL\n");
2543 return NULL;
2544 }
2545
2546 iommu = drhd->iommu;
2547 if (!iommu) {
2548 printk(KERN_ERR
2549 "intel_iommu_domain_alloc: iommu == NULL\n");
2550 return NULL;
2551 }
2552 domain = iommu_alloc_domain(iommu);
2553 if (!domain) {
2554 printk(KERN_ERR
2555 "intel_iommu_domain_alloc: domain == NULL\n");
2556 return NULL;
2557 }
2558 if (domain_init(domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2559 printk(KERN_ERR
2560 "intel_iommu_domain_alloc: domain_init() failed\n");
2561 intel_iommu_domain_exit(domain);
2562 return NULL;
2563 }
2564 return domain;
2565}
2566EXPORT_SYMBOL_GPL(intel_iommu_domain_alloc);
2567
2568int intel_iommu_context_mapping(
2569 struct dmar_domain *domain, struct pci_dev *pdev)
2570{
2571 int rc;
2572 rc = domain_context_mapping(domain, pdev);
2573 return rc;
2574}
2575EXPORT_SYMBOL_GPL(intel_iommu_context_mapping);
2576
2577int intel_iommu_page_mapping(
2578 struct dmar_domain *domain, dma_addr_t iova,
2579 u64 hpa, size_t size, int prot)
2580{
2581 int rc;
2582 rc = domain_page_mapping(domain, iova, hpa, size, prot);
2583 return rc;
2584}
2585EXPORT_SYMBOL_GPL(intel_iommu_page_mapping);
2586
2587void intel_iommu_detach_dev(struct dmar_domain *domain, u8 bus, u8 devfn)
2588{
2589 detach_domain_for_dev(domain, bus, devfn);
2590}
2591EXPORT_SYMBOL_GPL(intel_iommu_detach_dev);
2592
2593struct dmar_domain *
2594intel_iommu_find_domain(struct pci_dev *pdev)
2595{
2596 return find_domain(pdev);
2597}
2598EXPORT_SYMBOL_GPL(intel_iommu_find_domain);
2599
2600int intel_iommu_found(void)
2601{
2602 return g_num_of_iommus;
2603}
2604EXPORT_SYMBOL_GPL(intel_iommu_found);
2605
2606u64 intel_iommu_iova_to_pfn(struct dmar_domain *domain, u64 iova)
2607{
2608 struct dma_pte *pte;
2609 u64 pfn;
2610
2611 pfn = 0;
2612 pte = addr_to_dma_pte(domain, iova);
2613
2614 if (pte)
Mark McLoughlin19c239c2008-11-21 16:56:53 +00002615 pfn = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03002616
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002617 return pfn >> VTD_PAGE_SHIFT;
Kay, Allen M38717942008-09-09 18:37:29 +03002618}
2619EXPORT_SYMBOL_GPL(intel_iommu_iova_to_pfn);