blob: f3f686581a9026685dc3e6c994b00e88ed88486c [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>
Joerg Roedel5d450802008-12-03 14:52:32 +010037#include <linux/iommu.h>
Kay, Allen M38717942008-09-09 18:37:29 +030038#include <linux/intel-iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070039#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090040#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070041#include "pci.h"
42
Fenghua Yu5b6985c2008-10-16 18:02:32 -070043#define ROOT_SIZE VTD_PAGE_SIZE
44#define CONTEXT_SIZE VTD_PAGE_SIZE
45
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070046#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
47#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
48
49#define IOAPIC_RANGE_START (0xfee00000)
50#define IOAPIC_RANGE_END (0xfeefffff)
51#define IOVA_START_ADDR (0x1000)
52
53#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
54
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070055#define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
56
Mark McLoughlinf27be032008-11-20 15:49:43 +000057#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
58#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
59#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
mark gross5e0d2a62008-03-04 15:22:08 -080060
Weidong Hand9630fe2008-12-08 11:06:32 +080061/* global iommu list, set NULL for ignored DMAR units */
62static struct intel_iommu **g_iommus;
63
David Woodhouse9af88142009-02-13 23:18:03 +000064static int rwbf_quirk;
65
Mark McLoughlin46b08e12008-11-20 15:49:44 +000066/*
67 * 0: Present
68 * 1-11: Reserved
69 * 12-63: Context Ptr (12 - (haw-1))
70 * 64-127: Reserved
71 */
72struct root_entry {
73 u64 val;
74 u64 rsvd1;
75};
76#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
77static inline bool root_present(struct root_entry *root)
78{
79 return (root->val & 1);
80}
81static inline void set_root_present(struct root_entry *root)
82{
83 root->val |= 1;
84}
85static inline void set_root_value(struct root_entry *root, unsigned long value)
86{
87 root->val |= value & VTD_PAGE_MASK;
88}
89
90static inline struct context_entry *
91get_context_addr_from_root(struct root_entry *root)
92{
93 return (struct context_entry *)
94 (root_present(root)?phys_to_virt(
95 root->val & VTD_PAGE_MASK) :
96 NULL);
97}
98
Mark McLoughlin7a8fc252008-11-20 15:49:45 +000099/*
100 * low 64 bits:
101 * 0: present
102 * 1: fault processing disable
103 * 2-3: translation type
104 * 12-63: address space root
105 * high 64 bits:
106 * 0-2: address width
107 * 3-6: aval
108 * 8-23: domain id
109 */
110struct context_entry {
111 u64 lo;
112 u64 hi;
113};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000114
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000115static inline bool context_present(struct context_entry *context)
116{
117 return (context->lo & 1);
118}
119static inline void context_set_present(struct context_entry *context)
120{
121 context->lo |= 1;
122}
123
124static inline void context_set_fault_enable(struct context_entry *context)
125{
126 context->lo &= (((u64)-1) << 2) | 1;
127}
128
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000129#define CONTEXT_TT_MULTI_LEVEL 0
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000130
131static inline void context_set_translation_type(struct context_entry *context,
132 unsigned long value)
133{
134 context->lo &= (((u64)-1) << 4) | 3;
135 context->lo |= (value & 3) << 2;
136}
137
138static inline void context_set_address_root(struct context_entry *context,
139 unsigned long value)
140{
141 context->lo |= value & VTD_PAGE_MASK;
142}
143
144static inline void context_set_address_width(struct context_entry *context,
145 unsigned long value)
146{
147 context->hi |= value & 7;
148}
149
150static inline void context_set_domain_id(struct context_entry *context,
151 unsigned long value)
152{
153 context->hi |= (value & ((1 << 16) - 1)) << 8;
154}
155
156static inline void context_clear_entry(struct context_entry *context)
157{
158 context->lo = 0;
159 context->hi = 0;
160}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000161
Mark McLoughlin622ba122008-11-20 15:49:46 +0000162/*
163 * 0: readable
164 * 1: writable
165 * 2-6: reserved
166 * 7: super page
167 * 8-11: available
168 * 12-63: Host physcial address
169 */
170struct dma_pte {
171 u64 val;
172};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000173
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000174static inline void dma_clear_pte(struct dma_pte *pte)
175{
176 pte->val = 0;
177}
178
179static inline void dma_set_pte_readable(struct dma_pte *pte)
180{
181 pte->val |= DMA_PTE_READ;
182}
183
184static inline void dma_set_pte_writable(struct dma_pte *pte)
185{
186 pte->val |= DMA_PTE_WRITE;
187}
188
189static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
190{
191 pte->val = (pte->val & ~3) | (prot & 3);
192}
193
194static inline u64 dma_pte_addr(struct dma_pte *pte)
195{
196 return (pte->val & VTD_PAGE_MASK);
197}
198
199static inline void dma_set_pte_addr(struct dma_pte *pte, u64 addr)
200{
201 pte->val |= (addr & VTD_PAGE_MASK);
202}
203
204static inline bool dma_pte_present(struct dma_pte *pte)
205{
206 return (pte->val & 3) != 0;
207}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000208
Weidong Han3b5410e2008-12-08 09:17:15 +0800209/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100210#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800211
Weidong Han1ce28fe2008-12-08 16:35:39 +0800212/* domain represents a virtual machine, more than one devices
213 * across iommus may be owned in one domain, e.g. kvm guest.
214 */
215#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
216
Mark McLoughlin99126f72008-11-20 15:49:47 +0000217struct dmar_domain {
218 int id; /* domain id */
Weidong Han8c11e792008-12-08 15:29:22 +0800219 unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000220
221 struct list_head devices; /* all devices' list */
222 struct iova_domain iovad; /* iova's that belong to this domain */
223
224 struct dma_pte *pgd; /* virtual address */
225 spinlock_t mapping_lock; /* page table lock */
226 int gaw; /* max guest address width */
227
228 /* adjusted guest address width, 0 is level 2 30-bit */
229 int agaw;
230
Weidong Han3b5410e2008-12-08 09:17:15 +0800231 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800232
233 int iommu_coherency;/* indicate coherency of iommu access */
Weidong Hanc7151a82008-12-08 22:51:37 +0800234 int iommu_count; /* reference count of iommu */
235 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800236 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000237};
238
Mark McLoughlina647dac2008-11-20 15:49:48 +0000239/* PCI domain-device relationship */
240struct device_domain_info {
241 struct list_head link; /* link to domain siblings */
242 struct list_head global; /* link to global list */
243 u8 bus; /* PCI bus numer */
244 u8 devfn; /* PCI devfn number */
245 struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
246 struct dmar_domain *domain; /* pointer to domain */
247};
248
mark gross5e0d2a62008-03-04 15:22:08 -0800249static void flush_unmaps_timeout(unsigned long data);
250
251DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
252
mark gross80b20dd2008-04-18 13:53:58 -0700253#define HIGH_WATER_MARK 250
254struct deferred_flush_tables {
255 int next;
256 struct iova *iova[HIGH_WATER_MARK];
257 struct dmar_domain *domain[HIGH_WATER_MARK];
258};
259
260static struct deferred_flush_tables *deferred_flush;
261
mark gross5e0d2a62008-03-04 15:22:08 -0800262/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800263static int g_num_of_iommus;
264
265static DEFINE_SPINLOCK(async_umap_flush_lock);
266static LIST_HEAD(unmaps_to_do);
267
268static int timer_on;
269static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800270
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700271static void domain_remove_dev_info(struct dmar_domain *domain);
272
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800273#ifdef CONFIG_DMAR_DEFAULT_ON
274int dmar_disabled = 0;
275#else
276int dmar_disabled = 1;
277#endif /*CONFIG_DMAR_DEFAULT_ON*/
278
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700279static int __initdata dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700280static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800281static int intel_iommu_strict;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700282
283#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
284static DEFINE_SPINLOCK(device_domain_lock);
285static LIST_HEAD(device_domain_list);
286
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100287static struct iommu_ops intel_iommu_ops;
288
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700289static int __init intel_iommu_setup(char *str)
290{
291 if (!str)
292 return -EINVAL;
293 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800294 if (!strncmp(str, "on", 2)) {
295 dmar_disabled = 0;
296 printk(KERN_INFO "Intel-IOMMU: enabled\n");
297 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700298 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800299 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700300 } else if (!strncmp(str, "igfx_off", 8)) {
301 dmar_map_gfx = 0;
302 printk(KERN_INFO
303 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700304 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800305 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700306 "Intel-IOMMU: Forcing DAC for PCI devices\n");
307 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800308 } else if (!strncmp(str, "strict", 6)) {
309 printk(KERN_INFO
310 "Intel-IOMMU: disable batched IOTLB flush\n");
311 intel_iommu_strict = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700312 }
313
314 str += strcspn(str, ",");
315 while (*str == ',')
316 str++;
317 }
318 return 0;
319}
320__setup("intel_iommu=", intel_iommu_setup);
321
322static struct kmem_cache *iommu_domain_cache;
323static struct kmem_cache *iommu_devinfo_cache;
324static struct kmem_cache *iommu_iova_cache;
325
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700326static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep)
327{
328 unsigned int flags;
329 void *vaddr;
330
331 /* trying to avoid low memory issues */
332 flags = current->flags & PF_MEMALLOC;
333 current->flags |= PF_MEMALLOC;
334 vaddr = kmem_cache_alloc(cachep, GFP_ATOMIC);
335 current->flags &= (~PF_MEMALLOC | flags);
336 return vaddr;
337}
338
339
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700340static inline void *alloc_pgtable_page(void)
341{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700342 unsigned int flags;
343 void *vaddr;
344
345 /* trying to avoid low memory issues */
346 flags = current->flags & PF_MEMALLOC;
347 current->flags |= PF_MEMALLOC;
348 vaddr = (void *)get_zeroed_page(GFP_ATOMIC);
349 current->flags &= (~PF_MEMALLOC | flags);
350 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700351}
352
353static inline void free_pgtable_page(void *vaddr)
354{
355 free_page((unsigned long)vaddr);
356}
357
358static inline void *alloc_domain_mem(void)
359{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700360 return iommu_kmem_cache_alloc(iommu_domain_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700361}
362
Kay, Allen M38717942008-09-09 18:37:29 +0300363static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700364{
365 kmem_cache_free(iommu_domain_cache, vaddr);
366}
367
368static inline void * alloc_devinfo_mem(void)
369{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700370 return iommu_kmem_cache_alloc(iommu_devinfo_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700371}
372
373static inline void free_devinfo_mem(void *vaddr)
374{
375 kmem_cache_free(iommu_devinfo_cache, vaddr);
376}
377
378struct iova *alloc_iova_mem(void)
379{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700380 return iommu_kmem_cache_alloc(iommu_iova_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700381}
382
383void free_iova_mem(struct iova *iova)
384{
385 kmem_cache_free(iommu_iova_cache, iova);
386}
387
Weidong Han1b573682008-12-08 15:34:06 +0800388
389static inline int width_to_agaw(int width);
390
391/* calculate agaw for each iommu.
392 * "SAGAW" may be different across iommus, use a default agaw, and
393 * get a supported less agaw for iommus that don't support the default agaw.
394 */
395int iommu_calculate_agaw(struct intel_iommu *iommu)
396{
397 unsigned long sagaw;
398 int agaw = -1;
399
400 sagaw = cap_sagaw(iommu->cap);
401 for (agaw = width_to_agaw(DEFAULT_DOMAIN_ADDRESS_WIDTH);
402 agaw >= 0; agaw--) {
403 if (test_bit(agaw, &sagaw))
404 break;
405 }
406
407 return agaw;
408}
409
Weidong Han8c11e792008-12-08 15:29:22 +0800410/* in native case, each domain is related to only one iommu */
411static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
412{
413 int iommu_id;
414
Weidong Han1ce28fe2008-12-08 16:35:39 +0800415 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
416
Weidong Han8c11e792008-12-08 15:29:22 +0800417 iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
418 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
419 return NULL;
420
421 return g_iommus[iommu_id];
422}
423
Weidong Han8e6040972008-12-08 15:49:06 +0800424/* "Coherency" capability may be different across iommus */
425static void domain_update_iommu_coherency(struct dmar_domain *domain)
426{
427 int i;
428
429 domain->iommu_coherency = 1;
430
431 i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
432 for (; i < g_num_of_iommus; ) {
433 if (!ecap_coherent(g_iommus[i]->ecap)) {
434 domain->iommu_coherency = 0;
435 break;
436 }
437 i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
438 }
439}
440
Weidong Hanc7151a82008-12-08 22:51:37 +0800441static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn)
442{
443 struct dmar_drhd_unit *drhd = NULL;
444 int i;
445
446 for_each_drhd_unit(drhd) {
447 if (drhd->ignored)
448 continue;
449
450 for (i = 0; i < drhd->devices_cnt; i++)
Dirk Hohndel288e4872009-01-11 15:33:51 +0000451 if (drhd->devices[i] &&
452 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800453 drhd->devices[i]->devfn == devfn)
454 return drhd->iommu;
455
456 if (drhd->include_all)
457 return drhd->iommu;
458 }
459
460 return NULL;
461}
462
Weidong Han5331fe62008-12-08 23:00:00 +0800463static void domain_flush_cache(struct dmar_domain *domain,
464 void *addr, int size)
465{
466 if (!domain->iommu_coherency)
467 clflush_cache_range(addr, size);
468}
469
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700470/* Gets context entry for a given bus and devfn */
471static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
472 u8 bus, u8 devfn)
473{
474 struct root_entry *root;
475 struct context_entry *context;
476 unsigned long phy_addr;
477 unsigned long flags;
478
479 spin_lock_irqsave(&iommu->lock, flags);
480 root = &iommu->root_entry[bus];
481 context = get_context_addr_from_root(root);
482 if (!context) {
483 context = (struct context_entry *)alloc_pgtable_page();
484 if (!context) {
485 spin_unlock_irqrestore(&iommu->lock, flags);
486 return NULL;
487 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700488 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700489 phy_addr = virt_to_phys((void *)context);
490 set_root_value(root, phy_addr);
491 set_root_present(root);
492 __iommu_flush_cache(iommu, root, sizeof(*root));
493 }
494 spin_unlock_irqrestore(&iommu->lock, flags);
495 return &context[devfn];
496}
497
498static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
499{
500 struct root_entry *root;
501 struct context_entry *context;
502 int ret;
503 unsigned long flags;
504
505 spin_lock_irqsave(&iommu->lock, flags);
506 root = &iommu->root_entry[bus];
507 context = get_context_addr_from_root(root);
508 if (!context) {
509 ret = 0;
510 goto out;
511 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000512 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700513out:
514 spin_unlock_irqrestore(&iommu->lock, flags);
515 return ret;
516}
517
518static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
519{
520 struct root_entry *root;
521 struct context_entry *context;
522 unsigned long flags;
523
524 spin_lock_irqsave(&iommu->lock, flags);
525 root = &iommu->root_entry[bus];
526 context = get_context_addr_from_root(root);
527 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000528 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700529 __iommu_flush_cache(iommu, &context[devfn], \
530 sizeof(*context));
531 }
532 spin_unlock_irqrestore(&iommu->lock, flags);
533}
534
535static void free_context_table(struct intel_iommu *iommu)
536{
537 struct root_entry *root;
538 int i;
539 unsigned long flags;
540 struct context_entry *context;
541
542 spin_lock_irqsave(&iommu->lock, flags);
543 if (!iommu->root_entry) {
544 goto out;
545 }
546 for (i = 0; i < ROOT_ENTRY_NR; i++) {
547 root = &iommu->root_entry[i];
548 context = get_context_addr_from_root(root);
549 if (context)
550 free_pgtable_page(context);
551 }
552 free_pgtable_page(iommu->root_entry);
553 iommu->root_entry = NULL;
554out:
555 spin_unlock_irqrestore(&iommu->lock, flags);
556}
557
558/* page table handling */
559#define LEVEL_STRIDE (9)
560#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
561
562static inline int agaw_to_level(int agaw)
563{
564 return agaw + 2;
565}
566
567static inline int agaw_to_width(int agaw)
568{
569 return 30 + agaw * LEVEL_STRIDE;
570
571}
572
573static inline int width_to_agaw(int width)
574{
575 return (width - 30) / LEVEL_STRIDE;
576}
577
578static inline unsigned int level_to_offset_bits(int level)
579{
580 return (12 + (level - 1) * LEVEL_STRIDE);
581}
582
583static inline int address_level_offset(u64 addr, int level)
584{
585 return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK);
586}
587
588static inline u64 level_mask(int level)
589{
590 return ((u64)-1 << level_to_offset_bits(level));
591}
592
593static inline u64 level_size(int level)
594{
595 return ((u64)1 << level_to_offset_bits(level));
596}
597
598static inline u64 align_to_level(u64 addr, int level)
599{
600 return ((addr + level_size(level) - 1) & level_mask(level));
601}
602
603static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
604{
605 int addr_width = agaw_to_width(domain->agaw);
606 struct dma_pte *parent, *pte = NULL;
607 int level = agaw_to_level(domain->agaw);
608 int offset;
609 unsigned long flags;
610
611 BUG_ON(!domain->pgd);
612
613 addr &= (((u64)1) << addr_width) - 1;
614 parent = domain->pgd;
615
616 spin_lock_irqsave(&domain->mapping_lock, flags);
617 while (level > 0) {
618 void *tmp_page;
619
620 offset = address_level_offset(addr, level);
621 pte = &parent[offset];
622 if (level == 1)
623 break;
624
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000625 if (!dma_pte_present(pte)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700626 tmp_page = alloc_pgtable_page();
627
628 if (!tmp_page) {
629 spin_unlock_irqrestore(&domain->mapping_lock,
630 flags);
631 return NULL;
632 }
Weidong Han5331fe62008-12-08 23:00:00 +0800633 domain_flush_cache(domain, tmp_page, PAGE_SIZE);
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000634 dma_set_pte_addr(pte, virt_to_phys(tmp_page));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700635 /*
636 * high level table always sets r/w, last level page
637 * table control read/write
638 */
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000639 dma_set_pte_readable(pte);
640 dma_set_pte_writable(pte);
Weidong Han5331fe62008-12-08 23:00:00 +0800641 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700642 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000643 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700644 level--;
645 }
646
647 spin_unlock_irqrestore(&domain->mapping_lock, flags);
648 return pte;
649}
650
651/* return address's pte at specific level */
652static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
653 int level)
654{
655 struct dma_pte *parent, *pte = NULL;
656 int total = agaw_to_level(domain->agaw);
657 int offset;
658
659 parent = domain->pgd;
660 while (level <= total) {
661 offset = address_level_offset(addr, total);
662 pte = &parent[offset];
663 if (level == total)
664 return pte;
665
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000666 if (!dma_pte_present(pte))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700667 break;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000668 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700669 total--;
670 }
671 return NULL;
672}
673
674/* clear one page's page table */
675static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
676{
677 struct dma_pte *pte = NULL;
678
679 /* get last level pte */
680 pte = dma_addr_level_pte(domain, addr, 1);
681
682 if (pte) {
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000683 dma_clear_pte(pte);
Weidong Han5331fe62008-12-08 23:00:00 +0800684 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700685 }
686}
687
688/* clear last level pte, a tlb flush should be followed */
689static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
690{
691 int addr_width = agaw_to_width(domain->agaw);
692
693 start &= (((u64)1) << addr_width) - 1;
694 end &= (((u64)1) << addr_width) - 1;
695 /* in case it's partial page */
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700696 start = PAGE_ALIGN(start);
697 end &= PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700698
699 /* we don't need lock here, nobody else touches the iova range */
700 while (start < end) {
701 dma_pte_clear_one(domain, start);
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700702 start += VTD_PAGE_SIZE;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700703 }
704}
705
706/* free page table pages. last level pte should already be cleared */
707static void dma_pte_free_pagetable(struct dmar_domain *domain,
708 u64 start, u64 end)
709{
710 int addr_width = agaw_to_width(domain->agaw);
711 struct dma_pte *pte;
712 int total = agaw_to_level(domain->agaw);
713 int level;
714 u64 tmp;
715
716 start &= (((u64)1) << addr_width) - 1;
717 end &= (((u64)1) << addr_width) - 1;
718
719 /* we don't need lock here, nobody else touches the iova range */
720 level = 2;
721 while (level <= total) {
722 tmp = align_to_level(start, level);
723 if (tmp >= end || (tmp + level_size(level) > end))
724 return;
725
726 while (tmp < end) {
727 pte = dma_addr_level_pte(domain, tmp, level);
728 if (pte) {
729 free_pgtable_page(
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000730 phys_to_virt(dma_pte_addr(pte)));
731 dma_clear_pte(pte);
Weidong Han5331fe62008-12-08 23:00:00 +0800732 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700733 }
734 tmp += level_size(level);
735 }
736 level++;
737 }
738 /* free pgd */
739 if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
740 free_pgtable_page(domain->pgd);
741 domain->pgd = NULL;
742 }
743}
744
745/* iommu handling */
746static int iommu_alloc_root_entry(struct intel_iommu *iommu)
747{
748 struct root_entry *root;
749 unsigned long flags;
750
751 root = (struct root_entry *)alloc_pgtable_page();
752 if (!root)
753 return -ENOMEM;
754
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700755 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700756
757 spin_lock_irqsave(&iommu->lock, flags);
758 iommu->root_entry = root;
759 spin_unlock_irqrestore(&iommu->lock, flags);
760
761 return 0;
762}
763
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700764static void iommu_set_root_entry(struct intel_iommu *iommu)
765{
766 void *addr;
767 u32 cmd, sts;
768 unsigned long flag;
769
770 addr = iommu->root_entry;
771
772 spin_lock_irqsave(&iommu->register_lock, flag);
773 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
774
775 cmd = iommu->gcmd | DMA_GCMD_SRTP;
776 writel(cmd, iommu->reg + DMAR_GCMD_REG);
777
778 /* Make sure hardware complete it */
779 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
780 readl, (sts & DMA_GSTS_RTPS), sts);
781
782 spin_unlock_irqrestore(&iommu->register_lock, flag);
783}
784
785static void iommu_flush_write_buffer(struct intel_iommu *iommu)
786{
787 u32 val;
788 unsigned long flag;
789
David Woodhouse9af88142009-02-13 23:18:03 +0000790 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700791 return;
792 val = iommu->gcmd | DMA_GCMD_WBF;
793
794 spin_lock_irqsave(&iommu->register_lock, flag);
795 writel(val, iommu->reg + DMAR_GCMD_REG);
796
797 /* Make sure hardware complete it */
798 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
799 readl, (!(val & DMA_GSTS_WBFS)), val);
800
801 spin_unlock_irqrestore(&iommu->register_lock, flag);
802}
803
804/* return value determine if we need a write buffer flush */
805static int __iommu_flush_context(struct intel_iommu *iommu,
806 u16 did, u16 source_id, u8 function_mask, u64 type,
807 int non_present_entry_flush)
808{
809 u64 val = 0;
810 unsigned long flag;
811
812 /*
813 * In the non-present entry flush case, if hardware doesn't cache
814 * non-present entry we do nothing and if hardware cache non-present
815 * entry, we flush entries of domain 0 (the domain id is used to cache
816 * any non-present entries)
817 */
818 if (non_present_entry_flush) {
819 if (!cap_caching_mode(iommu->cap))
820 return 1;
821 else
822 did = 0;
823 }
824
825 switch (type) {
826 case DMA_CCMD_GLOBAL_INVL:
827 val = DMA_CCMD_GLOBAL_INVL;
828 break;
829 case DMA_CCMD_DOMAIN_INVL:
830 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
831 break;
832 case DMA_CCMD_DEVICE_INVL:
833 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
834 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
835 break;
836 default:
837 BUG();
838 }
839 val |= DMA_CCMD_ICC;
840
841 spin_lock_irqsave(&iommu->register_lock, flag);
842 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
843
844 /* Make sure hardware complete it */
845 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
846 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
847
848 spin_unlock_irqrestore(&iommu->register_lock, flag);
849
Ameya Palande4d235ba2008-10-18 20:27:30 -0700850 /* flush context entry will implicitly flush write buffer */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700851 return 0;
852}
853
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700854/* return value determine if we need a write buffer flush */
855static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
856 u64 addr, unsigned int size_order, u64 type,
857 int non_present_entry_flush)
858{
859 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
860 u64 val = 0, val_iva = 0;
861 unsigned long flag;
862
863 /*
864 * In the non-present entry flush case, if hardware doesn't cache
865 * non-present entry we do nothing and if hardware cache non-present
866 * entry, we flush entries of domain 0 (the domain id is used to cache
867 * any non-present entries)
868 */
869 if (non_present_entry_flush) {
870 if (!cap_caching_mode(iommu->cap))
871 return 1;
872 else
873 did = 0;
874 }
875
876 switch (type) {
877 case DMA_TLB_GLOBAL_FLUSH:
878 /* global flush doesn't need set IVA_REG */
879 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
880 break;
881 case DMA_TLB_DSI_FLUSH:
882 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
883 break;
884 case DMA_TLB_PSI_FLUSH:
885 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
886 /* Note: always flush non-leaf currently */
887 val_iva = size_order | addr;
888 break;
889 default:
890 BUG();
891 }
892 /* Note: set drain read/write */
893#if 0
894 /*
895 * This is probably to be super secure.. Looks like we can
896 * ignore it without any impact.
897 */
898 if (cap_read_drain(iommu->cap))
899 val |= DMA_TLB_READ_DRAIN;
900#endif
901 if (cap_write_drain(iommu->cap))
902 val |= DMA_TLB_WRITE_DRAIN;
903
904 spin_lock_irqsave(&iommu->register_lock, flag);
905 /* Note: Only uses first TLB reg currently */
906 if (val_iva)
907 dmar_writeq(iommu->reg + tlb_offset, val_iva);
908 dmar_writeq(iommu->reg + tlb_offset + 8, val);
909
910 /* Make sure hardware complete it */
911 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
912 dmar_readq, (!(val & DMA_TLB_IVT)), val);
913
914 spin_unlock_irqrestore(&iommu->register_lock, flag);
915
916 /* check IOTLB invalidation granularity */
917 if (DMA_TLB_IAIG(val) == 0)
918 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
919 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
920 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700921 (unsigned long long)DMA_TLB_IIRG(type),
922 (unsigned long long)DMA_TLB_IAIG(val));
Ameya Palande4d235ba2008-10-18 20:27:30 -0700923 /* flush iotlb entry will implicitly flush write buffer */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700924 return 0;
925}
926
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700927static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
928 u64 addr, unsigned int pages, int non_present_entry_flush)
929{
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700930 unsigned int mask;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700931
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700932 BUG_ON(addr & (~VTD_PAGE_MASK));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700933 BUG_ON(pages == 0);
934
935 /* Fallback to domain selective flush if no PSI support */
936 if (!cap_pgsel_inv(iommu->cap))
Youquan Songa77b67d2008-10-16 16:31:56 -0700937 return iommu->flush.flush_iotlb(iommu, did, 0, 0,
938 DMA_TLB_DSI_FLUSH,
939 non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700940
941 /*
942 * PSI requires page size to be 2 ^ x, and the base address is naturally
943 * aligned to the size
944 */
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700945 mask = ilog2(__roundup_pow_of_two(pages));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700946 /* Fallback to domain selective flush if size is too big */
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700947 if (mask > cap_max_amask_val(iommu->cap))
Youquan Songa77b67d2008-10-16 16:31:56 -0700948 return iommu->flush.flush_iotlb(iommu, did, 0, 0,
949 DMA_TLB_DSI_FLUSH, non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700950
Youquan Songa77b67d2008-10-16 16:31:56 -0700951 return iommu->flush.flush_iotlb(iommu, did, addr, mask,
952 DMA_TLB_PSI_FLUSH,
953 non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700954}
955
mark grossf8bab732008-02-08 04:18:38 -0800956static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
957{
958 u32 pmen;
959 unsigned long flags;
960
961 spin_lock_irqsave(&iommu->register_lock, flags);
962 pmen = readl(iommu->reg + DMAR_PMEN_REG);
963 pmen &= ~DMA_PMEN_EPM;
964 writel(pmen, iommu->reg + DMAR_PMEN_REG);
965
966 /* wait for the protected region status bit to clear */
967 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
968 readl, !(pmen & DMA_PMEN_PRS), pmen);
969
970 spin_unlock_irqrestore(&iommu->register_lock, flags);
971}
972
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700973static int iommu_enable_translation(struct intel_iommu *iommu)
974{
975 u32 sts;
976 unsigned long flags;
977
978 spin_lock_irqsave(&iommu->register_lock, flags);
979 writel(iommu->gcmd|DMA_GCMD_TE, iommu->reg + DMAR_GCMD_REG);
980
981 /* Make sure hardware complete it */
982 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
983 readl, (sts & DMA_GSTS_TES), sts);
984
985 iommu->gcmd |= DMA_GCMD_TE;
986 spin_unlock_irqrestore(&iommu->register_lock, flags);
987 return 0;
988}
989
990static int iommu_disable_translation(struct intel_iommu *iommu)
991{
992 u32 sts;
993 unsigned long flag;
994
995 spin_lock_irqsave(&iommu->register_lock, flag);
996 iommu->gcmd &= ~DMA_GCMD_TE;
997 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
998
999 /* Make sure hardware complete it */
1000 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
1001 readl, (!(sts & DMA_GSTS_TES)), sts);
1002
1003 spin_unlock_irqrestore(&iommu->register_lock, flag);
1004 return 0;
1005}
1006
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001007/* iommu interrupt handling. Most stuff are MSI-like. */
1008
mark grossd94afc62008-02-08 04:18:39 -08001009static const char *fault_reason_strings[] =
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001010{
1011 "Software",
1012 "Present bit in root entry is clear",
1013 "Present bit in context entry is clear",
1014 "Invalid context entry",
1015 "Access beyond MGAW",
1016 "PTE Write access is not set",
1017 "PTE Read access is not set",
1018 "Next page table ptr is invalid",
1019 "Root table address invalid",
1020 "Context table ptr is invalid",
1021 "non-zero reserved fields in RTP",
1022 "non-zero reserved fields in CTP",
1023 "non-zero reserved fields in PTE",
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001024};
mark grossf8bab732008-02-08 04:18:38 -08001025#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001026
mark grossd94afc62008-02-08 04:18:39 -08001027const char *dmar_get_fault_reason(u8 fault_reason)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001028{
mark grossd94afc62008-02-08 04:18:39 -08001029 if (fault_reason > MAX_FAULT_REASON_IDX)
1030 return "Unknown";
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001031 else
1032 return fault_reason_strings[fault_reason];
1033}
1034
1035void dmar_msi_unmask(unsigned int irq)
1036{
1037 struct intel_iommu *iommu = get_irq_data(irq);
1038 unsigned long flag;
1039
1040 /* unmask it */
1041 spin_lock_irqsave(&iommu->register_lock, flag);
1042 writel(0, iommu->reg + DMAR_FECTL_REG);
1043 /* Read a reg to force flush the post write */
1044 readl(iommu->reg + DMAR_FECTL_REG);
1045 spin_unlock_irqrestore(&iommu->register_lock, flag);
1046}
1047
1048void dmar_msi_mask(unsigned int irq)
1049{
1050 unsigned long flag;
1051 struct intel_iommu *iommu = get_irq_data(irq);
1052
1053 /* mask it */
1054 spin_lock_irqsave(&iommu->register_lock, flag);
1055 writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
1056 /* Read a reg to force flush the post write */
1057 readl(iommu->reg + DMAR_FECTL_REG);
1058 spin_unlock_irqrestore(&iommu->register_lock, flag);
1059}
1060
1061void dmar_msi_write(int irq, struct msi_msg *msg)
1062{
1063 struct intel_iommu *iommu = get_irq_data(irq);
1064 unsigned long flag;
1065
1066 spin_lock_irqsave(&iommu->register_lock, flag);
1067 writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
1068 writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
1069 writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
1070 spin_unlock_irqrestore(&iommu->register_lock, flag);
1071}
1072
1073void dmar_msi_read(int irq, struct msi_msg *msg)
1074{
1075 struct intel_iommu *iommu = get_irq_data(irq);
1076 unsigned long flag;
1077
1078 spin_lock_irqsave(&iommu->register_lock, flag);
1079 msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
1080 msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
1081 msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
1082 spin_unlock_irqrestore(&iommu->register_lock, flag);
1083}
1084
1085static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001086 u8 fault_reason, u16 source_id, unsigned long long addr)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001087{
mark grossd94afc62008-02-08 04:18:39 -08001088 const char *reason;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001089
1090 reason = dmar_get_fault_reason(fault_reason);
1091
1092 printk(KERN_ERR
1093 "DMAR:[%s] Request device [%02x:%02x.%d] "
1094 "fault addr %llx \n"
1095 "DMAR:[fault reason %02d] %s\n",
1096 (type ? "DMA Read" : "DMA Write"),
1097 (source_id >> 8), PCI_SLOT(source_id & 0xFF),
1098 PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
1099 return 0;
1100}
1101
1102#define PRIMARY_FAULT_REG_LEN (16)
1103static irqreturn_t iommu_page_fault(int irq, void *dev_id)
1104{
1105 struct intel_iommu *iommu = dev_id;
1106 int reg, fault_index;
1107 u32 fault_status;
1108 unsigned long flag;
1109
1110 spin_lock_irqsave(&iommu->register_lock, flag);
1111 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
1112
1113 /* TBD: ignore advanced fault log currently */
1114 if (!(fault_status & DMA_FSTS_PPF))
1115 goto clear_overflow;
1116
1117 fault_index = dma_fsts_fault_record_index(fault_status);
1118 reg = cap_fault_reg_offset(iommu->cap);
1119 while (1) {
1120 u8 fault_reason;
1121 u16 source_id;
1122 u64 guest_addr;
1123 int type;
1124 u32 data;
1125
1126 /* highest 32 bits */
1127 data = readl(iommu->reg + reg +
1128 fault_index * PRIMARY_FAULT_REG_LEN + 12);
1129 if (!(data & DMA_FRCD_F))
1130 break;
1131
1132 fault_reason = dma_frcd_fault_reason(data);
1133 type = dma_frcd_type(data);
1134
1135 data = readl(iommu->reg + reg +
1136 fault_index * PRIMARY_FAULT_REG_LEN + 8);
1137 source_id = dma_frcd_source_id(data);
1138
1139 guest_addr = dmar_readq(iommu->reg + reg +
1140 fault_index * PRIMARY_FAULT_REG_LEN);
1141 guest_addr = dma_frcd_page_addr(guest_addr);
1142 /* clear the fault */
1143 writel(DMA_FRCD_F, iommu->reg + reg +
1144 fault_index * PRIMARY_FAULT_REG_LEN + 12);
1145
1146 spin_unlock_irqrestore(&iommu->register_lock, flag);
1147
1148 iommu_page_fault_do_one(iommu, type, fault_reason,
1149 source_id, guest_addr);
1150
1151 fault_index++;
1152 if (fault_index > cap_num_fault_regs(iommu->cap))
1153 fault_index = 0;
1154 spin_lock_irqsave(&iommu->register_lock, flag);
1155 }
1156clear_overflow:
1157 /* clear primary fault overflow */
1158 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
1159 if (fault_status & DMA_FSTS_PFO)
1160 writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
1161
1162 spin_unlock_irqrestore(&iommu->register_lock, flag);
1163 return IRQ_HANDLED;
1164}
1165
1166int dmar_set_interrupt(struct intel_iommu *iommu)
1167{
1168 int irq, ret;
1169
1170 irq = create_irq();
1171 if (!irq) {
1172 printk(KERN_ERR "IOMMU: no free vectors\n");
1173 return -EINVAL;
1174 }
1175
1176 set_irq_data(irq, iommu);
1177 iommu->irq = irq;
1178
1179 ret = arch_setup_dmar_msi(irq);
1180 if (ret) {
1181 set_irq_data(irq, NULL);
1182 iommu->irq = 0;
1183 destroy_irq(irq);
1184 return 0;
1185 }
1186
1187 /* Force fault register is cleared */
1188 iommu_page_fault(irq, iommu);
1189
1190 ret = request_irq(irq, iommu_page_fault, 0, iommu->name, iommu);
1191 if (ret)
1192 printk(KERN_ERR "IOMMU: can't request irq\n");
1193 return ret;
1194}
1195
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001196static int iommu_init_domains(struct intel_iommu *iommu)
1197{
1198 unsigned long ndomains;
1199 unsigned long nlongs;
1200
1201 ndomains = cap_ndoms(iommu->cap);
1202 pr_debug("Number of Domains supportd <%ld>\n", ndomains);
1203 nlongs = BITS_TO_LONGS(ndomains);
1204
1205 /* TBD: there might be 64K domains,
1206 * consider other allocation for future chip
1207 */
1208 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1209 if (!iommu->domain_ids) {
1210 printk(KERN_ERR "Allocating domain id array failed\n");
1211 return -ENOMEM;
1212 }
1213 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1214 GFP_KERNEL);
1215 if (!iommu->domains) {
1216 printk(KERN_ERR "Allocating domain array failed\n");
1217 kfree(iommu->domain_ids);
1218 return -ENOMEM;
1219 }
1220
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001221 spin_lock_init(&iommu->lock);
1222
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001223 /*
1224 * if Caching mode is set, then invalid translations are tagged
1225 * with domainid 0. Hence we need to pre-allocate it.
1226 */
1227 if (cap_caching_mode(iommu->cap))
1228 set_bit(0, iommu->domain_ids);
1229 return 0;
1230}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001231
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001232
1233static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001234static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001235
1236void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001237{
1238 struct dmar_domain *domain;
1239 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001240 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001241
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001242 i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
1243 for (; i < cap_ndoms(iommu->cap); ) {
1244 domain = iommu->domains[i];
1245 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001246
1247 spin_lock_irqsave(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001248 if (--domain->iommu_count == 0) {
1249 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1250 vm_domain_exit(domain);
1251 else
1252 domain_exit(domain);
1253 }
Weidong Hanc7151a82008-12-08 22:51:37 +08001254 spin_unlock_irqrestore(&domain->iommu_lock, flags);
1255
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001256 i = find_next_bit(iommu->domain_ids,
1257 cap_ndoms(iommu->cap), i+1);
1258 }
1259
1260 if (iommu->gcmd & DMA_GCMD_TE)
1261 iommu_disable_translation(iommu);
1262
1263 if (iommu->irq) {
1264 set_irq_data(iommu->irq, NULL);
1265 /* This will mask the irq */
1266 free_irq(iommu->irq, iommu);
1267 destroy_irq(iommu->irq);
1268 }
1269
1270 kfree(iommu->domains);
1271 kfree(iommu->domain_ids);
1272
Weidong Hand9630fe2008-12-08 11:06:32 +08001273 g_iommus[iommu->seq_id] = NULL;
1274
1275 /* if all iommus are freed, free g_iommus */
1276 for (i = 0; i < g_num_of_iommus; i++) {
1277 if (g_iommus[i])
1278 break;
1279 }
1280
1281 if (i == g_num_of_iommus)
1282 kfree(g_iommus);
1283
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001284 /* free context mapping */
1285 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001286}
1287
1288static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
1289{
1290 unsigned long num;
1291 unsigned long ndomains;
1292 struct dmar_domain *domain;
1293 unsigned long flags;
1294
1295 domain = alloc_domain_mem();
1296 if (!domain)
1297 return NULL;
1298
1299 ndomains = cap_ndoms(iommu->cap);
1300
1301 spin_lock_irqsave(&iommu->lock, flags);
1302 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1303 if (num >= ndomains) {
1304 spin_unlock_irqrestore(&iommu->lock, flags);
1305 free_domain_mem(domain);
1306 printk(KERN_ERR "IOMMU: no free domain ids\n");
1307 return NULL;
1308 }
1309
1310 set_bit(num, iommu->domain_ids);
1311 domain->id = num;
Weidong Han8c11e792008-12-08 15:29:22 +08001312 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
1313 set_bit(iommu->seq_id, &domain->iommu_bmp);
Weidong Hand71a2f32008-12-07 21:13:41 +08001314 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001315 iommu->domains[num] = domain;
1316 spin_unlock_irqrestore(&iommu->lock, flags);
1317
1318 return domain;
1319}
1320
1321static void iommu_free_domain(struct dmar_domain *domain)
1322{
1323 unsigned long flags;
Weidong Han8c11e792008-12-08 15:29:22 +08001324 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001325
Weidong Han8c11e792008-12-08 15:29:22 +08001326 iommu = domain_get_iommu(domain);
1327
1328 spin_lock_irqsave(&iommu->lock, flags);
1329 clear_bit(domain->id, iommu->domain_ids);
1330 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001331}
1332
1333static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001334static struct lock_class_key reserved_alloc_key;
1335static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001336
1337static void dmar_init_reserved_ranges(void)
1338{
1339 struct pci_dev *pdev = NULL;
1340 struct iova *iova;
1341 int i;
1342 u64 addr, size;
1343
David Millerf6611972008-02-06 01:36:23 -08001344 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001345
Mark Gross8a443df2008-03-04 14:59:31 -08001346 lockdep_set_class(&reserved_iova_list.iova_alloc_lock,
1347 &reserved_alloc_key);
1348 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1349 &reserved_rbtree_key);
1350
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001351 /* IOAPIC ranges shouldn't be accessed by DMA */
1352 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1353 IOVA_PFN(IOAPIC_RANGE_END));
1354 if (!iova)
1355 printk(KERN_ERR "Reserve IOAPIC range failed\n");
1356
1357 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1358 for_each_pci_dev(pdev) {
1359 struct resource *r;
1360
1361 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1362 r = &pdev->resource[i];
1363 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1364 continue;
1365 addr = r->start;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001366 addr &= PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001367 size = r->end - addr;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001368 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001369 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
1370 IOVA_PFN(size + addr) - 1);
1371 if (!iova)
1372 printk(KERN_ERR "Reserve iova failed\n");
1373 }
1374 }
1375
1376}
1377
1378static void domain_reserve_special_ranges(struct dmar_domain *domain)
1379{
1380 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1381}
1382
1383static inline int guestwidth_to_adjustwidth(int gaw)
1384{
1385 int agaw;
1386 int r = (gaw - 12) % 9;
1387
1388 if (r == 0)
1389 agaw = gaw;
1390 else
1391 agaw = gaw + 9 - r;
1392 if (agaw > 64)
1393 agaw = 64;
1394 return agaw;
1395}
1396
1397static int domain_init(struct dmar_domain *domain, int guest_width)
1398{
1399 struct intel_iommu *iommu;
1400 int adjust_width, agaw;
1401 unsigned long sagaw;
1402
David Millerf6611972008-02-06 01:36:23 -08001403 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001404 spin_lock_init(&domain->mapping_lock);
Weidong Hanc7151a82008-12-08 22:51:37 +08001405 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001406
1407 domain_reserve_special_ranges(domain);
1408
1409 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001410 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001411 if (guest_width > cap_mgaw(iommu->cap))
1412 guest_width = cap_mgaw(iommu->cap);
1413 domain->gaw = guest_width;
1414 adjust_width = guestwidth_to_adjustwidth(guest_width);
1415 agaw = width_to_agaw(adjust_width);
1416 sagaw = cap_sagaw(iommu->cap);
1417 if (!test_bit(agaw, &sagaw)) {
1418 /* hardware doesn't support it, choose a bigger one */
1419 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1420 agaw = find_next_bit(&sagaw, 5, agaw);
1421 if (agaw >= 5)
1422 return -ENODEV;
1423 }
1424 domain->agaw = agaw;
1425 INIT_LIST_HEAD(&domain->devices);
1426
Weidong Han8e6040972008-12-08 15:49:06 +08001427 if (ecap_coherent(iommu->ecap))
1428 domain->iommu_coherency = 1;
1429 else
1430 domain->iommu_coherency = 0;
1431
Weidong Hanc7151a82008-12-08 22:51:37 +08001432 domain->iommu_count = 1;
1433
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001434 /* always allocate the top pgd */
1435 domain->pgd = (struct dma_pte *)alloc_pgtable_page();
1436 if (!domain->pgd)
1437 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001438 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001439 return 0;
1440}
1441
1442static void domain_exit(struct dmar_domain *domain)
1443{
1444 u64 end;
1445
1446 /* Domain 0 is reserved, so dont process it */
1447 if (!domain)
1448 return;
1449
1450 domain_remove_dev_info(domain);
1451 /* destroy iovas */
1452 put_iova_domain(&domain->iovad);
1453 end = DOMAIN_MAX_ADDR(domain->gaw);
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001454 end = end & (~PAGE_MASK);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001455
1456 /* clear ptes */
1457 dma_pte_clear_range(domain, 0, end);
1458
1459 /* free page tables */
1460 dma_pte_free_pagetable(domain, 0, end);
1461
1462 iommu_free_domain(domain);
1463 free_domain_mem(domain);
1464}
1465
1466static int domain_context_mapping_one(struct dmar_domain *domain,
1467 u8 bus, u8 devfn)
1468{
1469 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001470 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001471 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001472 struct dma_pte *pgd;
1473 unsigned long num;
1474 unsigned long ndomains;
1475 int id;
1476 int agaw;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001477
1478 pr_debug("Set context mapping for %02x:%02x.%d\n",
1479 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
1480 BUG_ON(!domain->pgd);
Weidong Han5331fe62008-12-08 23:00:00 +08001481
1482 iommu = device_to_iommu(bus, devfn);
1483 if (!iommu)
1484 return -ENODEV;
1485
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001486 context = device_to_context_entry(iommu, bus, devfn);
1487 if (!context)
1488 return -ENOMEM;
1489 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001490 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001491 spin_unlock_irqrestore(&iommu->lock, flags);
1492 return 0;
1493 }
1494
Weidong Hanea6606b2008-12-08 23:08:15 +08001495 id = domain->id;
1496 pgd = domain->pgd;
1497
1498 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
1499 int found = 0;
1500
1501 /* find an available domain id for this device in iommu */
1502 ndomains = cap_ndoms(iommu->cap);
1503 num = find_first_bit(iommu->domain_ids, ndomains);
1504 for (; num < ndomains; ) {
1505 if (iommu->domains[num] == domain) {
1506 id = num;
1507 found = 1;
1508 break;
1509 }
1510 num = find_next_bit(iommu->domain_ids,
1511 cap_ndoms(iommu->cap), num+1);
1512 }
1513
1514 if (found == 0) {
1515 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1516 if (num >= ndomains) {
1517 spin_unlock_irqrestore(&iommu->lock, flags);
1518 printk(KERN_ERR "IOMMU: no free domain ids\n");
1519 return -EFAULT;
1520 }
1521
1522 set_bit(num, iommu->domain_ids);
1523 iommu->domains[num] = domain;
1524 id = num;
1525 }
1526
1527 /* Skip top levels of page tables for
1528 * iommu which has less agaw than default.
1529 */
1530 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1531 pgd = phys_to_virt(dma_pte_addr(pgd));
1532 if (!dma_pte_present(pgd)) {
1533 spin_unlock_irqrestore(&iommu->lock, flags);
1534 return -ENOMEM;
1535 }
1536 }
1537 }
1538
1539 context_set_domain_id(context, id);
1540 context_set_address_width(context, iommu->agaw);
1541 context_set_address_root(context, virt_to_phys(pgd));
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001542 context_set_translation_type(context, CONTEXT_TT_MULTI_LEVEL);
1543 context_set_fault_enable(context);
1544 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001545 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001546
1547 /* it's a non-present to present mapping */
Youquan Songa77b67d2008-10-16 16:31:56 -07001548 if (iommu->flush.flush_context(iommu, domain->id,
1549 (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT,
1550 DMA_CCMD_DEVICE_INVL, 1))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001551 iommu_flush_write_buffer(iommu);
1552 else
Youquan Songa77b67d2008-10-16 16:31:56 -07001553 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH, 0);
1554
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001555 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001556
1557 spin_lock_irqsave(&domain->iommu_lock, flags);
1558 if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
1559 domain->iommu_count++;
1560 domain_update_iommu_coherency(domain);
1561 }
1562 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001563 return 0;
1564}
1565
1566static int
1567domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev)
1568{
1569 int ret;
1570 struct pci_dev *tmp, *parent;
1571
1572 ret = domain_context_mapping_one(domain, pdev->bus->number,
1573 pdev->devfn);
1574 if (ret)
1575 return ret;
1576
1577 /* dependent device mapping */
1578 tmp = pci_find_upstream_pcie_bridge(pdev);
1579 if (!tmp)
1580 return 0;
1581 /* Secondary interface's bus number and devfn 0 */
1582 parent = pdev->bus->self;
1583 while (parent != tmp) {
1584 ret = domain_context_mapping_one(domain, parent->bus->number,
1585 parent->devfn);
1586 if (ret)
1587 return ret;
1588 parent = parent->bus->self;
1589 }
1590 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
1591 return domain_context_mapping_one(domain,
1592 tmp->subordinate->number, 0);
1593 else /* this is a legacy PCI bridge */
1594 return domain_context_mapping_one(domain,
1595 tmp->bus->number, tmp->devfn);
1596}
1597
Weidong Han5331fe62008-12-08 23:00:00 +08001598static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001599{
1600 int ret;
1601 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001602 struct intel_iommu *iommu;
1603
1604 iommu = device_to_iommu(pdev->bus->number, pdev->devfn);
1605 if (!iommu)
1606 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001607
Weidong Han8c11e792008-12-08 15:29:22 +08001608 ret = device_context_mapped(iommu,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001609 pdev->bus->number, pdev->devfn);
1610 if (!ret)
1611 return ret;
1612 /* dependent device mapping */
1613 tmp = pci_find_upstream_pcie_bridge(pdev);
1614 if (!tmp)
1615 return ret;
1616 /* Secondary interface's bus number and devfn 0 */
1617 parent = pdev->bus->self;
1618 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001619 ret = device_context_mapped(iommu, parent->bus->number,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001620 parent->devfn);
1621 if (!ret)
1622 return ret;
1623 parent = parent->bus->self;
1624 }
1625 if (tmp->is_pcie)
Weidong Han8c11e792008-12-08 15:29:22 +08001626 return device_context_mapped(iommu,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001627 tmp->subordinate->number, 0);
1628 else
Weidong Han8c11e792008-12-08 15:29:22 +08001629 return device_context_mapped(iommu,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001630 tmp->bus->number, tmp->devfn);
1631}
1632
1633static int
1634domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
1635 u64 hpa, size_t size, int prot)
1636{
1637 u64 start_pfn, end_pfn;
1638 struct dma_pte *pte;
1639 int index;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001640 int addr_width = agaw_to_width(domain->agaw);
1641
1642 hpa &= (((u64)1) << addr_width) - 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001643
1644 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1645 return -EINVAL;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001646 iova &= PAGE_MASK;
1647 start_pfn = ((u64)hpa) >> VTD_PAGE_SHIFT;
1648 end_pfn = (VTD_PAGE_ALIGN(((u64)hpa) + size)) >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001649 index = 0;
1650 while (start_pfn < end_pfn) {
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001651 pte = addr_to_dma_pte(domain, iova + VTD_PAGE_SIZE * index);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001652 if (!pte)
1653 return -ENOMEM;
1654 /* We don't need lock here, nobody else
1655 * touches the iova range
1656 */
Mark McLoughlin19c239c2008-11-21 16:56:53 +00001657 BUG_ON(dma_pte_addr(pte));
1658 dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT);
1659 dma_set_pte_prot(pte, prot);
Weidong Han5331fe62008-12-08 23:00:00 +08001660 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001661 start_pfn++;
1662 index++;
1663 }
1664 return 0;
1665}
1666
Weidong Hanc7151a82008-12-08 22:51:37 +08001667static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001668{
Weidong Hanc7151a82008-12-08 22:51:37 +08001669 if (!iommu)
1670 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001671
1672 clear_context_table(iommu, bus, devfn);
1673 iommu->flush.flush_context(iommu, 0, 0, 0,
Youquan Songa77b67d2008-10-16 16:31:56 -07001674 DMA_CCMD_GLOBAL_INVL, 0);
Weidong Han8c11e792008-12-08 15:29:22 +08001675 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Youquan Songa77b67d2008-10-16 16:31:56 -07001676 DMA_TLB_GLOBAL_FLUSH, 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001677}
1678
1679static void domain_remove_dev_info(struct dmar_domain *domain)
1680{
1681 struct device_domain_info *info;
1682 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001683 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001684
1685 spin_lock_irqsave(&device_domain_lock, flags);
1686 while (!list_empty(&domain->devices)) {
1687 info = list_entry(domain->devices.next,
1688 struct device_domain_info, link);
1689 list_del(&info->link);
1690 list_del(&info->global);
1691 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001692 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001693 spin_unlock_irqrestore(&device_domain_lock, flags);
1694
Weidong Hanc7151a82008-12-08 22:51:37 +08001695 iommu = device_to_iommu(info->bus, info->devfn);
1696 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001697 free_devinfo_mem(info);
1698
1699 spin_lock_irqsave(&device_domain_lock, flags);
1700 }
1701 spin_unlock_irqrestore(&device_domain_lock, flags);
1702}
1703
1704/*
1705 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001706 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001707 */
Kay, Allen M38717942008-09-09 18:37:29 +03001708static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001709find_domain(struct pci_dev *pdev)
1710{
1711 struct device_domain_info *info;
1712
1713 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001714 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001715 if (info)
1716 return info->domain;
1717 return NULL;
1718}
1719
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001720/* domain is initialized */
1721static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1722{
1723 struct dmar_domain *domain, *found = NULL;
1724 struct intel_iommu *iommu;
1725 struct dmar_drhd_unit *drhd;
1726 struct device_domain_info *info, *tmp;
1727 struct pci_dev *dev_tmp;
1728 unsigned long flags;
1729 int bus = 0, devfn = 0;
1730
1731 domain = find_domain(pdev);
1732 if (domain)
1733 return domain;
1734
1735 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1736 if (dev_tmp) {
1737 if (dev_tmp->is_pcie) {
1738 bus = dev_tmp->subordinate->number;
1739 devfn = 0;
1740 } else {
1741 bus = dev_tmp->bus->number;
1742 devfn = dev_tmp->devfn;
1743 }
1744 spin_lock_irqsave(&device_domain_lock, flags);
1745 list_for_each_entry(info, &device_domain_list, global) {
1746 if (info->bus == bus && info->devfn == devfn) {
1747 found = info->domain;
1748 break;
1749 }
1750 }
1751 spin_unlock_irqrestore(&device_domain_lock, flags);
1752 /* pcie-pci bridge already has a domain, uses it */
1753 if (found) {
1754 domain = found;
1755 goto found_domain;
1756 }
1757 }
1758
1759 /* Allocate new domain for the device */
1760 drhd = dmar_find_matched_drhd_unit(pdev);
1761 if (!drhd) {
1762 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
1763 pci_name(pdev));
1764 return NULL;
1765 }
1766 iommu = drhd->iommu;
1767
1768 domain = iommu_alloc_domain(iommu);
1769 if (!domain)
1770 goto error;
1771
1772 if (domain_init(domain, gaw)) {
1773 domain_exit(domain);
1774 goto error;
1775 }
1776
1777 /* register pcie-to-pci device */
1778 if (dev_tmp) {
1779 info = alloc_devinfo_mem();
1780 if (!info) {
1781 domain_exit(domain);
1782 goto error;
1783 }
1784 info->bus = bus;
1785 info->devfn = devfn;
1786 info->dev = NULL;
1787 info->domain = domain;
1788 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08001789 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001790
1791 /* pcie-to-pci bridge already has a domain, uses it */
1792 found = NULL;
1793 spin_lock_irqsave(&device_domain_lock, flags);
1794 list_for_each_entry(tmp, &device_domain_list, global) {
1795 if (tmp->bus == bus && tmp->devfn == devfn) {
1796 found = tmp->domain;
1797 break;
1798 }
1799 }
1800 if (found) {
1801 free_devinfo_mem(info);
1802 domain_exit(domain);
1803 domain = found;
1804 } else {
1805 list_add(&info->link, &domain->devices);
1806 list_add(&info->global, &device_domain_list);
1807 }
1808 spin_unlock_irqrestore(&device_domain_lock, flags);
1809 }
1810
1811found_domain:
1812 info = alloc_devinfo_mem();
1813 if (!info)
1814 goto error;
1815 info->bus = pdev->bus->number;
1816 info->devfn = pdev->devfn;
1817 info->dev = pdev;
1818 info->domain = domain;
1819 spin_lock_irqsave(&device_domain_lock, flags);
1820 /* somebody is fast */
1821 found = find_domain(pdev);
1822 if (found != NULL) {
1823 spin_unlock_irqrestore(&device_domain_lock, flags);
1824 if (found != domain) {
1825 domain_exit(domain);
1826 domain = found;
1827 }
1828 free_devinfo_mem(info);
1829 return domain;
1830 }
1831 list_add(&info->link, &domain->devices);
1832 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001833 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001834 spin_unlock_irqrestore(&device_domain_lock, flags);
1835 return domain;
1836error:
1837 /* recheck it here, maybe others set it */
1838 return find_domain(pdev);
1839}
1840
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001841static int iommu_prepare_identity_map(struct pci_dev *pdev,
1842 unsigned long long start,
1843 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001844{
1845 struct dmar_domain *domain;
1846 unsigned long size;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001847 unsigned long long base;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001848 int ret;
1849
1850 printk(KERN_INFO
1851 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
1852 pci_name(pdev), start, end);
1853 /* page table init */
1854 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
1855 if (!domain)
1856 return -ENOMEM;
1857
1858 /* The address might not be aligned */
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001859 base = start & PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001860 size = end - base;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001861 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001862 if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
1863 IOVA_PFN(base + size) - 1)) {
1864 printk(KERN_ERR "IOMMU: reserve iova failed\n");
1865 ret = -ENOMEM;
1866 goto error;
1867 }
1868
1869 pr_debug("Mapping reserved region %lx@%llx for %s\n",
1870 size, base, pci_name(pdev));
1871 /*
1872 * RMRR range might have overlap with physical memory range,
1873 * clear it first
1874 */
1875 dma_pte_clear_range(domain, base, base + size);
1876
1877 ret = domain_page_mapping(domain, base, base, size,
1878 DMA_PTE_READ|DMA_PTE_WRITE);
1879 if (ret)
1880 goto error;
1881
1882 /* context entry init */
1883 ret = domain_context_mapping(domain, pdev);
1884 if (!ret)
1885 return 0;
1886error:
1887 domain_exit(domain);
1888 return ret;
1889
1890}
1891
1892static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
1893 struct pci_dev *pdev)
1894{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001895 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001896 return 0;
1897 return iommu_prepare_identity_map(pdev, rmrr->base_address,
1898 rmrr->end_address + 1);
1899}
1900
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001901#ifdef CONFIG_DMAR_GFX_WA
Yinghai Lud52d53b2008-06-16 20:10:55 -07001902struct iommu_prepare_data {
1903 struct pci_dev *pdev;
1904 int ret;
1905};
1906
1907static int __init iommu_prepare_work_fn(unsigned long start_pfn,
1908 unsigned long end_pfn, void *datax)
1909{
1910 struct iommu_prepare_data *data;
1911
1912 data = (struct iommu_prepare_data *)datax;
1913
1914 data->ret = iommu_prepare_identity_map(data->pdev,
1915 start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
1916 return data->ret;
1917
1918}
1919
1920static int __init iommu_prepare_with_active_regions(struct pci_dev *pdev)
1921{
1922 int nid;
1923 struct iommu_prepare_data data;
1924
1925 data.pdev = pdev;
1926 data.ret = 0;
1927
1928 for_each_online_node(nid) {
1929 work_with_active_regions(nid, iommu_prepare_work_fn, &data);
1930 if (data.ret)
1931 return data.ret;
1932 }
1933 return data.ret;
1934}
1935
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001936static void __init iommu_prepare_gfx_mapping(void)
1937{
1938 struct pci_dev *pdev = NULL;
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001939 int ret;
1940
1941 for_each_pci_dev(pdev) {
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001942 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001943 !IS_GFX_DEVICE(pdev))
1944 continue;
1945 printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
1946 pci_name(pdev));
Yinghai Lud52d53b2008-06-16 20:10:55 -07001947 ret = iommu_prepare_with_active_regions(pdev);
1948 if (ret)
1949 printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001950 }
1951}
Mark McLoughlin2abd7e12008-11-20 15:49:50 +00001952#else /* !CONFIG_DMAR_GFX_WA */
1953static inline void iommu_prepare_gfx_mapping(void)
1954{
1955 return;
1956}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001957#endif
1958
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07001959#ifdef CONFIG_DMAR_FLOPPY_WA
1960static inline void iommu_prepare_isa(void)
1961{
1962 struct pci_dev *pdev;
1963 int ret;
1964
1965 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
1966 if (!pdev)
1967 return;
1968
1969 printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n");
1970 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
1971
1972 if (ret)
1973 printk("IOMMU: Failed to create 0-64M identity map, "
1974 "floppy might not work\n");
1975
1976}
1977#else
1978static inline void iommu_prepare_isa(void)
1979{
1980 return;
1981}
1982#endif /* !CONFIG_DMAR_FLPY_WA */
1983
Mark McLoughlin519a0542008-11-20 14:21:13 +00001984static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001985{
1986 struct dmar_drhd_unit *drhd;
1987 struct dmar_rmrr_unit *rmrr;
1988 struct pci_dev *pdev;
1989 struct intel_iommu *iommu;
mark gross80b20dd2008-04-18 13:53:58 -07001990 int i, ret, unit = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001991
1992 /*
1993 * for each drhd
1994 * allocate root
1995 * initialize and program root entry to not present
1996 * endfor
1997 */
1998 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08001999 g_num_of_iommus++;
2000 /*
2001 * lock not needed as this is only incremented in the single
2002 * threaded kernel __init code path all other access are read
2003 * only
2004 */
2005 }
2006
Weidong Hand9630fe2008-12-08 11:06:32 +08002007 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2008 GFP_KERNEL);
2009 if (!g_iommus) {
2010 printk(KERN_ERR "Allocating global iommu array failed\n");
2011 ret = -ENOMEM;
2012 goto error;
2013 }
2014
mark gross80b20dd2008-04-18 13:53:58 -07002015 deferred_flush = kzalloc(g_num_of_iommus *
2016 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2017 if (!deferred_flush) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002018 kfree(g_iommus);
mark gross5e0d2a62008-03-04 15:22:08 -08002019 ret = -ENOMEM;
2020 goto error;
2021 }
2022
mark gross5e0d2a62008-03-04 15:22:08 -08002023 for_each_drhd_unit(drhd) {
2024 if (drhd->ignored)
2025 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002026
2027 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002028 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002029
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002030 ret = iommu_init_domains(iommu);
2031 if (ret)
2032 goto error;
2033
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002034 /*
2035 * TBD:
2036 * we could share the same root & context tables
2037 * amoung all IOMMU's. Need to Split it later.
2038 */
2039 ret = iommu_alloc_root_entry(iommu);
2040 if (ret) {
2041 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2042 goto error;
2043 }
2044 }
2045
Youquan Songa77b67d2008-10-16 16:31:56 -07002046 for_each_drhd_unit(drhd) {
2047 if (drhd->ignored)
2048 continue;
2049
2050 iommu = drhd->iommu;
2051 if (dmar_enable_qi(iommu)) {
2052 /*
2053 * Queued Invalidate not enabled, use Register Based
2054 * Invalidate
2055 */
2056 iommu->flush.flush_context = __iommu_flush_context;
2057 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
2058 printk(KERN_INFO "IOMMU 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002059 "invalidation\n",
2060 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002061 } else {
2062 iommu->flush.flush_context = qi_flush_context;
2063 iommu->flush.flush_iotlb = qi_flush_iotlb;
2064 printk(KERN_INFO "IOMMU 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002065 "invalidation\n",
2066 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002067 }
2068 }
2069
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002070 /*
2071 * For each rmrr
2072 * for each dev attached to rmrr
2073 * do
2074 * locate drhd for dev, alloc domain for dev
2075 * allocate free domain
2076 * allocate page table entries for rmrr
2077 * if context not allocated for bus
2078 * allocate and init context
2079 * set present in root table for this bus
2080 * init context with domain, translation etc
2081 * endfor
2082 * endfor
2083 */
2084 for_each_rmrr_units(rmrr) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002085 for (i = 0; i < rmrr->devices_cnt; i++) {
2086 pdev = rmrr->devices[i];
2087 /* some BIOS lists non-exist devices in DMAR table */
2088 if (!pdev)
2089 continue;
2090 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2091 if (ret)
2092 printk(KERN_ERR
2093 "IOMMU: mapping reserved region failed\n");
2094 }
2095 }
2096
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07002097 iommu_prepare_gfx_mapping();
2098
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002099 iommu_prepare_isa();
2100
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002101 /*
2102 * for each drhd
2103 * enable fault log
2104 * global invalidate context cache
2105 * global invalidate iotlb
2106 * enable translation
2107 */
2108 for_each_drhd_unit(drhd) {
2109 if (drhd->ignored)
2110 continue;
2111 iommu = drhd->iommu;
2112 sprintf (iommu->name, "dmar%d", unit++);
2113
2114 iommu_flush_write_buffer(iommu);
2115
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002116 ret = dmar_set_interrupt(iommu);
2117 if (ret)
2118 goto error;
2119
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002120 iommu_set_root_entry(iommu);
2121
Youquan Songa77b67d2008-10-16 16:31:56 -07002122 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
2123 0);
2124 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
2125 0);
mark grossf8bab732008-02-08 04:18:38 -08002126 iommu_disable_protect_mem_regions(iommu);
2127
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002128 ret = iommu_enable_translation(iommu);
2129 if (ret)
2130 goto error;
2131 }
2132
2133 return 0;
2134error:
2135 for_each_drhd_unit(drhd) {
2136 if (drhd->ignored)
2137 continue;
2138 iommu = drhd->iommu;
2139 free_iommu(iommu);
2140 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002141 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002142 return ret;
2143}
2144
2145static inline u64 aligned_size(u64 host_addr, size_t size)
2146{
2147 u64 addr;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002148 addr = (host_addr & (~PAGE_MASK)) + size;
2149 return PAGE_ALIGN(addr);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002150}
2151
2152struct iova *
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002153iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002154{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002155 struct iova *piova;
2156
2157 /* Make sure it's in range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002158 end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002159 if (!size || (IOVA_START_ADDR + size > end))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002160 return NULL;
2161
2162 piova = alloc_iova(&domain->iovad,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002163 size >> PAGE_SHIFT, IOVA_PFN(end), 1);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002164 return piova;
2165}
2166
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002167static struct iova *
2168__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002169 size_t size, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002170{
2171 struct pci_dev *pdev = to_pci_dev(dev);
2172 struct iova *iova = NULL;
2173
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002174 if (dma_mask <= DMA_32BIT_MASK || dmar_forcedac)
2175 iova = iommu_alloc_iova(domain, size, dma_mask);
2176 else {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002177 /*
2178 * First try to allocate an io virtual address in
2179 * DMA_32BIT_MASK and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002180 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002181 */
2182 iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
2183 if (!iova)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002184 iova = iommu_alloc_iova(domain, size, dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002185 }
2186
2187 if (!iova) {
2188 printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev));
2189 return NULL;
2190 }
2191
2192 return iova;
2193}
2194
2195static struct dmar_domain *
2196get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002197{
2198 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002199 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002200
2201 domain = get_domain_for_dev(pdev,
2202 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2203 if (!domain) {
2204 printk(KERN_ERR
2205 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002206 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002207 }
2208
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002209 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002210 if (unlikely(!domain_context_mapped(pdev))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002211 ret = domain_context_mapping(domain, pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002212 if (ret) {
2213 printk(KERN_ERR
2214 "Domain context map for %s failed",
2215 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002216 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002217 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002218 }
2219
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002220 return domain;
2221}
2222
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002223static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2224 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002225{
2226 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002227 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002228 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002229 struct iova *iova;
2230 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002231 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002232 struct intel_iommu *iommu;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002233
2234 BUG_ON(dir == DMA_NONE);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002235 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002236 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002237
2238 domain = get_valid_domain_for_dev(pdev);
2239 if (!domain)
2240 return 0;
2241
Weidong Han8c11e792008-12-08 15:29:22 +08002242 iommu = domain_get_iommu(domain);
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002243 size = aligned_size((u64)paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002244
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002245 iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002246 if (!iova)
2247 goto error;
2248
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002249 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002250
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002251 /*
2252 * Check if DMAR supports zero-length reads on write only
2253 * mappings..
2254 */
2255 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002256 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002257 prot |= DMA_PTE_READ;
2258 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2259 prot |= DMA_PTE_WRITE;
2260 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002261 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002262 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002263 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002264 * is not a big problem
2265 */
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002266 ret = domain_page_mapping(domain, start_paddr,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002267 ((u64)paddr) & PAGE_MASK, size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002268 if (ret)
2269 goto error;
2270
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002271 /* it's a non-present to present mapping */
Weidong Han8c11e792008-12-08 15:29:22 +08002272 ret = iommu_flush_iotlb_psi(iommu, domain->id,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002273 start_paddr, size >> VTD_PAGE_SHIFT, 1);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002274 if (ret)
Weidong Han8c11e792008-12-08 15:29:22 +08002275 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002276
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002277 return start_paddr + ((u64)paddr & (~PAGE_MASK));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002278
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002279error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002280 if (iova)
2281 __free_iova(&domain->iovad, iova);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002282 printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002283 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002284 return 0;
2285}
2286
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002287dma_addr_t intel_map_single(struct device *hwdev, phys_addr_t paddr,
2288 size_t size, int dir)
2289{
2290 return __intel_map_single(hwdev, paddr, size, dir,
2291 to_pci_dev(hwdev)->dma_mask);
2292}
2293
mark gross5e0d2a62008-03-04 15:22:08 -08002294static void flush_unmaps(void)
2295{
mark gross80b20dd2008-04-18 13:53:58 -07002296 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002297
mark gross5e0d2a62008-03-04 15:22:08 -08002298 timer_on = 0;
2299
2300 /* just flush them all */
2301 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002302 struct intel_iommu *iommu = g_iommus[i];
2303 if (!iommu)
2304 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002305
Weidong Hana2bb8452008-12-08 11:24:12 +08002306 if (deferred_flush[i].next) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002307 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
2308 DMA_TLB_GLOBAL_FLUSH, 0);
mark gross80b20dd2008-04-18 13:53:58 -07002309 for (j = 0; j < deferred_flush[i].next; j++) {
2310 __free_iova(&deferred_flush[i].domain[j]->iovad,
2311 deferred_flush[i].iova[j]);
2312 }
2313 deferred_flush[i].next = 0;
2314 }
mark gross5e0d2a62008-03-04 15:22:08 -08002315 }
2316
mark gross5e0d2a62008-03-04 15:22:08 -08002317 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002318}
2319
2320static void flush_unmaps_timeout(unsigned long data)
2321{
mark gross80b20dd2008-04-18 13:53:58 -07002322 unsigned long flags;
2323
2324 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002325 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002326 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002327}
2328
2329static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2330{
2331 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002332 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002333 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002334
2335 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002336 if (list_size == HIGH_WATER_MARK)
2337 flush_unmaps();
2338
Weidong Han8c11e792008-12-08 15:29:22 +08002339 iommu = domain_get_iommu(dom);
2340 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002341
mark gross80b20dd2008-04-18 13:53:58 -07002342 next = deferred_flush[iommu_id].next;
2343 deferred_flush[iommu_id].domain[next] = dom;
2344 deferred_flush[iommu_id].iova[next] = iova;
2345 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002346
2347 if (!timer_on) {
2348 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2349 timer_on = 1;
2350 }
2351 list_size++;
2352 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2353}
2354
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002355void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
2356 int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002357{
2358 struct pci_dev *pdev = to_pci_dev(dev);
2359 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002360 unsigned long start_addr;
2361 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002362 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002363
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002364 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002365 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002366 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002367 BUG_ON(!domain);
2368
Weidong Han8c11e792008-12-08 15:29:22 +08002369 iommu = domain_get_iommu(domain);
2370
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002371 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
2372 if (!iova)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002373 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002374
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002375 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002376 size = aligned_size((u64)dev_addr, size);
2377
2378 pr_debug("Device %s unmapping: %lx@%llx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002379 pci_name(pdev), size, (unsigned long long)start_addr);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002380
2381 /* clear the whole page */
2382 dma_pte_clear_range(domain, start_addr, start_addr + size);
2383 /* free page tables */
2384 dma_pte_free_pagetable(domain, start_addr, start_addr + size);
mark gross5e0d2a62008-03-04 15:22:08 -08002385 if (intel_iommu_strict) {
Weidong Han8c11e792008-12-08 15:29:22 +08002386 if (iommu_flush_iotlb_psi(iommu,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002387 domain->id, start_addr, size >> VTD_PAGE_SHIFT, 0))
Weidong Han8c11e792008-12-08 15:29:22 +08002388 iommu_flush_write_buffer(iommu);
mark gross5e0d2a62008-03-04 15:22:08 -08002389 /* free iova */
2390 __free_iova(&domain->iovad, iova);
2391 } else {
2392 add_unmap(domain, iova);
2393 /*
2394 * queue up the release of the unmap to save the 1/6th of the
2395 * cpu used up by the iotlb flush operation...
2396 */
mark gross5e0d2a62008-03-04 15:22:08 -08002397 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002398}
2399
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002400void *intel_alloc_coherent(struct device *hwdev, size_t size,
2401 dma_addr_t *dma_handle, gfp_t flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002402{
2403 void *vaddr;
2404 int order;
2405
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002406 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002407 order = get_order(size);
2408 flags &= ~(GFP_DMA | GFP_DMA32);
2409
2410 vaddr = (void *)__get_free_pages(flags, order);
2411 if (!vaddr)
2412 return NULL;
2413 memset(vaddr, 0, size);
2414
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002415 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2416 DMA_BIDIRECTIONAL,
2417 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002418 if (*dma_handle)
2419 return vaddr;
2420 free_pages((unsigned long)vaddr, order);
2421 return NULL;
2422}
2423
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002424void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
2425 dma_addr_t dma_handle)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002426{
2427 int order;
2428
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002429 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002430 order = get_order(size);
2431
2432 intel_unmap_single(hwdev, dma_handle, size, DMA_BIDIRECTIONAL);
2433 free_pages((unsigned long)vaddr, order);
2434}
2435
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002436#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg)))
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002437
2438void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
2439 int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002440{
2441 int i;
2442 struct pci_dev *pdev = to_pci_dev(hwdev);
2443 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002444 unsigned long start_addr;
2445 struct iova *iova;
2446 size_t size = 0;
2447 void *addr;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002448 struct scatterlist *sg;
Weidong Han8c11e792008-12-08 15:29:22 +08002449 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002450
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002451 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002452 return;
2453
2454 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08002455 BUG_ON(!domain);
2456
2457 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002458
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002459 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002460 if (!iova)
2461 return;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002462 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002463 addr = SG_ENT_VIRT_ADDRESS(sg);
2464 size += aligned_size((u64)addr, sg->length);
2465 }
2466
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002467 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002468
2469 /* clear the whole page */
2470 dma_pte_clear_range(domain, start_addr, start_addr + size);
2471 /* free page tables */
2472 dma_pte_free_pagetable(domain, start_addr, start_addr + size);
2473
Weidong Han8c11e792008-12-08 15:29:22 +08002474 if (iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002475 size >> VTD_PAGE_SHIFT, 0))
Weidong Han8c11e792008-12-08 15:29:22 +08002476 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002477
2478 /* free iova */
2479 __free_iova(&domain->iovad, iova);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002480}
2481
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002482static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002483 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002484{
2485 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002486 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002487
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002488 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002489 BUG_ON(!sg_page(sg));
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002490 sg->dma_address = virt_to_bus(SG_ENT_VIRT_ADDRESS(sg));
2491 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002492 }
2493 return nelems;
2494}
2495
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002496int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
2497 int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002498{
2499 void *addr;
2500 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002501 struct pci_dev *pdev = to_pci_dev(hwdev);
2502 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002503 size_t size = 0;
2504 int prot = 0;
2505 size_t offset = 0;
2506 struct iova *iova = NULL;
2507 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002508 struct scatterlist *sg;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002509 unsigned long start_addr;
Weidong Han8c11e792008-12-08 15:29:22 +08002510 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002511
2512 BUG_ON(dir == DMA_NONE);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002513 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002514 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002515
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002516 domain = get_valid_domain_for_dev(pdev);
2517 if (!domain)
2518 return 0;
2519
Weidong Han8c11e792008-12-08 15:29:22 +08002520 iommu = domain_get_iommu(domain);
2521
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002522 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002523 addr = SG_ENT_VIRT_ADDRESS(sg);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002524 addr = (void *)virt_to_phys(addr);
2525 size += aligned_size((u64)addr, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002526 }
2527
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002528 iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002529 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002530 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002531 return 0;
2532 }
2533
2534 /*
2535 * Check if DMAR supports zero-length reads on write only
2536 * mappings..
2537 */
2538 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002539 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002540 prot |= DMA_PTE_READ;
2541 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2542 prot |= DMA_PTE_WRITE;
2543
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002544 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002545 offset = 0;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002546 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002547 addr = SG_ENT_VIRT_ADDRESS(sg);
2548 addr = (void *)virt_to_phys(addr);
2549 size = aligned_size((u64)addr, sg->length);
2550 ret = domain_page_mapping(domain, start_addr + offset,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002551 ((u64)addr) & PAGE_MASK,
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002552 size, prot);
2553 if (ret) {
2554 /* clear the page */
2555 dma_pte_clear_range(domain, start_addr,
2556 start_addr + offset);
2557 /* free page tables */
2558 dma_pte_free_pagetable(domain, start_addr,
2559 start_addr + offset);
2560 /* free iova */
2561 __free_iova(&domain->iovad, iova);
2562 return 0;
2563 }
2564 sg->dma_address = start_addr + offset +
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002565 ((u64)addr & (~PAGE_MASK));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002566 sg->dma_length = sg->length;
2567 offset += size;
2568 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002569
2570 /* it's a non-present to present mapping */
Weidong Han8c11e792008-12-08 15:29:22 +08002571 if (iommu_flush_iotlb_psi(iommu, domain->id,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002572 start_addr, offset >> VTD_PAGE_SHIFT, 1))
Weidong Han8c11e792008-12-08 15:29:22 +08002573 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002574 return nelems;
2575}
2576
2577static struct dma_mapping_ops intel_dma_ops = {
2578 .alloc_coherent = intel_alloc_coherent,
2579 .free_coherent = intel_free_coherent,
2580 .map_single = intel_map_single,
2581 .unmap_single = intel_unmap_single,
2582 .map_sg = intel_map_sg,
2583 .unmap_sg = intel_unmap_sg,
2584};
2585
2586static inline int iommu_domain_cache_init(void)
2587{
2588 int ret = 0;
2589
2590 iommu_domain_cache = kmem_cache_create("iommu_domain",
2591 sizeof(struct dmar_domain),
2592 0,
2593 SLAB_HWCACHE_ALIGN,
2594
2595 NULL);
2596 if (!iommu_domain_cache) {
2597 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
2598 ret = -ENOMEM;
2599 }
2600
2601 return ret;
2602}
2603
2604static inline int iommu_devinfo_cache_init(void)
2605{
2606 int ret = 0;
2607
2608 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
2609 sizeof(struct device_domain_info),
2610 0,
2611 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002612 NULL);
2613 if (!iommu_devinfo_cache) {
2614 printk(KERN_ERR "Couldn't create devinfo cache\n");
2615 ret = -ENOMEM;
2616 }
2617
2618 return ret;
2619}
2620
2621static inline int iommu_iova_cache_init(void)
2622{
2623 int ret = 0;
2624
2625 iommu_iova_cache = kmem_cache_create("iommu_iova",
2626 sizeof(struct iova),
2627 0,
2628 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002629 NULL);
2630 if (!iommu_iova_cache) {
2631 printk(KERN_ERR "Couldn't create iova cache\n");
2632 ret = -ENOMEM;
2633 }
2634
2635 return ret;
2636}
2637
2638static int __init iommu_init_mempool(void)
2639{
2640 int ret;
2641 ret = iommu_iova_cache_init();
2642 if (ret)
2643 return ret;
2644
2645 ret = iommu_domain_cache_init();
2646 if (ret)
2647 goto domain_error;
2648
2649 ret = iommu_devinfo_cache_init();
2650 if (!ret)
2651 return ret;
2652
2653 kmem_cache_destroy(iommu_domain_cache);
2654domain_error:
2655 kmem_cache_destroy(iommu_iova_cache);
2656
2657 return -ENOMEM;
2658}
2659
2660static void __init iommu_exit_mempool(void)
2661{
2662 kmem_cache_destroy(iommu_devinfo_cache);
2663 kmem_cache_destroy(iommu_domain_cache);
2664 kmem_cache_destroy(iommu_iova_cache);
2665
2666}
2667
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002668static void __init init_no_remapping_devices(void)
2669{
2670 struct dmar_drhd_unit *drhd;
2671
2672 for_each_drhd_unit(drhd) {
2673 if (!drhd->include_all) {
2674 int i;
2675 for (i = 0; i < drhd->devices_cnt; i++)
2676 if (drhd->devices[i] != NULL)
2677 break;
2678 /* ignore DMAR unit if no pci devices exist */
2679 if (i == drhd->devices_cnt)
2680 drhd->ignored = 1;
2681 }
2682 }
2683
2684 if (dmar_map_gfx)
2685 return;
2686
2687 for_each_drhd_unit(drhd) {
2688 int i;
2689 if (drhd->ignored || drhd->include_all)
2690 continue;
2691
2692 for (i = 0; i < drhd->devices_cnt; i++)
2693 if (drhd->devices[i] &&
2694 !IS_GFX_DEVICE(drhd->devices[i]))
2695 break;
2696
2697 if (i < drhd->devices_cnt)
2698 continue;
2699
2700 /* bypass IOMMU if it is just for gfx devices */
2701 drhd->ignored = 1;
2702 for (i = 0; i < drhd->devices_cnt; i++) {
2703 if (!drhd->devices[i])
2704 continue;
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002705 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002706 }
2707 }
2708}
2709
2710int __init intel_iommu_init(void)
2711{
2712 int ret = 0;
2713
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002714 if (dmar_table_init())
2715 return -ENODEV;
2716
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002717 if (dmar_dev_scope_init())
2718 return -ENODEV;
2719
Suresh Siddha2ae21012008-07-10 11:16:43 -07002720 /*
2721 * Check the need for DMA-remapping initialization now.
2722 * Above initialization will also be used by Interrupt-remapping.
2723 */
2724 if (no_iommu || swiotlb || dmar_disabled)
2725 return -ENODEV;
2726
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002727 iommu_init_mempool();
2728 dmar_init_reserved_ranges();
2729
2730 init_no_remapping_devices();
2731
2732 ret = init_dmars();
2733 if (ret) {
2734 printk(KERN_ERR "IOMMU: dmar init failed\n");
2735 put_iova_domain(&reserved_iova_list);
2736 iommu_exit_mempool();
2737 return ret;
2738 }
2739 printk(KERN_INFO
2740 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
2741
mark gross5e0d2a62008-03-04 15:22:08 -08002742 init_timer(&unmap_timer);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002743 force_iommu = 1;
2744 dma_ops = &intel_dma_ops;
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01002745
2746 register_iommu(&intel_iommu_ops);
2747
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002748 return 0;
2749}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07002750
Weidong Hanc7151a82008-12-08 22:51:37 +08002751static int vm_domain_add_dev_info(struct dmar_domain *domain,
2752 struct pci_dev *pdev)
2753{
2754 struct device_domain_info *info;
2755 unsigned long flags;
2756
2757 info = alloc_devinfo_mem();
2758 if (!info)
2759 return -ENOMEM;
2760
2761 info->bus = pdev->bus->number;
2762 info->devfn = pdev->devfn;
2763 info->dev = pdev;
2764 info->domain = domain;
2765
2766 spin_lock_irqsave(&device_domain_lock, flags);
2767 list_add(&info->link, &domain->devices);
2768 list_add(&info->global, &device_domain_list);
2769 pdev->dev.archdata.iommu = info;
2770 spin_unlock_irqrestore(&device_domain_lock, flags);
2771
2772 return 0;
2773}
2774
2775static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
2776 struct pci_dev *pdev)
2777{
2778 struct device_domain_info *info;
2779 struct intel_iommu *iommu;
2780 unsigned long flags;
2781 int found = 0;
2782 struct list_head *entry, *tmp;
2783
2784 iommu = device_to_iommu(pdev->bus->number, pdev->devfn);
2785 if (!iommu)
2786 return;
2787
2788 spin_lock_irqsave(&device_domain_lock, flags);
2789 list_for_each_safe(entry, tmp, &domain->devices) {
2790 info = list_entry(entry, struct device_domain_info, link);
2791 if (info->bus == pdev->bus->number &&
2792 info->devfn == pdev->devfn) {
2793 list_del(&info->link);
2794 list_del(&info->global);
2795 if (info->dev)
2796 info->dev->dev.archdata.iommu = NULL;
2797 spin_unlock_irqrestore(&device_domain_lock, flags);
2798
2799 iommu_detach_dev(iommu, info->bus, info->devfn);
2800 free_devinfo_mem(info);
2801
2802 spin_lock_irqsave(&device_domain_lock, flags);
2803
2804 if (found)
2805 break;
2806 else
2807 continue;
2808 }
2809
2810 /* if there is no other devices under the same iommu
2811 * owned by this domain, clear this iommu in iommu_bmp
2812 * update iommu count and coherency
2813 */
2814 if (device_to_iommu(info->bus, info->devfn) == iommu)
2815 found = 1;
2816 }
2817
2818 if (found == 0) {
2819 unsigned long tmp_flags;
2820 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
2821 clear_bit(iommu->seq_id, &domain->iommu_bmp);
2822 domain->iommu_count--;
2823 domain_update_iommu_coherency(domain);
2824 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
2825 }
2826
2827 spin_unlock_irqrestore(&device_domain_lock, flags);
2828}
2829
2830static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
2831{
2832 struct device_domain_info *info;
2833 struct intel_iommu *iommu;
2834 unsigned long flags1, flags2;
2835
2836 spin_lock_irqsave(&device_domain_lock, flags1);
2837 while (!list_empty(&domain->devices)) {
2838 info = list_entry(domain->devices.next,
2839 struct device_domain_info, link);
2840 list_del(&info->link);
2841 list_del(&info->global);
2842 if (info->dev)
2843 info->dev->dev.archdata.iommu = NULL;
2844
2845 spin_unlock_irqrestore(&device_domain_lock, flags1);
2846
2847 iommu = device_to_iommu(info->bus, info->devfn);
2848 iommu_detach_dev(iommu, info->bus, info->devfn);
2849
2850 /* clear this iommu in iommu_bmp, update iommu count
2851 * and coherency
2852 */
2853 spin_lock_irqsave(&domain->iommu_lock, flags2);
2854 if (test_and_clear_bit(iommu->seq_id,
2855 &domain->iommu_bmp)) {
2856 domain->iommu_count--;
2857 domain_update_iommu_coherency(domain);
2858 }
2859 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
2860
2861 free_devinfo_mem(info);
2862 spin_lock_irqsave(&device_domain_lock, flags1);
2863 }
2864 spin_unlock_irqrestore(&device_domain_lock, flags1);
2865}
2866
Weidong Han5e98c4b2008-12-08 23:03:27 +08002867/* domain id for virtual machine, it won't be set in context */
2868static unsigned long vm_domid;
2869
Weidong Hanfe40f1e2008-12-08 23:10:23 +08002870static int vm_domain_min_agaw(struct dmar_domain *domain)
2871{
2872 int i;
2873 int min_agaw = domain->agaw;
2874
2875 i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
2876 for (; i < g_num_of_iommus; ) {
2877 if (min_agaw > g_iommus[i]->agaw)
2878 min_agaw = g_iommus[i]->agaw;
2879
2880 i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
2881 }
2882
2883 return min_agaw;
2884}
2885
Weidong Han5e98c4b2008-12-08 23:03:27 +08002886static struct dmar_domain *iommu_alloc_vm_domain(void)
2887{
2888 struct dmar_domain *domain;
2889
2890 domain = alloc_domain_mem();
2891 if (!domain)
2892 return NULL;
2893
2894 domain->id = vm_domid++;
2895 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
2896 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
2897
2898 return domain;
2899}
2900
2901static int vm_domain_init(struct dmar_domain *domain, int guest_width)
2902{
2903 int adjust_width;
2904
2905 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
2906 spin_lock_init(&domain->mapping_lock);
2907 spin_lock_init(&domain->iommu_lock);
2908
2909 domain_reserve_special_ranges(domain);
2910
2911 /* calculate AGAW */
2912 domain->gaw = guest_width;
2913 adjust_width = guestwidth_to_adjustwidth(guest_width);
2914 domain->agaw = width_to_agaw(adjust_width);
2915
2916 INIT_LIST_HEAD(&domain->devices);
2917
2918 domain->iommu_count = 0;
2919 domain->iommu_coherency = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08002920 domain->max_addr = 0;
Weidong Han5e98c4b2008-12-08 23:03:27 +08002921
2922 /* always allocate the top pgd */
2923 domain->pgd = (struct dma_pte *)alloc_pgtable_page();
2924 if (!domain->pgd)
2925 return -ENOMEM;
2926 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
2927 return 0;
2928}
2929
2930static void iommu_free_vm_domain(struct dmar_domain *domain)
2931{
2932 unsigned long flags;
2933 struct dmar_drhd_unit *drhd;
2934 struct intel_iommu *iommu;
2935 unsigned long i;
2936 unsigned long ndomains;
2937
2938 for_each_drhd_unit(drhd) {
2939 if (drhd->ignored)
2940 continue;
2941 iommu = drhd->iommu;
2942
2943 ndomains = cap_ndoms(iommu->cap);
2944 i = find_first_bit(iommu->domain_ids, ndomains);
2945 for (; i < ndomains; ) {
2946 if (iommu->domains[i] == domain) {
2947 spin_lock_irqsave(&iommu->lock, flags);
2948 clear_bit(i, iommu->domain_ids);
2949 iommu->domains[i] = NULL;
2950 spin_unlock_irqrestore(&iommu->lock, flags);
2951 break;
2952 }
2953 i = find_next_bit(iommu->domain_ids, ndomains, i+1);
2954 }
2955 }
2956}
2957
2958static void vm_domain_exit(struct dmar_domain *domain)
2959{
2960 u64 end;
2961
2962 /* Domain 0 is reserved, so dont process it */
2963 if (!domain)
2964 return;
2965
2966 vm_domain_remove_all_dev_info(domain);
2967 /* destroy iovas */
2968 put_iova_domain(&domain->iovad);
2969 end = DOMAIN_MAX_ADDR(domain->gaw);
2970 end = end & (~VTD_PAGE_MASK);
2971
2972 /* clear ptes */
2973 dma_pte_clear_range(domain, 0, end);
2974
2975 /* free page tables */
2976 dma_pte_free_pagetable(domain, 0, end);
2977
2978 iommu_free_vm_domain(domain);
2979 free_domain_mem(domain);
2980}
2981
Joerg Roedel5d450802008-12-03 14:52:32 +01002982static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03002983{
Joerg Roedel5d450802008-12-03 14:52:32 +01002984 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03002985
Joerg Roedel5d450802008-12-03 14:52:32 +01002986 dmar_domain = iommu_alloc_vm_domain();
2987 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03002988 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01002989 "intel_iommu_domain_init: dmar_domain == NULL\n");
2990 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03002991 }
Joerg Roedel5d450802008-12-03 14:52:32 +01002992 if (vm_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03002993 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01002994 "intel_iommu_domain_init() failed\n");
2995 vm_domain_exit(dmar_domain);
2996 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03002997 }
Joerg Roedel5d450802008-12-03 14:52:32 +01002998 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08002999
Joerg Roedel5d450802008-12-03 14:52:32 +01003000 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003001}
Kay, Allen M38717942008-09-09 18:37:29 +03003002
Joerg Roedel5d450802008-12-03 14:52:32 +01003003static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003004{
Joerg Roedel5d450802008-12-03 14:52:32 +01003005 struct dmar_domain *dmar_domain = domain->priv;
3006
3007 domain->priv = NULL;
3008 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003009}
Kay, Allen M38717942008-09-09 18:37:29 +03003010
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003011static int intel_iommu_attach_device(struct iommu_domain *domain,
3012 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003013{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003014 struct dmar_domain *dmar_domain = domain->priv;
3015 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003016 struct intel_iommu *iommu;
3017 int addr_width;
3018 u64 end;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003019 int ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003020
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003021 /* normally pdev is not mapped */
3022 if (unlikely(domain_context_mapped(pdev))) {
3023 struct dmar_domain *old_domain;
3024
3025 old_domain = find_domain(pdev);
3026 if (old_domain) {
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003027 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003028 vm_domain_remove_one_dev_info(old_domain, pdev);
3029 else
3030 domain_remove_dev_info(old_domain);
3031 }
3032 }
3033
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003034 iommu = device_to_iommu(pdev->bus->number, pdev->devfn);
3035 if (!iommu)
3036 return -ENODEV;
3037
3038 /* check if this iommu agaw is sufficient for max mapped address */
3039 addr_width = agaw_to_width(iommu->agaw);
3040 end = DOMAIN_MAX_ADDR(addr_width);
3041 end = end & VTD_PAGE_MASK;
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003042 if (end < dmar_domain->max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003043 printk(KERN_ERR "%s: iommu agaw (%d) is not "
3044 "sufficient for the mapped address (%llx)\n",
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003045 __func__, iommu->agaw, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003046 return -EFAULT;
3047 }
3048
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003049 ret = domain_context_mapping(dmar_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003050 if (ret)
3051 return ret;
3052
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003053 ret = vm_domain_add_dev_info(dmar_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003054 return ret;
3055}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003056
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003057static void intel_iommu_detach_device(struct iommu_domain *domain,
3058 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003059{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003060 struct dmar_domain *dmar_domain = domain->priv;
3061 struct pci_dev *pdev = to_pci_dev(dev);
3062
3063 vm_domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003064}
Kay, Allen M38717942008-09-09 18:37:29 +03003065
Joerg Roedeldde57a22008-12-03 15:04:09 +01003066static int intel_iommu_map_range(struct iommu_domain *domain,
3067 unsigned long iova, phys_addr_t hpa,
3068 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003069{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003070 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003071 u64 max_addr;
3072 int addr_width;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003073 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003074 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003075
Joerg Roedeldde57a22008-12-03 15:04:09 +01003076 if (iommu_prot & IOMMU_READ)
3077 prot |= DMA_PTE_READ;
3078 if (iommu_prot & IOMMU_WRITE)
3079 prot |= DMA_PTE_WRITE;
3080
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003081 max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size);
Joerg Roedeldde57a22008-12-03 15:04:09 +01003082 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003083 int min_agaw;
3084 u64 end;
3085
3086 /* check if minimum agaw is sufficient for mapped address */
Joerg Roedeldde57a22008-12-03 15:04:09 +01003087 min_agaw = vm_domain_min_agaw(dmar_domain);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003088 addr_width = agaw_to_width(min_agaw);
3089 end = DOMAIN_MAX_ADDR(addr_width);
3090 end = end & VTD_PAGE_MASK;
3091 if (end < max_addr) {
3092 printk(KERN_ERR "%s: iommu agaw (%d) is not "
3093 "sufficient for the mapped address (%llx)\n",
3094 __func__, min_agaw, max_addr);
3095 return -EFAULT;
3096 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003097 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003098 }
3099
Joerg Roedeldde57a22008-12-03 15:04:09 +01003100 ret = domain_page_mapping(dmar_domain, iova, hpa, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003101 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003102}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003103
Joerg Roedeldde57a22008-12-03 15:04:09 +01003104static void intel_iommu_unmap_range(struct iommu_domain *domain,
3105 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003106{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003107 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003108 dma_addr_t base;
3109
3110 /* The address might not be aligned */
3111 base = iova & VTD_PAGE_MASK;
3112 size = VTD_PAGE_ALIGN(size);
Joerg Roedeldde57a22008-12-03 15:04:09 +01003113 dma_pte_clear_range(dmar_domain, base, base + size);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003114
Joerg Roedeldde57a22008-12-03 15:04:09 +01003115 if (dmar_domain->max_addr == base + size)
3116 dmar_domain->max_addr = base;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003117}
Kay, Allen M38717942008-09-09 18:37:29 +03003118
Joerg Roedeld14d6572008-12-03 15:06:57 +01003119static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
3120 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03003121{
Joerg Roedeld14d6572008-12-03 15:06:57 +01003122 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03003123 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003124 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003125
Joerg Roedeld14d6572008-12-03 15:06:57 +01003126 pte = addr_to_dma_pte(dmar_domain, iova);
Kay, Allen M38717942008-09-09 18:37:29 +03003127 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003128 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03003129
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003130 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03003131}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003132
3133static struct iommu_ops intel_iommu_ops = {
3134 .domain_init = intel_iommu_domain_init,
3135 .domain_destroy = intel_iommu_domain_destroy,
3136 .attach_dev = intel_iommu_attach_device,
3137 .detach_dev = intel_iommu_detach_device,
3138 .map = intel_iommu_map_range,
3139 .unmap = intel_iommu_unmap_range,
3140 .iova_to_phys = intel_iommu_iova_to_phys,
3141};
David Woodhouse9af88142009-02-13 23:18:03 +00003142
3143static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
3144{
3145 /*
3146 * Mobile 4 Series Chipset neglects to set RWBF capability,
3147 * but needs it:
3148 */
3149 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
3150 rwbf_quirk = 1;
3151}
3152
3153DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);