blob: be999ff025af98687c5e60ef5cf56d9a68065bce [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 */
Sheng Yang58c610b2009-03-18 15:33:05 +0800234 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800235 int iommu_count; /* reference count of iommu */
236 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800237 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000238};
239
Mark McLoughlina647dac2008-11-20 15:49:48 +0000240/* PCI domain-device relationship */
241struct device_domain_info {
242 struct list_head link; /* link to domain siblings */
243 struct list_head global; /* link to global list */
244 u8 bus; /* PCI bus numer */
245 u8 devfn; /* PCI devfn number */
246 struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
247 struct dmar_domain *domain; /* pointer to domain */
248};
249
mark gross5e0d2a62008-03-04 15:22:08 -0800250static void flush_unmaps_timeout(unsigned long data);
251
252DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
253
mark gross80b20dd2008-04-18 13:53:58 -0700254#define HIGH_WATER_MARK 250
255struct deferred_flush_tables {
256 int next;
257 struct iova *iova[HIGH_WATER_MARK];
258 struct dmar_domain *domain[HIGH_WATER_MARK];
259};
260
261static struct deferred_flush_tables *deferred_flush;
262
mark gross5e0d2a62008-03-04 15:22:08 -0800263/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800264static int g_num_of_iommus;
265
266static DEFINE_SPINLOCK(async_umap_flush_lock);
267static LIST_HEAD(unmaps_to_do);
268
269static int timer_on;
270static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800271
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700272static void domain_remove_dev_info(struct dmar_domain *domain);
273
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800274#ifdef CONFIG_DMAR_DEFAULT_ON
275int dmar_disabled = 0;
276#else
277int dmar_disabled = 1;
278#endif /*CONFIG_DMAR_DEFAULT_ON*/
279
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700280static int __initdata dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700281static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800282static int intel_iommu_strict;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700283
284#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
285static DEFINE_SPINLOCK(device_domain_lock);
286static LIST_HEAD(device_domain_list);
287
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100288static struct iommu_ops intel_iommu_ops;
289
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700290static int __init intel_iommu_setup(char *str)
291{
292 if (!str)
293 return -EINVAL;
294 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800295 if (!strncmp(str, "on", 2)) {
296 dmar_disabled = 0;
297 printk(KERN_INFO "Intel-IOMMU: enabled\n");
298 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700299 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800300 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700301 } else if (!strncmp(str, "igfx_off", 8)) {
302 dmar_map_gfx = 0;
303 printk(KERN_INFO
304 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700305 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800306 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700307 "Intel-IOMMU: Forcing DAC for PCI devices\n");
308 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800309 } else if (!strncmp(str, "strict", 6)) {
310 printk(KERN_INFO
311 "Intel-IOMMU: disable batched IOTLB flush\n");
312 intel_iommu_strict = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700313 }
314
315 str += strcspn(str, ",");
316 while (*str == ',')
317 str++;
318 }
319 return 0;
320}
321__setup("intel_iommu=", intel_iommu_setup);
322
323static struct kmem_cache *iommu_domain_cache;
324static struct kmem_cache *iommu_devinfo_cache;
325static struct kmem_cache *iommu_iova_cache;
326
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700327static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep)
328{
329 unsigned int flags;
330 void *vaddr;
331
332 /* trying to avoid low memory issues */
333 flags = current->flags & PF_MEMALLOC;
334 current->flags |= PF_MEMALLOC;
335 vaddr = kmem_cache_alloc(cachep, GFP_ATOMIC);
336 current->flags &= (~PF_MEMALLOC | flags);
337 return vaddr;
338}
339
340
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700341static inline void *alloc_pgtable_page(void)
342{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700343 unsigned int flags;
344 void *vaddr;
345
346 /* trying to avoid low memory issues */
347 flags = current->flags & PF_MEMALLOC;
348 current->flags |= PF_MEMALLOC;
349 vaddr = (void *)get_zeroed_page(GFP_ATOMIC);
350 current->flags &= (~PF_MEMALLOC | flags);
351 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700352}
353
354static inline void free_pgtable_page(void *vaddr)
355{
356 free_page((unsigned long)vaddr);
357}
358
359static inline void *alloc_domain_mem(void)
360{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700361 return iommu_kmem_cache_alloc(iommu_domain_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700362}
363
Kay, Allen M38717942008-09-09 18:37:29 +0300364static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700365{
366 kmem_cache_free(iommu_domain_cache, vaddr);
367}
368
369static inline void * alloc_devinfo_mem(void)
370{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700371 return iommu_kmem_cache_alloc(iommu_devinfo_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700372}
373
374static inline void free_devinfo_mem(void *vaddr)
375{
376 kmem_cache_free(iommu_devinfo_cache, vaddr);
377}
378
379struct iova *alloc_iova_mem(void)
380{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700381 return iommu_kmem_cache_alloc(iommu_iova_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700382}
383
384void free_iova_mem(struct iova *iova)
385{
386 kmem_cache_free(iommu_iova_cache, iova);
387}
388
Weidong Han1b573682008-12-08 15:34:06 +0800389
390static inline int width_to_agaw(int width);
391
392/* calculate agaw for each iommu.
393 * "SAGAW" may be different across iommus, use a default agaw, and
394 * get a supported less agaw for iommus that don't support the default agaw.
395 */
396int iommu_calculate_agaw(struct intel_iommu *iommu)
397{
398 unsigned long sagaw;
399 int agaw = -1;
400
401 sagaw = cap_sagaw(iommu->cap);
402 for (agaw = width_to_agaw(DEFAULT_DOMAIN_ADDRESS_WIDTH);
403 agaw >= 0; agaw--) {
404 if (test_bit(agaw, &sagaw))
405 break;
406 }
407
408 return agaw;
409}
410
Weidong Han8c11e792008-12-08 15:29:22 +0800411/* in native case, each domain is related to only one iommu */
412static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
413{
414 int iommu_id;
415
Weidong Han1ce28fe2008-12-08 16:35:39 +0800416 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
417
Weidong Han8c11e792008-12-08 15:29:22 +0800418 iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
419 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
420 return NULL;
421
422 return g_iommus[iommu_id];
423}
424
Weidong Han8e6040972008-12-08 15:49:06 +0800425static 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
Sheng Yang58c610b2009-03-18 15:33:05 +0800441static void domain_update_iommu_snooping(struct dmar_domain *domain)
442{
443 int i;
444
445 domain->iommu_snooping = 1;
446
447 i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
448 for (; i < g_num_of_iommus; ) {
449 if (!ecap_sc_support(g_iommus[i]->ecap)) {
450 domain->iommu_snooping = 0;
451 break;
452 }
453 i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
454 }
455}
456
457/* Some capabilities may be different across iommus */
458static void domain_update_iommu_cap(struct dmar_domain *domain)
459{
460 domain_update_iommu_coherency(domain);
461 domain_update_iommu_snooping(domain);
462}
463
Weidong Hanc7151a82008-12-08 22:51:37 +0800464static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn)
465{
466 struct dmar_drhd_unit *drhd = NULL;
467 int i;
468
469 for_each_drhd_unit(drhd) {
470 if (drhd->ignored)
471 continue;
472
473 for (i = 0; i < drhd->devices_cnt; i++)
Dirk Hohndel288e4872009-01-11 15:33:51 +0000474 if (drhd->devices[i] &&
475 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800476 drhd->devices[i]->devfn == devfn)
477 return drhd->iommu;
478
479 if (drhd->include_all)
480 return drhd->iommu;
481 }
482
483 return NULL;
484}
485
Weidong Han5331fe62008-12-08 23:00:00 +0800486static void domain_flush_cache(struct dmar_domain *domain,
487 void *addr, int size)
488{
489 if (!domain->iommu_coherency)
490 clflush_cache_range(addr, size);
491}
492
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700493/* Gets context entry for a given bus and devfn */
494static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
495 u8 bus, u8 devfn)
496{
497 struct root_entry *root;
498 struct context_entry *context;
499 unsigned long phy_addr;
500 unsigned long flags;
501
502 spin_lock_irqsave(&iommu->lock, flags);
503 root = &iommu->root_entry[bus];
504 context = get_context_addr_from_root(root);
505 if (!context) {
506 context = (struct context_entry *)alloc_pgtable_page();
507 if (!context) {
508 spin_unlock_irqrestore(&iommu->lock, flags);
509 return NULL;
510 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700511 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700512 phy_addr = virt_to_phys((void *)context);
513 set_root_value(root, phy_addr);
514 set_root_present(root);
515 __iommu_flush_cache(iommu, root, sizeof(*root));
516 }
517 spin_unlock_irqrestore(&iommu->lock, flags);
518 return &context[devfn];
519}
520
521static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
522{
523 struct root_entry *root;
524 struct context_entry *context;
525 int ret;
526 unsigned long flags;
527
528 spin_lock_irqsave(&iommu->lock, flags);
529 root = &iommu->root_entry[bus];
530 context = get_context_addr_from_root(root);
531 if (!context) {
532 ret = 0;
533 goto out;
534 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000535 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700536out:
537 spin_unlock_irqrestore(&iommu->lock, flags);
538 return ret;
539}
540
541static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
542{
543 struct root_entry *root;
544 struct context_entry *context;
545 unsigned long flags;
546
547 spin_lock_irqsave(&iommu->lock, flags);
548 root = &iommu->root_entry[bus];
549 context = get_context_addr_from_root(root);
550 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000551 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700552 __iommu_flush_cache(iommu, &context[devfn], \
553 sizeof(*context));
554 }
555 spin_unlock_irqrestore(&iommu->lock, flags);
556}
557
558static void free_context_table(struct intel_iommu *iommu)
559{
560 struct root_entry *root;
561 int i;
562 unsigned long flags;
563 struct context_entry *context;
564
565 spin_lock_irqsave(&iommu->lock, flags);
566 if (!iommu->root_entry) {
567 goto out;
568 }
569 for (i = 0; i < ROOT_ENTRY_NR; i++) {
570 root = &iommu->root_entry[i];
571 context = get_context_addr_from_root(root);
572 if (context)
573 free_pgtable_page(context);
574 }
575 free_pgtable_page(iommu->root_entry);
576 iommu->root_entry = NULL;
577out:
578 spin_unlock_irqrestore(&iommu->lock, flags);
579}
580
581/* page table handling */
582#define LEVEL_STRIDE (9)
583#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
584
585static inline int agaw_to_level(int agaw)
586{
587 return agaw + 2;
588}
589
590static inline int agaw_to_width(int agaw)
591{
592 return 30 + agaw * LEVEL_STRIDE;
593
594}
595
596static inline int width_to_agaw(int width)
597{
598 return (width - 30) / LEVEL_STRIDE;
599}
600
601static inline unsigned int level_to_offset_bits(int level)
602{
603 return (12 + (level - 1) * LEVEL_STRIDE);
604}
605
606static inline int address_level_offset(u64 addr, int level)
607{
608 return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK);
609}
610
611static inline u64 level_mask(int level)
612{
613 return ((u64)-1 << level_to_offset_bits(level));
614}
615
616static inline u64 level_size(int level)
617{
618 return ((u64)1 << level_to_offset_bits(level));
619}
620
621static inline u64 align_to_level(u64 addr, int level)
622{
623 return ((addr + level_size(level) - 1) & level_mask(level));
624}
625
626static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
627{
628 int addr_width = agaw_to_width(domain->agaw);
629 struct dma_pte *parent, *pte = NULL;
630 int level = agaw_to_level(domain->agaw);
631 int offset;
632 unsigned long flags;
633
634 BUG_ON(!domain->pgd);
635
636 addr &= (((u64)1) << addr_width) - 1;
637 parent = domain->pgd;
638
639 spin_lock_irqsave(&domain->mapping_lock, flags);
640 while (level > 0) {
641 void *tmp_page;
642
643 offset = address_level_offset(addr, level);
644 pte = &parent[offset];
645 if (level == 1)
646 break;
647
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000648 if (!dma_pte_present(pte)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700649 tmp_page = alloc_pgtable_page();
650
651 if (!tmp_page) {
652 spin_unlock_irqrestore(&domain->mapping_lock,
653 flags);
654 return NULL;
655 }
Weidong Han5331fe62008-12-08 23:00:00 +0800656 domain_flush_cache(domain, tmp_page, PAGE_SIZE);
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000657 dma_set_pte_addr(pte, virt_to_phys(tmp_page));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700658 /*
659 * high level table always sets r/w, last level page
660 * table control read/write
661 */
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000662 dma_set_pte_readable(pte);
663 dma_set_pte_writable(pte);
Weidong Han5331fe62008-12-08 23:00:00 +0800664 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700665 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000666 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700667 level--;
668 }
669
670 spin_unlock_irqrestore(&domain->mapping_lock, flags);
671 return pte;
672}
673
674/* return address's pte at specific level */
675static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
676 int level)
677{
678 struct dma_pte *parent, *pte = NULL;
679 int total = agaw_to_level(domain->agaw);
680 int offset;
681
682 parent = domain->pgd;
683 while (level <= total) {
684 offset = address_level_offset(addr, total);
685 pte = &parent[offset];
686 if (level == total)
687 return pte;
688
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000689 if (!dma_pte_present(pte))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700690 break;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000691 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700692 total--;
693 }
694 return NULL;
695}
696
697/* clear one page's page table */
698static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
699{
700 struct dma_pte *pte = NULL;
701
702 /* get last level pte */
703 pte = dma_addr_level_pte(domain, addr, 1);
704
705 if (pte) {
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000706 dma_clear_pte(pte);
Weidong Han5331fe62008-12-08 23:00:00 +0800707 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700708 }
709}
710
711/* clear last level pte, a tlb flush should be followed */
712static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
713{
714 int addr_width = agaw_to_width(domain->agaw);
715
716 start &= (((u64)1) << addr_width) - 1;
717 end &= (((u64)1) << addr_width) - 1;
718 /* in case it's partial page */
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700719 start = PAGE_ALIGN(start);
720 end &= PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700721
722 /* we don't need lock here, nobody else touches the iova range */
723 while (start < end) {
724 dma_pte_clear_one(domain, start);
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700725 start += VTD_PAGE_SIZE;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700726 }
727}
728
729/* free page table pages. last level pte should already be cleared */
730static void dma_pte_free_pagetable(struct dmar_domain *domain,
731 u64 start, u64 end)
732{
733 int addr_width = agaw_to_width(domain->agaw);
734 struct dma_pte *pte;
735 int total = agaw_to_level(domain->agaw);
736 int level;
737 u64 tmp;
738
739 start &= (((u64)1) << addr_width) - 1;
740 end &= (((u64)1) << addr_width) - 1;
741
742 /* we don't need lock here, nobody else touches the iova range */
743 level = 2;
744 while (level <= total) {
745 tmp = align_to_level(start, level);
746 if (tmp >= end || (tmp + level_size(level) > end))
747 return;
748
749 while (tmp < end) {
750 pte = dma_addr_level_pte(domain, tmp, level);
751 if (pte) {
752 free_pgtable_page(
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000753 phys_to_virt(dma_pte_addr(pte)));
754 dma_clear_pte(pte);
Weidong Han5331fe62008-12-08 23:00:00 +0800755 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700756 }
757 tmp += level_size(level);
758 }
759 level++;
760 }
761 /* free pgd */
762 if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
763 free_pgtable_page(domain->pgd);
764 domain->pgd = NULL;
765 }
766}
767
768/* iommu handling */
769static int iommu_alloc_root_entry(struct intel_iommu *iommu)
770{
771 struct root_entry *root;
772 unsigned long flags;
773
774 root = (struct root_entry *)alloc_pgtable_page();
775 if (!root)
776 return -ENOMEM;
777
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700778 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700779
780 spin_lock_irqsave(&iommu->lock, flags);
781 iommu->root_entry = root;
782 spin_unlock_irqrestore(&iommu->lock, flags);
783
784 return 0;
785}
786
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700787static void iommu_set_root_entry(struct intel_iommu *iommu)
788{
789 void *addr;
790 u32 cmd, sts;
791 unsigned long flag;
792
793 addr = iommu->root_entry;
794
795 spin_lock_irqsave(&iommu->register_lock, flag);
796 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
797
798 cmd = iommu->gcmd | DMA_GCMD_SRTP;
799 writel(cmd, iommu->reg + DMAR_GCMD_REG);
800
801 /* Make sure hardware complete it */
802 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
803 readl, (sts & DMA_GSTS_RTPS), sts);
804
805 spin_unlock_irqrestore(&iommu->register_lock, flag);
806}
807
808static void iommu_flush_write_buffer(struct intel_iommu *iommu)
809{
810 u32 val;
811 unsigned long flag;
812
David Woodhouse9af88142009-02-13 23:18:03 +0000813 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700814 return;
815 val = iommu->gcmd | DMA_GCMD_WBF;
816
817 spin_lock_irqsave(&iommu->register_lock, flag);
818 writel(val, iommu->reg + DMAR_GCMD_REG);
819
820 /* Make sure hardware complete it */
821 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
822 readl, (!(val & DMA_GSTS_WBFS)), val);
823
824 spin_unlock_irqrestore(&iommu->register_lock, flag);
825}
826
827/* return value determine if we need a write buffer flush */
828static int __iommu_flush_context(struct intel_iommu *iommu,
829 u16 did, u16 source_id, u8 function_mask, u64 type,
830 int non_present_entry_flush)
831{
832 u64 val = 0;
833 unsigned long flag;
834
835 /*
836 * In the non-present entry flush case, if hardware doesn't cache
837 * non-present entry we do nothing and if hardware cache non-present
838 * entry, we flush entries of domain 0 (the domain id is used to cache
839 * any non-present entries)
840 */
841 if (non_present_entry_flush) {
842 if (!cap_caching_mode(iommu->cap))
843 return 1;
844 else
845 did = 0;
846 }
847
848 switch (type) {
849 case DMA_CCMD_GLOBAL_INVL:
850 val = DMA_CCMD_GLOBAL_INVL;
851 break;
852 case DMA_CCMD_DOMAIN_INVL:
853 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
854 break;
855 case DMA_CCMD_DEVICE_INVL:
856 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
857 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
858 break;
859 default:
860 BUG();
861 }
862 val |= DMA_CCMD_ICC;
863
864 spin_lock_irqsave(&iommu->register_lock, flag);
865 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
866
867 /* Make sure hardware complete it */
868 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
869 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
870
871 spin_unlock_irqrestore(&iommu->register_lock, flag);
872
Ameya Palande4d235ba2008-10-18 20:27:30 -0700873 /* flush context entry will implicitly flush write buffer */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700874 return 0;
875}
876
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700877/* return value determine if we need a write buffer flush */
878static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
879 u64 addr, unsigned int size_order, u64 type,
880 int non_present_entry_flush)
881{
882 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
883 u64 val = 0, val_iva = 0;
884 unsigned long flag;
885
886 /*
887 * In the non-present entry flush case, if hardware doesn't cache
888 * non-present entry we do nothing and if hardware cache non-present
889 * entry, we flush entries of domain 0 (the domain id is used to cache
890 * any non-present entries)
891 */
892 if (non_present_entry_flush) {
893 if (!cap_caching_mode(iommu->cap))
894 return 1;
895 else
896 did = 0;
897 }
898
899 switch (type) {
900 case DMA_TLB_GLOBAL_FLUSH:
901 /* global flush doesn't need set IVA_REG */
902 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
903 break;
904 case DMA_TLB_DSI_FLUSH:
905 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
906 break;
907 case DMA_TLB_PSI_FLUSH:
908 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
909 /* Note: always flush non-leaf currently */
910 val_iva = size_order | addr;
911 break;
912 default:
913 BUG();
914 }
915 /* Note: set drain read/write */
916#if 0
917 /*
918 * This is probably to be super secure.. Looks like we can
919 * ignore it without any impact.
920 */
921 if (cap_read_drain(iommu->cap))
922 val |= DMA_TLB_READ_DRAIN;
923#endif
924 if (cap_write_drain(iommu->cap))
925 val |= DMA_TLB_WRITE_DRAIN;
926
927 spin_lock_irqsave(&iommu->register_lock, flag);
928 /* Note: Only uses first TLB reg currently */
929 if (val_iva)
930 dmar_writeq(iommu->reg + tlb_offset, val_iva);
931 dmar_writeq(iommu->reg + tlb_offset + 8, val);
932
933 /* Make sure hardware complete it */
934 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
935 dmar_readq, (!(val & DMA_TLB_IVT)), val);
936
937 spin_unlock_irqrestore(&iommu->register_lock, flag);
938
939 /* check IOTLB invalidation granularity */
940 if (DMA_TLB_IAIG(val) == 0)
941 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
942 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
943 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700944 (unsigned long long)DMA_TLB_IIRG(type),
945 (unsigned long long)DMA_TLB_IAIG(val));
Ameya Palande4d235ba2008-10-18 20:27:30 -0700946 /* flush iotlb entry will implicitly flush write buffer */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700947 return 0;
948}
949
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700950static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
951 u64 addr, unsigned int pages, int non_present_entry_flush)
952{
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700953 unsigned int mask;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700954
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700955 BUG_ON(addr & (~VTD_PAGE_MASK));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700956 BUG_ON(pages == 0);
957
958 /* Fallback to domain selective flush if no PSI support */
959 if (!cap_pgsel_inv(iommu->cap))
Youquan Songa77b67d2008-10-16 16:31:56 -0700960 return iommu->flush.flush_iotlb(iommu, did, 0, 0,
961 DMA_TLB_DSI_FLUSH,
962 non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700963
964 /*
965 * PSI requires page size to be 2 ^ x, and the base address is naturally
966 * aligned to the size
967 */
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700968 mask = ilog2(__roundup_pow_of_two(pages));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700969 /* Fallback to domain selective flush if size is too big */
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -0700970 if (mask > cap_max_amask_val(iommu->cap))
Youquan Songa77b67d2008-10-16 16:31:56 -0700971 return iommu->flush.flush_iotlb(iommu, did, 0, 0,
972 DMA_TLB_DSI_FLUSH, non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700973
Youquan Songa77b67d2008-10-16 16:31:56 -0700974 return iommu->flush.flush_iotlb(iommu, did, addr, mask,
975 DMA_TLB_PSI_FLUSH,
976 non_present_entry_flush);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700977}
978
mark grossf8bab732008-02-08 04:18:38 -0800979static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
980{
981 u32 pmen;
982 unsigned long flags;
983
984 spin_lock_irqsave(&iommu->register_lock, flags);
985 pmen = readl(iommu->reg + DMAR_PMEN_REG);
986 pmen &= ~DMA_PMEN_EPM;
987 writel(pmen, iommu->reg + DMAR_PMEN_REG);
988
989 /* wait for the protected region status bit to clear */
990 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
991 readl, !(pmen & DMA_PMEN_PRS), pmen);
992
993 spin_unlock_irqrestore(&iommu->register_lock, flags);
994}
995
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700996static int iommu_enable_translation(struct intel_iommu *iommu)
997{
998 u32 sts;
999 unsigned long flags;
1000
1001 spin_lock_irqsave(&iommu->register_lock, flags);
1002 writel(iommu->gcmd|DMA_GCMD_TE, iommu->reg + DMAR_GCMD_REG);
1003
1004 /* Make sure hardware complete it */
1005 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
1006 readl, (sts & DMA_GSTS_TES), sts);
1007
1008 iommu->gcmd |= DMA_GCMD_TE;
1009 spin_unlock_irqrestore(&iommu->register_lock, flags);
1010 return 0;
1011}
1012
1013static int iommu_disable_translation(struct intel_iommu *iommu)
1014{
1015 u32 sts;
1016 unsigned long flag;
1017
1018 spin_lock_irqsave(&iommu->register_lock, flag);
1019 iommu->gcmd &= ~DMA_GCMD_TE;
1020 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1021
1022 /* Make sure hardware complete it */
1023 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
1024 readl, (!(sts & DMA_GSTS_TES)), sts);
1025
1026 spin_unlock_irqrestore(&iommu->register_lock, flag);
1027 return 0;
1028}
1029
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001030/* iommu interrupt handling. Most stuff are MSI-like. */
1031
mark grossd94afc62008-02-08 04:18:39 -08001032static const char *fault_reason_strings[] =
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001033{
1034 "Software",
1035 "Present bit in root entry is clear",
1036 "Present bit in context entry is clear",
1037 "Invalid context entry",
1038 "Access beyond MGAW",
1039 "PTE Write access is not set",
1040 "PTE Read access is not set",
1041 "Next page table ptr is invalid",
1042 "Root table address invalid",
1043 "Context table ptr is invalid",
1044 "non-zero reserved fields in RTP",
1045 "non-zero reserved fields in CTP",
1046 "non-zero reserved fields in PTE",
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001047};
mark grossf8bab732008-02-08 04:18:38 -08001048#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001049
mark grossd94afc62008-02-08 04:18:39 -08001050const char *dmar_get_fault_reason(u8 fault_reason)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001051{
mark grossd94afc62008-02-08 04:18:39 -08001052 if (fault_reason > MAX_FAULT_REASON_IDX)
1053 return "Unknown";
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001054 else
1055 return fault_reason_strings[fault_reason];
1056}
1057
1058void dmar_msi_unmask(unsigned int irq)
1059{
1060 struct intel_iommu *iommu = get_irq_data(irq);
1061 unsigned long flag;
1062
1063 /* unmask it */
1064 spin_lock_irqsave(&iommu->register_lock, flag);
1065 writel(0, iommu->reg + DMAR_FECTL_REG);
1066 /* Read a reg to force flush the post write */
1067 readl(iommu->reg + DMAR_FECTL_REG);
1068 spin_unlock_irqrestore(&iommu->register_lock, flag);
1069}
1070
1071void dmar_msi_mask(unsigned int irq)
1072{
1073 unsigned long flag;
1074 struct intel_iommu *iommu = get_irq_data(irq);
1075
1076 /* mask it */
1077 spin_lock_irqsave(&iommu->register_lock, flag);
1078 writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
1079 /* Read a reg to force flush the post write */
1080 readl(iommu->reg + DMAR_FECTL_REG);
1081 spin_unlock_irqrestore(&iommu->register_lock, flag);
1082}
1083
1084void dmar_msi_write(int irq, struct msi_msg *msg)
1085{
1086 struct intel_iommu *iommu = get_irq_data(irq);
1087 unsigned long flag;
1088
1089 spin_lock_irqsave(&iommu->register_lock, flag);
1090 writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
1091 writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
1092 writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
1093 spin_unlock_irqrestore(&iommu->register_lock, flag);
1094}
1095
1096void dmar_msi_read(int irq, struct msi_msg *msg)
1097{
1098 struct intel_iommu *iommu = get_irq_data(irq);
1099 unsigned long flag;
1100
1101 spin_lock_irqsave(&iommu->register_lock, flag);
1102 msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
1103 msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
1104 msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
1105 spin_unlock_irqrestore(&iommu->register_lock, flag);
1106}
1107
1108static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001109 u8 fault_reason, u16 source_id, unsigned long long addr)
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001110{
mark grossd94afc62008-02-08 04:18:39 -08001111 const char *reason;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001112
1113 reason = dmar_get_fault_reason(fault_reason);
1114
1115 printk(KERN_ERR
1116 "DMAR:[%s] Request device [%02x:%02x.%d] "
1117 "fault addr %llx \n"
1118 "DMAR:[fault reason %02d] %s\n",
1119 (type ? "DMA Read" : "DMA Write"),
1120 (source_id >> 8), PCI_SLOT(source_id & 0xFF),
1121 PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
1122 return 0;
1123}
1124
1125#define PRIMARY_FAULT_REG_LEN (16)
1126static irqreturn_t iommu_page_fault(int irq, void *dev_id)
1127{
1128 struct intel_iommu *iommu = dev_id;
1129 int reg, fault_index;
1130 u32 fault_status;
1131 unsigned long flag;
1132
1133 spin_lock_irqsave(&iommu->register_lock, flag);
1134 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
1135
1136 /* TBD: ignore advanced fault log currently */
1137 if (!(fault_status & DMA_FSTS_PPF))
1138 goto clear_overflow;
1139
1140 fault_index = dma_fsts_fault_record_index(fault_status);
1141 reg = cap_fault_reg_offset(iommu->cap);
1142 while (1) {
1143 u8 fault_reason;
1144 u16 source_id;
1145 u64 guest_addr;
1146 int type;
1147 u32 data;
1148
1149 /* highest 32 bits */
1150 data = readl(iommu->reg + reg +
1151 fault_index * PRIMARY_FAULT_REG_LEN + 12);
1152 if (!(data & DMA_FRCD_F))
1153 break;
1154
1155 fault_reason = dma_frcd_fault_reason(data);
1156 type = dma_frcd_type(data);
1157
1158 data = readl(iommu->reg + reg +
1159 fault_index * PRIMARY_FAULT_REG_LEN + 8);
1160 source_id = dma_frcd_source_id(data);
1161
1162 guest_addr = dmar_readq(iommu->reg + reg +
1163 fault_index * PRIMARY_FAULT_REG_LEN);
1164 guest_addr = dma_frcd_page_addr(guest_addr);
1165 /* clear the fault */
1166 writel(DMA_FRCD_F, iommu->reg + reg +
1167 fault_index * PRIMARY_FAULT_REG_LEN + 12);
1168
1169 spin_unlock_irqrestore(&iommu->register_lock, flag);
1170
1171 iommu_page_fault_do_one(iommu, type, fault_reason,
1172 source_id, guest_addr);
1173
1174 fault_index++;
1175 if (fault_index > cap_num_fault_regs(iommu->cap))
1176 fault_index = 0;
1177 spin_lock_irqsave(&iommu->register_lock, flag);
1178 }
1179clear_overflow:
1180 /* clear primary fault overflow */
1181 fault_status = readl(iommu->reg + DMAR_FSTS_REG);
1182 if (fault_status & DMA_FSTS_PFO)
1183 writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
1184
1185 spin_unlock_irqrestore(&iommu->register_lock, flag);
1186 return IRQ_HANDLED;
1187}
1188
1189int dmar_set_interrupt(struct intel_iommu *iommu)
1190{
1191 int irq, ret;
1192
1193 irq = create_irq();
1194 if (!irq) {
1195 printk(KERN_ERR "IOMMU: no free vectors\n");
1196 return -EINVAL;
1197 }
1198
1199 set_irq_data(irq, iommu);
1200 iommu->irq = irq;
1201
1202 ret = arch_setup_dmar_msi(irq);
1203 if (ret) {
1204 set_irq_data(irq, NULL);
1205 iommu->irq = 0;
1206 destroy_irq(irq);
1207 return 0;
1208 }
1209
1210 /* Force fault register is cleared */
1211 iommu_page_fault(irq, iommu);
1212
1213 ret = request_irq(irq, iommu_page_fault, 0, iommu->name, iommu);
1214 if (ret)
1215 printk(KERN_ERR "IOMMU: can't request irq\n");
1216 return ret;
1217}
1218
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001219static int iommu_init_domains(struct intel_iommu *iommu)
1220{
1221 unsigned long ndomains;
1222 unsigned long nlongs;
1223
1224 ndomains = cap_ndoms(iommu->cap);
1225 pr_debug("Number of Domains supportd <%ld>\n", ndomains);
1226 nlongs = BITS_TO_LONGS(ndomains);
1227
1228 /* TBD: there might be 64K domains,
1229 * consider other allocation for future chip
1230 */
1231 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1232 if (!iommu->domain_ids) {
1233 printk(KERN_ERR "Allocating domain id array failed\n");
1234 return -ENOMEM;
1235 }
1236 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1237 GFP_KERNEL);
1238 if (!iommu->domains) {
1239 printk(KERN_ERR "Allocating domain array failed\n");
1240 kfree(iommu->domain_ids);
1241 return -ENOMEM;
1242 }
1243
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001244 spin_lock_init(&iommu->lock);
1245
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001246 /*
1247 * if Caching mode is set, then invalid translations are tagged
1248 * with domainid 0. Hence we need to pre-allocate it.
1249 */
1250 if (cap_caching_mode(iommu->cap))
1251 set_bit(0, iommu->domain_ids);
1252 return 0;
1253}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001254
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001255
1256static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001257static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001258
1259void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001260{
1261 struct dmar_domain *domain;
1262 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001263 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001264
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001265 i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
1266 for (; i < cap_ndoms(iommu->cap); ) {
1267 domain = iommu->domains[i];
1268 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001269
1270 spin_lock_irqsave(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001271 if (--domain->iommu_count == 0) {
1272 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1273 vm_domain_exit(domain);
1274 else
1275 domain_exit(domain);
1276 }
Weidong Hanc7151a82008-12-08 22:51:37 +08001277 spin_unlock_irqrestore(&domain->iommu_lock, flags);
1278
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001279 i = find_next_bit(iommu->domain_ids,
1280 cap_ndoms(iommu->cap), i+1);
1281 }
1282
1283 if (iommu->gcmd & DMA_GCMD_TE)
1284 iommu_disable_translation(iommu);
1285
1286 if (iommu->irq) {
1287 set_irq_data(iommu->irq, NULL);
1288 /* This will mask the irq */
1289 free_irq(iommu->irq, iommu);
1290 destroy_irq(iommu->irq);
1291 }
1292
1293 kfree(iommu->domains);
1294 kfree(iommu->domain_ids);
1295
Weidong Hand9630fe2008-12-08 11:06:32 +08001296 g_iommus[iommu->seq_id] = NULL;
1297
1298 /* if all iommus are freed, free g_iommus */
1299 for (i = 0; i < g_num_of_iommus; i++) {
1300 if (g_iommus[i])
1301 break;
1302 }
1303
1304 if (i == g_num_of_iommus)
1305 kfree(g_iommus);
1306
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001307 /* free context mapping */
1308 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001309}
1310
1311static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
1312{
1313 unsigned long num;
1314 unsigned long ndomains;
1315 struct dmar_domain *domain;
1316 unsigned long flags;
1317
1318 domain = alloc_domain_mem();
1319 if (!domain)
1320 return NULL;
1321
1322 ndomains = cap_ndoms(iommu->cap);
1323
1324 spin_lock_irqsave(&iommu->lock, flags);
1325 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1326 if (num >= ndomains) {
1327 spin_unlock_irqrestore(&iommu->lock, flags);
1328 free_domain_mem(domain);
1329 printk(KERN_ERR "IOMMU: no free domain ids\n");
1330 return NULL;
1331 }
1332
1333 set_bit(num, iommu->domain_ids);
1334 domain->id = num;
Weidong Han8c11e792008-12-08 15:29:22 +08001335 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
1336 set_bit(iommu->seq_id, &domain->iommu_bmp);
Weidong Hand71a2f32008-12-07 21:13:41 +08001337 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001338 iommu->domains[num] = domain;
1339 spin_unlock_irqrestore(&iommu->lock, flags);
1340
1341 return domain;
1342}
1343
1344static void iommu_free_domain(struct dmar_domain *domain)
1345{
1346 unsigned long flags;
Weidong Han8c11e792008-12-08 15:29:22 +08001347 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001348
Weidong Han8c11e792008-12-08 15:29:22 +08001349 iommu = domain_get_iommu(domain);
1350
1351 spin_lock_irqsave(&iommu->lock, flags);
1352 clear_bit(domain->id, iommu->domain_ids);
1353 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001354}
1355
1356static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001357static struct lock_class_key reserved_alloc_key;
1358static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001359
1360static void dmar_init_reserved_ranges(void)
1361{
1362 struct pci_dev *pdev = NULL;
1363 struct iova *iova;
1364 int i;
1365 u64 addr, size;
1366
David Millerf6611972008-02-06 01:36:23 -08001367 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001368
Mark Gross8a443df2008-03-04 14:59:31 -08001369 lockdep_set_class(&reserved_iova_list.iova_alloc_lock,
1370 &reserved_alloc_key);
1371 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1372 &reserved_rbtree_key);
1373
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001374 /* IOAPIC ranges shouldn't be accessed by DMA */
1375 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1376 IOVA_PFN(IOAPIC_RANGE_END));
1377 if (!iova)
1378 printk(KERN_ERR "Reserve IOAPIC range failed\n");
1379
1380 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1381 for_each_pci_dev(pdev) {
1382 struct resource *r;
1383
1384 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1385 r = &pdev->resource[i];
1386 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1387 continue;
1388 addr = r->start;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001389 addr &= PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001390 size = r->end - addr;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001391 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001392 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
1393 IOVA_PFN(size + addr) - 1);
1394 if (!iova)
1395 printk(KERN_ERR "Reserve iova failed\n");
1396 }
1397 }
1398
1399}
1400
1401static void domain_reserve_special_ranges(struct dmar_domain *domain)
1402{
1403 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1404}
1405
1406static inline int guestwidth_to_adjustwidth(int gaw)
1407{
1408 int agaw;
1409 int r = (gaw - 12) % 9;
1410
1411 if (r == 0)
1412 agaw = gaw;
1413 else
1414 agaw = gaw + 9 - r;
1415 if (agaw > 64)
1416 agaw = 64;
1417 return agaw;
1418}
1419
1420static int domain_init(struct dmar_domain *domain, int guest_width)
1421{
1422 struct intel_iommu *iommu;
1423 int adjust_width, agaw;
1424 unsigned long sagaw;
1425
David Millerf6611972008-02-06 01:36:23 -08001426 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001427 spin_lock_init(&domain->mapping_lock);
Weidong Hanc7151a82008-12-08 22:51:37 +08001428 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001429
1430 domain_reserve_special_ranges(domain);
1431
1432 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001433 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001434 if (guest_width > cap_mgaw(iommu->cap))
1435 guest_width = cap_mgaw(iommu->cap);
1436 domain->gaw = guest_width;
1437 adjust_width = guestwidth_to_adjustwidth(guest_width);
1438 agaw = width_to_agaw(adjust_width);
1439 sagaw = cap_sagaw(iommu->cap);
1440 if (!test_bit(agaw, &sagaw)) {
1441 /* hardware doesn't support it, choose a bigger one */
1442 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1443 agaw = find_next_bit(&sagaw, 5, agaw);
1444 if (agaw >= 5)
1445 return -ENODEV;
1446 }
1447 domain->agaw = agaw;
1448 INIT_LIST_HEAD(&domain->devices);
1449
Weidong Han8e6040972008-12-08 15:49:06 +08001450 if (ecap_coherent(iommu->ecap))
1451 domain->iommu_coherency = 1;
1452 else
1453 domain->iommu_coherency = 0;
1454
Sheng Yang58c610b2009-03-18 15:33:05 +08001455 if (ecap_sc_support(iommu->ecap))
1456 domain->iommu_snooping = 1;
1457 else
1458 domain->iommu_snooping = 0;
1459
Weidong Hanc7151a82008-12-08 22:51:37 +08001460 domain->iommu_count = 1;
1461
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001462 /* always allocate the top pgd */
1463 domain->pgd = (struct dma_pte *)alloc_pgtable_page();
1464 if (!domain->pgd)
1465 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001466 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001467 return 0;
1468}
1469
1470static void domain_exit(struct dmar_domain *domain)
1471{
1472 u64 end;
1473
1474 /* Domain 0 is reserved, so dont process it */
1475 if (!domain)
1476 return;
1477
1478 domain_remove_dev_info(domain);
1479 /* destroy iovas */
1480 put_iova_domain(&domain->iovad);
1481 end = DOMAIN_MAX_ADDR(domain->gaw);
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001482 end = end & (~PAGE_MASK);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001483
1484 /* clear ptes */
1485 dma_pte_clear_range(domain, 0, end);
1486
1487 /* free page tables */
1488 dma_pte_free_pagetable(domain, 0, end);
1489
1490 iommu_free_domain(domain);
1491 free_domain_mem(domain);
1492}
1493
1494static int domain_context_mapping_one(struct dmar_domain *domain,
1495 u8 bus, u8 devfn)
1496{
1497 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001498 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001499 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001500 struct dma_pte *pgd;
1501 unsigned long num;
1502 unsigned long ndomains;
1503 int id;
1504 int agaw;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001505
1506 pr_debug("Set context mapping for %02x:%02x.%d\n",
1507 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
1508 BUG_ON(!domain->pgd);
Weidong Han5331fe62008-12-08 23:00:00 +08001509
1510 iommu = device_to_iommu(bus, devfn);
1511 if (!iommu)
1512 return -ENODEV;
1513
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001514 context = device_to_context_entry(iommu, bus, devfn);
1515 if (!context)
1516 return -ENOMEM;
1517 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001518 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001519 spin_unlock_irqrestore(&iommu->lock, flags);
1520 return 0;
1521 }
1522
Weidong Hanea6606b2008-12-08 23:08:15 +08001523 id = domain->id;
1524 pgd = domain->pgd;
1525
1526 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
1527 int found = 0;
1528
1529 /* find an available domain id for this device in iommu */
1530 ndomains = cap_ndoms(iommu->cap);
1531 num = find_first_bit(iommu->domain_ids, ndomains);
1532 for (; num < ndomains; ) {
1533 if (iommu->domains[num] == domain) {
1534 id = num;
1535 found = 1;
1536 break;
1537 }
1538 num = find_next_bit(iommu->domain_ids,
1539 cap_ndoms(iommu->cap), num+1);
1540 }
1541
1542 if (found == 0) {
1543 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1544 if (num >= ndomains) {
1545 spin_unlock_irqrestore(&iommu->lock, flags);
1546 printk(KERN_ERR "IOMMU: no free domain ids\n");
1547 return -EFAULT;
1548 }
1549
1550 set_bit(num, iommu->domain_ids);
1551 iommu->domains[num] = domain;
1552 id = num;
1553 }
1554
1555 /* Skip top levels of page tables for
1556 * iommu which has less agaw than default.
1557 */
1558 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1559 pgd = phys_to_virt(dma_pte_addr(pgd));
1560 if (!dma_pte_present(pgd)) {
1561 spin_unlock_irqrestore(&iommu->lock, flags);
1562 return -ENOMEM;
1563 }
1564 }
1565 }
1566
1567 context_set_domain_id(context, id);
1568 context_set_address_width(context, iommu->agaw);
1569 context_set_address_root(context, virt_to_phys(pgd));
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001570 context_set_translation_type(context, CONTEXT_TT_MULTI_LEVEL);
1571 context_set_fault_enable(context);
1572 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001573 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001574
1575 /* it's a non-present to present mapping */
Youquan Songa77b67d2008-10-16 16:31:56 -07001576 if (iommu->flush.flush_context(iommu, domain->id,
1577 (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT,
1578 DMA_CCMD_DEVICE_INVL, 1))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001579 iommu_flush_write_buffer(iommu);
1580 else
Youquan Songa77b67d2008-10-16 16:31:56 -07001581 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH, 0);
1582
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001583 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001584
1585 spin_lock_irqsave(&domain->iommu_lock, flags);
1586 if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
1587 domain->iommu_count++;
Sheng Yang58c610b2009-03-18 15:33:05 +08001588 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001589 }
1590 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001591 return 0;
1592}
1593
1594static int
1595domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev)
1596{
1597 int ret;
1598 struct pci_dev *tmp, *parent;
1599
1600 ret = domain_context_mapping_one(domain, pdev->bus->number,
1601 pdev->devfn);
1602 if (ret)
1603 return ret;
1604
1605 /* dependent device mapping */
1606 tmp = pci_find_upstream_pcie_bridge(pdev);
1607 if (!tmp)
1608 return 0;
1609 /* Secondary interface's bus number and devfn 0 */
1610 parent = pdev->bus->self;
1611 while (parent != tmp) {
1612 ret = domain_context_mapping_one(domain, parent->bus->number,
1613 parent->devfn);
1614 if (ret)
1615 return ret;
1616 parent = parent->bus->self;
1617 }
1618 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
1619 return domain_context_mapping_one(domain,
1620 tmp->subordinate->number, 0);
1621 else /* this is a legacy PCI bridge */
1622 return domain_context_mapping_one(domain,
1623 tmp->bus->number, tmp->devfn);
1624}
1625
Weidong Han5331fe62008-12-08 23:00:00 +08001626static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001627{
1628 int ret;
1629 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001630 struct intel_iommu *iommu;
1631
1632 iommu = device_to_iommu(pdev->bus->number, pdev->devfn);
1633 if (!iommu)
1634 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001635
Weidong Han8c11e792008-12-08 15:29:22 +08001636 ret = device_context_mapped(iommu,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001637 pdev->bus->number, pdev->devfn);
1638 if (!ret)
1639 return ret;
1640 /* dependent device mapping */
1641 tmp = pci_find_upstream_pcie_bridge(pdev);
1642 if (!tmp)
1643 return ret;
1644 /* Secondary interface's bus number and devfn 0 */
1645 parent = pdev->bus->self;
1646 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001647 ret = device_context_mapped(iommu, parent->bus->number,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001648 parent->devfn);
1649 if (!ret)
1650 return ret;
1651 parent = parent->bus->self;
1652 }
1653 if (tmp->is_pcie)
Weidong Han8c11e792008-12-08 15:29:22 +08001654 return device_context_mapped(iommu,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001655 tmp->subordinate->number, 0);
1656 else
Weidong Han8c11e792008-12-08 15:29:22 +08001657 return device_context_mapped(iommu,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001658 tmp->bus->number, tmp->devfn);
1659}
1660
1661static int
1662domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
1663 u64 hpa, size_t size, int prot)
1664{
1665 u64 start_pfn, end_pfn;
1666 struct dma_pte *pte;
1667 int index;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001668 int addr_width = agaw_to_width(domain->agaw);
1669
1670 hpa &= (((u64)1) << addr_width) - 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001671
1672 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1673 return -EINVAL;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001674 iova &= PAGE_MASK;
1675 start_pfn = ((u64)hpa) >> VTD_PAGE_SHIFT;
1676 end_pfn = (VTD_PAGE_ALIGN(((u64)hpa) + size)) >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001677 index = 0;
1678 while (start_pfn < end_pfn) {
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001679 pte = addr_to_dma_pte(domain, iova + VTD_PAGE_SIZE * index);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001680 if (!pte)
1681 return -ENOMEM;
1682 /* We don't need lock here, nobody else
1683 * touches the iova range
1684 */
Mark McLoughlin19c239c2008-11-21 16:56:53 +00001685 BUG_ON(dma_pte_addr(pte));
1686 dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT);
1687 dma_set_pte_prot(pte, prot);
Weidong Han5331fe62008-12-08 23:00:00 +08001688 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001689 start_pfn++;
1690 index++;
1691 }
1692 return 0;
1693}
1694
Weidong Hanc7151a82008-12-08 22:51:37 +08001695static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001696{
Weidong Hanc7151a82008-12-08 22:51:37 +08001697 if (!iommu)
1698 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001699
1700 clear_context_table(iommu, bus, devfn);
1701 iommu->flush.flush_context(iommu, 0, 0, 0,
Youquan Songa77b67d2008-10-16 16:31:56 -07001702 DMA_CCMD_GLOBAL_INVL, 0);
Weidong Han8c11e792008-12-08 15:29:22 +08001703 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Youquan Songa77b67d2008-10-16 16:31:56 -07001704 DMA_TLB_GLOBAL_FLUSH, 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001705}
1706
1707static void domain_remove_dev_info(struct dmar_domain *domain)
1708{
1709 struct device_domain_info *info;
1710 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001711 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001712
1713 spin_lock_irqsave(&device_domain_lock, flags);
1714 while (!list_empty(&domain->devices)) {
1715 info = list_entry(domain->devices.next,
1716 struct device_domain_info, link);
1717 list_del(&info->link);
1718 list_del(&info->global);
1719 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001720 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001721 spin_unlock_irqrestore(&device_domain_lock, flags);
1722
Weidong Hanc7151a82008-12-08 22:51:37 +08001723 iommu = device_to_iommu(info->bus, info->devfn);
1724 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001725 free_devinfo_mem(info);
1726
1727 spin_lock_irqsave(&device_domain_lock, flags);
1728 }
1729 spin_unlock_irqrestore(&device_domain_lock, flags);
1730}
1731
1732/*
1733 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001734 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001735 */
Kay, Allen M38717942008-09-09 18:37:29 +03001736static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001737find_domain(struct pci_dev *pdev)
1738{
1739 struct device_domain_info *info;
1740
1741 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001742 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001743 if (info)
1744 return info->domain;
1745 return NULL;
1746}
1747
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001748/* domain is initialized */
1749static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1750{
1751 struct dmar_domain *domain, *found = NULL;
1752 struct intel_iommu *iommu;
1753 struct dmar_drhd_unit *drhd;
1754 struct device_domain_info *info, *tmp;
1755 struct pci_dev *dev_tmp;
1756 unsigned long flags;
1757 int bus = 0, devfn = 0;
1758
1759 domain = find_domain(pdev);
1760 if (domain)
1761 return domain;
1762
1763 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1764 if (dev_tmp) {
1765 if (dev_tmp->is_pcie) {
1766 bus = dev_tmp->subordinate->number;
1767 devfn = 0;
1768 } else {
1769 bus = dev_tmp->bus->number;
1770 devfn = dev_tmp->devfn;
1771 }
1772 spin_lock_irqsave(&device_domain_lock, flags);
1773 list_for_each_entry(info, &device_domain_list, global) {
1774 if (info->bus == bus && info->devfn == devfn) {
1775 found = info->domain;
1776 break;
1777 }
1778 }
1779 spin_unlock_irqrestore(&device_domain_lock, flags);
1780 /* pcie-pci bridge already has a domain, uses it */
1781 if (found) {
1782 domain = found;
1783 goto found_domain;
1784 }
1785 }
1786
1787 /* Allocate new domain for the device */
1788 drhd = dmar_find_matched_drhd_unit(pdev);
1789 if (!drhd) {
1790 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
1791 pci_name(pdev));
1792 return NULL;
1793 }
1794 iommu = drhd->iommu;
1795
1796 domain = iommu_alloc_domain(iommu);
1797 if (!domain)
1798 goto error;
1799
1800 if (domain_init(domain, gaw)) {
1801 domain_exit(domain);
1802 goto error;
1803 }
1804
1805 /* register pcie-to-pci device */
1806 if (dev_tmp) {
1807 info = alloc_devinfo_mem();
1808 if (!info) {
1809 domain_exit(domain);
1810 goto error;
1811 }
1812 info->bus = bus;
1813 info->devfn = devfn;
1814 info->dev = NULL;
1815 info->domain = domain;
1816 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08001817 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001818
1819 /* pcie-to-pci bridge already has a domain, uses it */
1820 found = NULL;
1821 spin_lock_irqsave(&device_domain_lock, flags);
1822 list_for_each_entry(tmp, &device_domain_list, global) {
1823 if (tmp->bus == bus && tmp->devfn == devfn) {
1824 found = tmp->domain;
1825 break;
1826 }
1827 }
1828 if (found) {
1829 free_devinfo_mem(info);
1830 domain_exit(domain);
1831 domain = found;
1832 } else {
1833 list_add(&info->link, &domain->devices);
1834 list_add(&info->global, &device_domain_list);
1835 }
1836 spin_unlock_irqrestore(&device_domain_lock, flags);
1837 }
1838
1839found_domain:
1840 info = alloc_devinfo_mem();
1841 if (!info)
1842 goto error;
1843 info->bus = pdev->bus->number;
1844 info->devfn = pdev->devfn;
1845 info->dev = pdev;
1846 info->domain = domain;
1847 spin_lock_irqsave(&device_domain_lock, flags);
1848 /* somebody is fast */
1849 found = find_domain(pdev);
1850 if (found != NULL) {
1851 spin_unlock_irqrestore(&device_domain_lock, flags);
1852 if (found != domain) {
1853 domain_exit(domain);
1854 domain = found;
1855 }
1856 free_devinfo_mem(info);
1857 return domain;
1858 }
1859 list_add(&info->link, &domain->devices);
1860 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001861 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001862 spin_unlock_irqrestore(&device_domain_lock, flags);
1863 return domain;
1864error:
1865 /* recheck it here, maybe others set it */
1866 return find_domain(pdev);
1867}
1868
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001869static int iommu_prepare_identity_map(struct pci_dev *pdev,
1870 unsigned long long start,
1871 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001872{
1873 struct dmar_domain *domain;
1874 unsigned long size;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001875 unsigned long long base;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001876 int ret;
1877
1878 printk(KERN_INFO
1879 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
1880 pci_name(pdev), start, end);
1881 /* page table init */
1882 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
1883 if (!domain)
1884 return -ENOMEM;
1885
1886 /* The address might not be aligned */
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001887 base = start & PAGE_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001888 size = end - base;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001889 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001890 if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
1891 IOVA_PFN(base + size) - 1)) {
1892 printk(KERN_ERR "IOMMU: reserve iova failed\n");
1893 ret = -ENOMEM;
1894 goto error;
1895 }
1896
1897 pr_debug("Mapping reserved region %lx@%llx for %s\n",
1898 size, base, pci_name(pdev));
1899 /*
1900 * RMRR range might have overlap with physical memory range,
1901 * clear it first
1902 */
1903 dma_pte_clear_range(domain, base, base + size);
1904
1905 ret = domain_page_mapping(domain, base, base, size,
1906 DMA_PTE_READ|DMA_PTE_WRITE);
1907 if (ret)
1908 goto error;
1909
1910 /* context entry init */
1911 ret = domain_context_mapping(domain, pdev);
1912 if (!ret)
1913 return 0;
1914error:
1915 domain_exit(domain);
1916 return ret;
1917
1918}
1919
1920static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
1921 struct pci_dev *pdev)
1922{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001923 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001924 return 0;
1925 return iommu_prepare_identity_map(pdev, rmrr->base_address,
1926 rmrr->end_address + 1);
1927}
1928
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001929#ifdef CONFIG_DMAR_GFX_WA
Yinghai Lud52d53b2008-06-16 20:10:55 -07001930struct iommu_prepare_data {
1931 struct pci_dev *pdev;
1932 int ret;
1933};
1934
1935static int __init iommu_prepare_work_fn(unsigned long start_pfn,
1936 unsigned long end_pfn, void *datax)
1937{
1938 struct iommu_prepare_data *data;
1939
1940 data = (struct iommu_prepare_data *)datax;
1941
1942 data->ret = iommu_prepare_identity_map(data->pdev,
1943 start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
1944 return data->ret;
1945
1946}
1947
1948static int __init iommu_prepare_with_active_regions(struct pci_dev *pdev)
1949{
1950 int nid;
1951 struct iommu_prepare_data data;
1952
1953 data.pdev = pdev;
1954 data.ret = 0;
1955
1956 for_each_online_node(nid) {
1957 work_with_active_regions(nid, iommu_prepare_work_fn, &data);
1958 if (data.ret)
1959 return data.ret;
1960 }
1961 return data.ret;
1962}
1963
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001964static void __init iommu_prepare_gfx_mapping(void)
1965{
1966 struct pci_dev *pdev = NULL;
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001967 int ret;
1968
1969 for_each_pci_dev(pdev) {
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001970 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001971 !IS_GFX_DEVICE(pdev))
1972 continue;
1973 printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
1974 pci_name(pdev));
Yinghai Lud52d53b2008-06-16 20:10:55 -07001975 ret = iommu_prepare_with_active_regions(pdev);
1976 if (ret)
1977 printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001978 }
1979}
Mark McLoughlin2abd7e12008-11-20 15:49:50 +00001980#else /* !CONFIG_DMAR_GFX_WA */
1981static inline void iommu_prepare_gfx_mapping(void)
1982{
1983 return;
1984}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07001985#endif
1986
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07001987#ifdef CONFIG_DMAR_FLOPPY_WA
1988static inline void iommu_prepare_isa(void)
1989{
1990 struct pci_dev *pdev;
1991 int ret;
1992
1993 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
1994 if (!pdev)
1995 return;
1996
1997 printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n");
1998 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
1999
2000 if (ret)
2001 printk("IOMMU: Failed to create 0-64M identity map, "
2002 "floppy might not work\n");
2003
2004}
2005#else
2006static inline void iommu_prepare_isa(void)
2007{
2008 return;
2009}
2010#endif /* !CONFIG_DMAR_FLPY_WA */
2011
Mark McLoughlin519a0542008-11-20 14:21:13 +00002012static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002013{
2014 struct dmar_drhd_unit *drhd;
2015 struct dmar_rmrr_unit *rmrr;
2016 struct pci_dev *pdev;
2017 struct intel_iommu *iommu;
mark gross80b20dd2008-04-18 13:53:58 -07002018 int i, ret, unit = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002019
2020 /*
2021 * for each drhd
2022 * allocate root
2023 * initialize and program root entry to not present
2024 * endfor
2025 */
2026 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002027 g_num_of_iommus++;
2028 /*
2029 * lock not needed as this is only incremented in the single
2030 * threaded kernel __init code path all other access are read
2031 * only
2032 */
2033 }
2034
Weidong Hand9630fe2008-12-08 11:06:32 +08002035 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2036 GFP_KERNEL);
2037 if (!g_iommus) {
2038 printk(KERN_ERR "Allocating global iommu array failed\n");
2039 ret = -ENOMEM;
2040 goto error;
2041 }
2042
mark gross80b20dd2008-04-18 13:53:58 -07002043 deferred_flush = kzalloc(g_num_of_iommus *
2044 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2045 if (!deferred_flush) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002046 kfree(g_iommus);
mark gross5e0d2a62008-03-04 15:22:08 -08002047 ret = -ENOMEM;
2048 goto error;
2049 }
2050
mark gross5e0d2a62008-03-04 15:22:08 -08002051 for_each_drhd_unit(drhd) {
2052 if (drhd->ignored)
2053 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002054
2055 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002056 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002057
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002058 ret = iommu_init_domains(iommu);
2059 if (ret)
2060 goto error;
2061
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002062 /*
2063 * TBD:
2064 * we could share the same root & context tables
2065 * amoung all IOMMU's. Need to Split it later.
2066 */
2067 ret = iommu_alloc_root_entry(iommu);
2068 if (ret) {
2069 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2070 goto error;
2071 }
2072 }
2073
Youquan Songa77b67d2008-10-16 16:31:56 -07002074 for_each_drhd_unit(drhd) {
2075 if (drhd->ignored)
2076 continue;
2077
2078 iommu = drhd->iommu;
2079 if (dmar_enable_qi(iommu)) {
2080 /*
2081 * Queued Invalidate not enabled, use Register Based
2082 * Invalidate
2083 */
2084 iommu->flush.flush_context = __iommu_flush_context;
2085 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
2086 printk(KERN_INFO "IOMMU 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002087 "invalidation\n",
2088 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002089 } else {
2090 iommu->flush.flush_context = qi_flush_context;
2091 iommu->flush.flush_iotlb = qi_flush_iotlb;
2092 printk(KERN_INFO "IOMMU 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002093 "invalidation\n",
2094 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002095 }
2096 }
2097
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002098 /*
2099 * For each rmrr
2100 * for each dev attached to rmrr
2101 * do
2102 * locate drhd for dev, alloc domain for dev
2103 * allocate free domain
2104 * allocate page table entries for rmrr
2105 * if context not allocated for bus
2106 * allocate and init context
2107 * set present in root table for this bus
2108 * init context with domain, translation etc
2109 * endfor
2110 * endfor
2111 */
2112 for_each_rmrr_units(rmrr) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002113 for (i = 0; i < rmrr->devices_cnt; i++) {
2114 pdev = rmrr->devices[i];
2115 /* some BIOS lists non-exist devices in DMAR table */
2116 if (!pdev)
2117 continue;
2118 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2119 if (ret)
2120 printk(KERN_ERR
2121 "IOMMU: mapping reserved region failed\n");
2122 }
2123 }
2124
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07002125 iommu_prepare_gfx_mapping();
2126
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002127 iommu_prepare_isa();
2128
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002129 /*
2130 * for each drhd
2131 * enable fault log
2132 * global invalidate context cache
2133 * global invalidate iotlb
2134 * enable translation
2135 */
2136 for_each_drhd_unit(drhd) {
2137 if (drhd->ignored)
2138 continue;
2139 iommu = drhd->iommu;
2140 sprintf (iommu->name, "dmar%d", unit++);
2141
2142 iommu_flush_write_buffer(iommu);
2143
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002144 ret = dmar_set_interrupt(iommu);
2145 if (ret)
2146 goto error;
2147
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002148 iommu_set_root_entry(iommu);
2149
Youquan Songa77b67d2008-10-16 16:31:56 -07002150 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
2151 0);
2152 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
2153 0);
mark grossf8bab732008-02-08 04:18:38 -08002154 iommu_disable_protect_mem_regions(iommu);
2155
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002156 ret = iommu_enable_translation(iommu);
2157 if (ret)
2158 goto error;
2159 }
2160
2161 return 0;
2162error:
2163 for_each_drhd_unit(drhd) {
2164 if (drhd->ignored)
2165 continue;
2166 iommu = drhd->iommu;
2167 free_iommu(iommu);
2168 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002169 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002170 return ret;
2171}
2172
2173static inline u64 aligned_size(u64 host_addr, size_t size)
2174{
2175 u64 addr;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002176 addr = (host_addr & (~PAGE_MASK)) + size;
2177 return PAGE_ALIGN(addr);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002178}
2179
2180struct iova *
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002181iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002182{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002183 struct iova *piova;
2184
2185 /* Make sure it's in range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002186 end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002187 if (!size || (IOVA_START_ADDR + size > end))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002188 return NULL;
2189
2190 piova = alloc_iova(&domain->iovad,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002191 size >> PAGE_SHIFT, IOVA_PFN(end), 1);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002192 return piova;
2193}
2194
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002195static struct iova *
2196__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002197 size_t size, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002198{
2199 struct pci_dev *pdev = to_pci_dev(dev);
2200 struct iova *iova = NULL;
2201
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002202 if (dma_mask <= DMA_32BIT_MASK || dmar_forcedac)
2203 iova = iommu_alloc_iova(domain, size, dma_mask);
2204 else {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002205 /*
2206 * First try to allocate an io virtual address in
2207 * DMA_32BIT_MASK and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002208 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002209 */
2210 iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
2211 if (!iova)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002212 iova = iommu_alloc_iova(domain, size, dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002213 }
2214
2215 if (!iova) {
2216 printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev));
2217 return NULL;
2218 }
2219
2220 return iova;
2221}
2222
2223static struct dmar_domain *
2224get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002225{
2226 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002227 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002228
2229 domain = get_domain_for_dev(pdev,
2230 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2231 if (!domain) {
2232 printk(KERN_ERR
2233 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002234 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002235 }
2236
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002237 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002238 if (unlikely(!domain_context_mapped(pdev))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002239 ret = domain_context_mapping(domain, pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002240 if (ret) {
2241 printk(KERN_ERR
2242 "Domain context map for %s failed",
2243 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002244 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002245 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002246 }
2247
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002248 return domain;
2249}
2250
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002251static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2252 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002253{
2254 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002255 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002256 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002257 struct iova *iova;
2258 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002259 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002260 struct intel_iommu *iommu;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002261
2262 BUG_ON(dir == DMA_NONE);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002263 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002264 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002265
2266 domain = get_valid_domain_for_dev(pdev);
2267 if (!domain)
2268 return 0;
2269
Weidong Han8c11e792008-12-08 15:29:22 +08002270 iommu = domain_get_iommu(domain);
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002271 size = aligned_size((u64)paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002272
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002273 iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002274 if (!iova)
2275 goto error;
2276
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002277 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002278
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002279 /*
2280 * Check if DMAR supports zero-length reads on write only
2281 * mappings..
2282 */
2283 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002284 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002285 prot |= DMA_PTE_READ;
2286 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2287 prot |= DMA_PTE_WRITE;
2288 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002289 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002290 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002291 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002292 * is not a big problem
2293 */
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002294 ret = domain_page_mapping(domain, start_paddr,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002295 ((u64)paddr) & PAGE_MASK, size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002296 if (ret)
2297 goto error;
2298
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002299 /* it's a non-present to present mapping */
Weidong Han8c11e792008-12-08 15:29:22 +08002300 ret = iommu_flush_iotlb_psi(iommu, domain->id,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002301 start_paddr, size >> VTD_PAGE_SHIFT, 1);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002302 if (ret)
Weidong Han8c11e792008-12-08 15:29:22 +08002303 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002304
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002305 return start_paddr + ((u64)paddr & (~PAGE_MASK));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002306
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002307error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002308 if (iova)
2309 __free_iova(&domain->iovad, iova);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002310 printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002311 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002312 return 0;
2313}
2314
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002315dma_addr_t intel_map_single(struct device *hwdev, phys_addr_t paddr,
2316 size_t size, int dir)
2317{
2318 return __intel_map_single(hwdev, paddr, size, dir,
2319 to_pci_dev(hwdev)->dma_mask);
2320}
2321
mark gross5e0d2a62008-03-04 15:22:08 -08002322static void flush_unmaps(void)
2323{
mark gross80b20dd2008-04-18 13:53:58 -07002324 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002325
mark gross5e0d2a62008-03-04 15:22:08 -08002326 timer_on = 0;
2327
2328 /* just flush them all */
2329 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002330 struct intel_iommu *iommu = g_iommus[i];
2331 if (!iommu)
2332 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002333
Weidong Hana2bb8452008-12-08 11:24:12 +08002334 if (deferred_flush[i].next) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002335 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
2336 DMA_TLB_GLOBAL_FLUSH, 0);
mark gross80b20dd2008-04-18 13:53:58 -07002337 for (j = 0; j < deferred_flush[i].next; j++) {
2338 __free_iova(&deferred_flush[i].domain[j]->iovad,
2339 deferred_flush[i].iova[j]);
2340 }
2341 deferred_flush[i].next = 0;
2342 }
mark gross5e0d2a62008-03-04 15:22:08 -08002343 }
2344
mark gross5e0d2a62008-03-04 15:22:08 -08002345 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002346}
2347
2348static void flush_unmaps_timeout(unsigned long data)
2349{
mark gross80b20dd2008-04-18 13:53:58 -07002350 unsigned long flags;
2351
2352 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002353 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002354 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002355}
2356
2357static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2358{
2359 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002360 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002361 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002362
2363 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002364 if (list_size == HIGH_WATER_MARK)
2365 flush_unmaps();
2366
Weidong Han8c11e792008-12-08 15:29:22 +08002367 iommu = domain_get_iommu(dom);
2368 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002369
mark gross80b20dd2008-04-18 13:53:58 -07002370 next = deferred_flush[iommu_id].next;
2371 deferred_flush[iommu_id].domain[next] = dom;
2372 deferred_flush[iommu_id].iova[next] = iova;
2373 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002374
2375 if (!timer_on) {
2376 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2377 timer_on = 1;
2378 }
2379 list_size++;
2380 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2381}
2382
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002383void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
2384 int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002385{
2386 struct pci_dev *pdev = to_pci_dev(dev);
2387 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002388 unsigned long start_addr;
2389 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002390 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002391
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002392 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002393 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002394 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002395 BUG_ON(!domain);
2396
Weidong Han8c11e792008-12-08 15:29:22 +08002397 iommu = domain_get_iommu(domain);
2398
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002399 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
2400 if (!iova)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002401 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002402
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002403 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002404 size = aligned_size((u64)dev_addr, size);
2405
2406 pr_debug("Device %s unmapping: %lx@%llx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002407 pci_name(pdev), size, (unsigned long long)start_addr);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002408
2409 /* clear the whole page */
2410 dma_pte_clear_range(domain, start_addr, start_addr + size);
2411 /* free page tables */
2412 dma_pte_free_pagetable(domain, start_addr, start_addr + size);
mark gross5e0d2a62008-03-04 15:22:08 -08002413 if (intel_iommu_strict) {
Weidong Han8c11e792008-12-08 15:29:22 +08002414 if (iommu_flush_iotlb_psi(iommu,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002415 domain->id, start_addr, size >> VTD_PAGE_SHIFT, 0))
Weidong Han8c11e792008-12-08 15:29:22 +08002416 iommu_flush_write_buffer(iommu);
mark gross5e0d2a62008-03-04 15:22:08 -08002417 /* free iova */
2418 __free_iova(&domain->iovad, iova);
2419 } else {
2420 add_unmap(domain, iova);
2421 /*
2422 * queue up the release of the unmap to save the 1/6th of the
2423 * cpu used up by the iotlb flush operation...
2424 */
mark gross5e0d2a62008-03-04 15:22:08 -08002425 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002426}
2427
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002428void *intel_alloc_coherent(struct device *hwdev, size_t size,
2429 dma_addr_t *dma_handle, gfp_t flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002430{
2431 void *vaddr;
2432 int order;
2433
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002434 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002435 order = get_order(size);
2436 flags &= ~(GFP_DMA | GFP_DMA32);
2437
2438 vaddr = (void *)__get_free_pages(flags, order);
2439 if (!vaddr)
2440 return NULL;
2441 memset(vaddr, 0, size);
2442
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002443 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2444 DMA_BIDIRECTIONAL,
2445 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002446 if (*dma_handle)
2447 return vaddr;
2448 free_pages((unsigned long)vaddr, order);
2449 return NULL;
2450}
2451
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002452void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
2453 dma_addr_t dma_handle)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002454{
2455 int order;
2456
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002457 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002458 order = get_order(size);
2459
2460 intel_unmap_single(hwdev, dma_handle, size, DMA_BIDIRECTIONAL);
2461 free_pages((unsigned long)vaddr, order);
2462}
2463
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002464#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg)))
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002465
2466void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
2467 int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002468{
2469 int i;
2470 struct pci_dev *pdev = to_pci_dev(hwdev);
2471 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002472 unsigned long start_addr;
2473 struct iova *iova;
2474 size_t size = 0;
2475 void *addr;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002476 struct scatterlist *sg;
Weidong Han8c11e792008-12-08 15:29:22 +08002477 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002478
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002479 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002480 return;
2481
2482 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08002483 BUG_ON(!domain);
2484
2485 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002486
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002487 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002488 if (!iova)
2489 return;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002490 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002491 addr = SG_ENT_VIRT_ADDRESS(sg);
2492 size += aligned_size((u64)addr, sg->length);
2493 }
2494
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002495 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002496
2497 /* clear the whole page */
2498 dma_pte_clear_range(domain, start_addr, start_addr + size);
2499 /* free page tables */
2500 dma_pte_free_pagetable(domain, start_addr, start_addr + size);
2501
Weidong Han8c11e792008-12-08 15:29:22 +08002502 if (iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002503 size >> VTD_PAGE_SHIFT, 0))
Weidong Han8c11e792008-12-08 15:29:22 +08002504 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002505
2506 /* free iova */
2507 __free_iova(&domain->iovad, iova);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002508}
2509
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002510static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002511 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002512{
2513 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002514 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002515
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002516 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002517 BUG_ON(!sg_page(sg));
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002518 sg->dma_address = virt_to_bus(SG_ENT_VIRT_ADDRESS(sg));
2519 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002520 }
2521 return nelems;
2522}
2523
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002524int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
2525 int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002526{
2527 void *addr;
2528 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002529 struct pci_dev *pdev = to_pci_dev(hwdev);
2530 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002531 size_t size = 0;
2532 int prot = 0;
2533 size_t offset = 0;
2534 struct iova *iova = NULL;
2535 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002536 struct scatterlist *sg;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002537 unsigned long start_addr;
Weidong Han8c11e792008-12-08 15:29:22 +08002538 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002539
2540 BUG_ON(dir == DMA_NONE);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002541 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002542 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002543
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002544 domain = get_valid_domain_for_dev(pdev);
2545 if (!domain)
2546 return 0;
2547
Weidong Han8c11e792008-12-08 15:29:22 +08002548 iommu = domain_get_iommu(domain);
2549
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002550 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002551 addr = SG_ENT_VIRT_ADDRESS(sg);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002552 addr = (void *)virt_to_phys(addr);
2553 size += aligned_size((u64)addr, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002554 }
2555
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002556 iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002557 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002558 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002559 return 0;
2560 }
2561
2562 /*
2563 * Check if DMAR supports zero-length reads on write only
2564 * mappings..
2565 */
2566 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002567 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002568 prot |= DMA_PTE_READ;
2569 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2570 prot |= DMA_PTE_WRITE;
2571
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002572 start_addr = iova->pfn_lo << PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002573 offset = 0;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002574 for_each_sg(sglist, sg, nelems, i) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002575 addr = SG_ENT_VIRT_ADDRESS(sg);
2576 addr = (void *)virt_to_phys(addr);
2577 size = aligned_size((u64)addr, sg->length);
2578 ret = domain_page_mapping(domain, start_addr + offset,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002579 ((u64)addr) & PAGE_MASK,
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002580 size, prot);
2581 if (ret) {
2582 /* clear the page */
2583 dma_pte_clear_range(domain, start_addr,
2584 start_addr + offset);
2585 /* free page tables */
2586 dma_pte_free_pagetable(domain, start_addr,
2587 start_addr + offset);
2588 /* free iova */
2589 __free_iova(&domain->iovad, iova);
2590 return 0;
2591 }
2592 sg->dma_address = start_addr + offset +
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002593 ((u64)addr & (~PAGE_MASK));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002594 sg->dma_length = sg->length;
2595 offset += size;
2596 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002597
2598 /* it's a non-present to present mapping */
Weidong Han8c11e792008-12-08 15:29:22 +08002599 if (iommu_flush_iotlb_psi(iommu, domain->id,
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002600 start_addr, offset >> VTD_PAGE_SHIFT, 1))
Weidong Han8c11e792008-12-08 15:29:22 +08002601 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002602 return nelems;
2603}
2604
2605static struct dma_mapping_ops intel_dma_ops = {
2606 .alloc_coherent = intel_alloc_coherent,
2607 .free_coherent = intel_free_coherent,
2608 .map_single = intel_map_single,
2609 .unmap_single = intel_unmap_single,
2610 .map_sg = intel_map_sg,
2611 .unmap_sg = intel_unmap_sg,
2612};
2613
2614static inline int iommu_domain_cache_init(void)
2615{
2616 int ret = 0;
2617
2618 iommu_domain_cache = kmem_cache_create("iommu_domain",
2619 sizeof(struct dmar_domain),
2620 0,
2621 SLAB_HWCACHE_ALIGN,
2622
2623 NULL);
2624 if (!iommu_domain_cache) {
2625 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
2626 ret = -ENOMEM;
2627 }
2628
2629 return ret;
2630}
2631
2632static inline int iommu_devinfo_cache_init(void)
2633{
2634 int ret = 0;
2635
2636 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
2637 sizeof(struct device_domain_info),
2638 0,
2639 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002640 NULL);
2641 if (!iommu_devinfo_cache) {
2642 printk(KERN_ERR "Couldn't create devinfo cache\n");
2643 ret = -ENOMEM;
2644 }
2645
2646 return ret;
2647}
2648
2649static inline int iommu_iova_cache_init(void)
2650{
2651 int ret = 0;
2652
2653 iommu_iova_cache = kmem_cache_create("iommu_iova",
2654 sizeof(struct iova),
2655 0,
2656 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002657 NULL);
2658 if (!iommu_iova_cache) {
2659 printk(KERN_ERR "Couldn't create iova cache\n");
2660 ret = -ENOMEM;
2661 }
2662
2663 return ret;
2664}
2665
2666static int __init iommu_init_mempool(void)
2667{
2668 int ret;
2669 ret = iommu_iova_cache_init();
2670 if (ret)
2671 return ret;
2672
2673 ret = iommu_domain_cache_init();
2674 if (ret)
2675 goto domain_error;
2676
2677 ret = iommu_devinfo_cache_init();
2678 if (!ret)
2679 return ret;
2680
2681 kmem_cache_destroy(iommu_domain_cache);
2682domain_error:
2683 kmem_cache_destroy(iommu_iova_cache);
2684
2685 return -ENOMEM;
2686}
2687
2688static void __init iommu_exit_mempool(void)
2689{
2690 kmem_cache_destroy(iommu_devinfo_cache);
2691 kmem_cache_destroy(iommu_domain_cache);
2692 kmem_cache_destroy(iommu_iova_cache);
2693
2694}
2695
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002696static void __init init_no_remapping_devices(void)
2697{
2698 struct dmar_drhd_unit *drhd;
2699
2700 for_each_drhd_unit(drhd) {
2701 if (!drhd->include_all) {
2702 int i;
2703 for (i = 0; i < drhd->devices_cnt; i++)
2704 if (drhd->devices[i] != NULL)
2705 break;
2706 /* ignore DMAR unit if no pci devices exist */
2707 if (i == drhd->devices_cnt)
2708 drhd->ignored = 1;
2709 }
2710 }
2711
2712 if (dmar_map_gfx)
2713 return;
2714
2715 for_each_drhd_unit(drhd) {
2716 int i;
2717 if (drhd->ignored || drhd->include_all)
2718 continue;
2719
2720 for (i = 0; i < drhd->devices_cnt; i++)
2721 if (drhd->devices[i] &&
2722 !IS_GFX_DEVICE(drhd->devices[i]))
2723 break;
2724
2725 if (i < drhd->devices_cnt)
2726 continue;
2727
2728 /* bypass IOMMU if it is just for gfx devices */
2729 drhd->ignored = 1;
2730 for (i = 0; i < drhd->devices_cnt; i++) {
2731 if (!drhd->devices[i])
2732 continue;
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002733 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002734 }
2735 }
2736}
2737
2738int __init intel_iommu_init(void)
2739{
2740 int ret = 0;
2741
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002742 if (dmar_table_init())
2743 return -ENODEV;
2744
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002745 if (dmar_dev_scope_init())
2746 return -ENODEV;
2747
Suresh Siddha2ae21012008-07-10 11:16:43 -07002748 /*
2749 * Check the need for DMA-remapping initialization now.
2750 * Above initialization will also be used by Interrupt-remapping.
2751 */
2752 if (no_iommu || swiotlb || dmar_disabled)
2753 return -ENODEV;
2754
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002755 iommu_init_mempool();
2756 dmar_init_reserved_ranges();
2757
2758 init_no_remapping_devices();
2759
2760 ret = init_dmars();
2761 if (ret) {
2762 printk(KERN_ERR "IOMMU: dmar init failed\n");
2763 put_iova_domain(&reserved_iova_list);
2764 iommu_exit_mempool();
2765 return ret;
2766 }
2767 printk(KERN_INFO
2768 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
2769
mark gross5e0d2a62008-03-04 15:22:08 -08002770 init_timer(&unmap_timer);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002771 force_iommu = 1;
2772 dma_ops = &intel_dma_ops;
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01002773
2774 register_iommu(&intel_iommu_ops);
2775
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002776 return 0;
2777}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07002778
Weidong Hanc7151a82008-12-08 22:51:37 +08002779static int vm_domain_add_dev_info(struct dmar_domain *domain,
2780 struct pci_dev *pdev)
2781{
2782 struct device_domain_info *info;
2783 unsigned long flags;
2784
2785 info = alloc_devinfo_mem();
2786 if (!info)
2787 return -ENOMEM;
2788
2789 info->bus = pdev->bus->number;
2790 info->devfn = pdev->devfn;
2791 info->dev = pdev;
2792 info->domain = domain;
2793
2794 spin_lock_irqsave(&device_domain_lock, flags);
2795 list_add(&info->link, &domain->devices);
2796 list_add(&info->global, &device_domain_list);
2797 pdev->dev.archdata.iommu = info;
2798 spin_unlock_irqrestore(&device_domain_lock, flags);
2799
2800 return 0;
2801}
2802
2803static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
2804 struct pci_dev *pdev)
2805{
2806 struct device_domain_info *info;
2807 struct intel_iommu *iommu;
2808 unsigned long flags;
2809 int found = 0;
2810 struct list_head *entry, *tmp;
2811
2812 iommu = device_to_iommu(pdev->bus->number, pdev->devfn);
2813 if (!iommu)
2814 return;
2815
2816 spin_lock_irqsave(&device_domain_lock, flags);
2817 list_for_each_safe(entry, tmp, &domain->devices) {
2818 info = list_entry(entry, struct device_domain_info, link);
2819 if (info->bus == pdev->bus->number &&
2820 info->devfn == pdev->devfn) {
2821 list_del(&info->link);
2822 list_del(&info->global);
2823 if (info->dev)
2824 info->dev->dev.archdata.iommu = NULL;
2825 spin_unlock_irqrestore(&device_domain_lock, flags);
2826
2827 iommu_detach_dev(iommu, info->bus, info->devfn);
2828 free_devinfo_mem(info);
2829
2830 spin_lock_irqsave(&device_domain_lock, flags);
2831
2832 if (found)
2833 break;
2834 else
2835 continue;
2836 }
2837
2838 /* if there is no other devices under the same iommu
2839 * owned by this domain, clear this iommu in iommu_bmp
2840 * update iommu count and coherency
2841 */
2842 if (device_to_iommu(info->bus, info->devfn) == iommu)
2843 found = 1;
2844 }
2845
2846 if (found == 0) {
2847 unsigned long tmp_flags;
2848 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
2849 clear_bit(iommu->seq_id, &domain->iommu_bmp);
2850 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08002851 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08002852 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
2853 }
2854
2855 spin_unlock_irqrestore(&device_domain_lock, flags);
2856}
2857
2858static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
2859{
2860 struct device_domain_info *info;
2861 struct intel_iommu *iommu;
2862 unsigned long flags1, flags2;
2863
2864 spin_lock_irqsave(&device_domain_lock, flags1);
2865 while (!list_empty(&domain->devices)) {
2866 info = list_entry(domain->devices.next,
2867 struct device_domain_info, link);
2868 list_del(&info->link);
2869 list_del(&info->global);
2870 if (info->dev)
2871 info->dev->dev.archdata.iommu = NULL;
2872
2873 spin_unlock_irqrestore(&device_domain_lock, flags1);
2874
2875 iommu = device_to_iommu(info->bus, info->devfn);
2876 iommu_detach_dev(iommu, info->bus, info->devfn);
2877
2878 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08002879 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08002880 */
2881 spin_lock_irqsave(&domain->iommu_lock, flags2);
2882 if (test_and_clear_bit(iommu->seq_id,
2883 &domain->iommu_bmp)) {
2884 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08002885 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08002886 }
2887 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
2888
2889 free_devinfo_mem(info);
2890 spin_lock_irqsave(&device_domain_lock, flags1);
2891 }
2892 spin_unlock_irqrestore(&device_domain_lock, flags1);
2893}
2894
Weidong Han5e98c4b2008-12-08 23:03:27 +08002895/* domain id for virtual machine, it won't be set in context */
2896static unsigned long vm_domid;
2897
Weidong Hanfe40f1e2008-12-08 23:10:23 +08002898static int vm_domain_min_agaw(struct dmar_domain *domain)
2899{
2900 int i;
2901 int min_agaw = domain->agaw;
2902
2903 i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
2904 for (; i < g_num_of_iommus; ) {
2905 if (min_agaw > g_iommus[i]->agaw)
2906 min_agaw = g_iommus[i]->agaw;
2907
2908 i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
2909 }
2910
2911 return min_agaw;
2912}
2913
Weidong Han5e98c4b2008-12-08 23:03:27 +08002914static struct dmar_domain *iommu_alloc_vm_domain(void)
2915{
2916 struct dmar_domain *domain;
2917
2918 domain = alloc_domain_mem();
2919 if (!domain)
2920 return NULL;
2921
2922 domain->id = vm_domid++;
2923 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
2924 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
2925
2926 return domain;
2927}
2928
2929static int vm_domain_init(struct dmar_domain *domain, int guest_width)
2930{
2931 int adjust_width;
2932
2933 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
2934 spin_lock_init(&domain->mapping_lock);
2935 spin_lock_init(&domain->iommu_lock);
2936
2937 domain_reserve_special_ranges(domain);
2938
2939 /* calculate AGAW */
2940 domain->gaw = guest_width;
2941 adjust_width = guestwidth_to_adjustwidth(guest_width);
2942 domain->agaw = width_to_agaw(adjust_width);
2943
2944 INIT_LIST_HEAD(&domain->devices);
2945
2946 domain->iommu_count = 0;
2947 domain->iommu_coherency = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08002948 domain->max_addr = 0;
Weidong Han5e98c4b2008-12-08 23:03:27 +08002949
2950 /* always allocate the top pgd */
2951 domain->pgd = (struct dma_pte *)alloc_pgtable_page();
2952 if (!domain->pgd)
2953 return -ENOMEM;
2954 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
2955 return 0;
2956}
2957
2958static void iommu_free_vm_domain(struct dmar_domain *domain)
2959{
2960 unsigned long flags;
2961 struct dmar_drhd_unit *drhd;
2962 struct intel_iommu *iommu;
2963 unsigned long i;
2964 unsigned long ndomains;
2965
2966 for_each_drhd_unit(drhd) {
2967 if (drhd->ignored)
2968 continue;
2969 iommu = drhd->iommu;
2970
2971 ndomains = cap_ndoms(iommu->cap);
2972 i = find_first_bit(iommu->domain_ids, ndomains);
2973 for (; i < ndomains; ) {
2974 if (iommu->domains[i] == domain) {
2975 spin_lock_irqsave(&iommu->lock, flags);
2976 clear_bit(i, iommu->domain_ids);
2977 iommu->domains[i] = NULL;
2978 spin_unlock_irqrestore(&iommu->lock, flags);
2979 break;
2980 }
2981 i = find_next_bit(iommu->domain_ids, ndomains, i+1);
2982 }
2983 }
2984}
2985
2986static void vm_domain_exit(struct dmar_domain *domain)
2987{
2988 u64 end;
2989
2990 /* Domain 0 is reserved, so dont process it */
2991 if (!domain)
2992 return;
2993
2994 vm_domain_remove_all_dev_info(domain);
2995 /* destroy iovas */
2996 put_iova_domain(&domain->iovad);
2997 end = DOMAIN_MAX_ADDR(domain->gaw);
2998 end = end & (~VTD_PAGE_MASK);
2999
3000 /* clear ptes */
3001 dma_pte_clear_range(domain, 0, end);
3002
3003 /* free page tables */
3004 dma_pte_free_pagetable(domain, 0, end);
3005
3006 iommu_free_vm_domain(domain);
3007 free_domain_mem(domain);
3008}
3009
Joerg Roedel5d450802008-12-03 14:52:32 +01003010static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003011{
Joerg Roedel5d450802008-12-03 14:52:32 +01003012 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003013
Joerg Roedel5d450802008-12-03 14:52:32 +01003014 dmar_domain = iommu_alloc_vm_domain();
3015 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003016 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003017 "intel_iommu_domain_init: dmar_domain == NULL\n");
3018 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003019 }
Joerg Roedel5d450802008-12-03 14:52:32 +01003020 if (vm_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003021 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003022 "intel_iommu_domain_init() failed\n");
3023 vm_domain_exit(dmar_domain);
3024 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003025 }
Joerg Roedel5d450802008-12-03 14:52:32 +01003026 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003027
Joerg Roedel5d450802008-12-03 14:52:32 +01003028 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003029}
Kay, Allen M38717942008-09-09 18:37:29 +03003030
Joerg Roedel5d450802008-12-03 14:52:32 +01003031static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003032{
Joerg Roedel5d450802008-12-03 14:52:32 +01003033 struct dmar_domain *dmar_domain = domain->priv;
3034
3035 domain->priv = NULL;
3036 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003037}
Kay, Allen M38717942008-09-09 18:37:29 +03003038
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003039static int intel_iommu_attach_device(struct iommu_domain *domain,
3040 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003041{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003042 struct dmar_domain *dmar_domain = domain->priv;
3043 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003044 struct intel_iommu *iommu;
3045 int addr_width;
3046 u64 end;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003047 int ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003048
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003049 /* normally pdev is not mapped */
3050 if (unlikely(domain_context_mapped(pdev))) {
3051 struct dmar_domain *old_domain;
3052
3053 old_domain = find_domain(pdev);
3054 if (old_domain) {
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003055 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003056 vm_domain_remove_one_dev_info(old_domain, pdev);
3057 else
3058 domain_remove_dev_info(old_domain);
3059 }
3060 }
3061
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003062 iommu = device_to_iommu(pdev->bus->number, pdev->devfn);
3063 if (!iommu)
3064 return -ENODEV;
3065
3066 /* check if this iommu agaw is sufficient for max mapped address */
3067 addr_width = agaw_to_width(iommu->agaw);
3068 end = DOMAIN_MAX_ADDR(addr_width);
3069 end = end & VTD_PAGE_MASK;
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003070 if (end < dmar_domain->max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003071 printk(KERN_ERR "%s: iommu agaw (%d) is not "
3072 "sufficient for the mapped address (%llx)\n",
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003073 __func__, iommu->agaw, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003074 return -EFAULT;
3075 }
3076
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003077 ret = domain_context_mapping(dmar_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003078 if (ret)
3079 return ret;
3080
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003081 ret = vm_domain_add_dev_info(dmar_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003082 return ret;
3083}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003084
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003085static void intel_iommu_detach_device(struct iommu_domain *domain,
3086 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003087{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003088 struct dmar_domain *dmar_domain = domain->priv;
3089 struct pci_dev *pdev = to_pci_dev(dev);
3090
3091 vm_domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003092}
Kay, Allen M38717942008-09-09 18:37:29 +03003093
Joerg Roedeldde57a22008-12-03 15:04:09 +01003094static int intel_iommu_map_range(struct iommu_domain *domain,
3095 unsigned long iova, phys_addr_t hpa,
3096 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003097{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003098 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003099 u64 max_addr;
3100 int addr_width;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003101 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003102 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003103
Joerg Roedeldde57a22008-12-03 15:04:09 +01003104 if (iommu_prot & IOMMU_READ)
3105 prot |= DMA_PTE_READ;
3106 if (iommu_prot & IOMMU_WRITE)
3107 prot |= DMA_PTE_WRITE;
3108
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003109 max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size);
Joerg Roedeldde57a22008-12-03 15:04:09 +01003110 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003111 int min_agaw;
3112 u64 end;
3113
3114 /* check if minimum agaw is sufficient for mapped address */
Joerg Roedeldde57a22008-12-03 15:04:09 +01003115 min_agaw = vm_domain_min_agaw(dmar_domain);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003116 addr_width = agaw_to_width(min_agaw);
3117 end = DOMAIN_MAX_ADDR(addr_width);
3118 end = end & VTD_PAGE_MASK;
3119 if (end < max_addr) {
3120 printk(KERN_ERR "%s: iommu agaw (%d) is not "
3121 "sufficient for the mapped address (%llx)\n",
3122 __func__, min_agaw, max_addr);
3123 return -EFAULT;
3124 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003125 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003126 }
3127
Joerg Roedeldde57a22008-12-03 15:04:09 +01003128 ret = domain_page_mapping(dmar_domain, iova, hpa, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003129 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003130}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003131
Joerg Roedeldde57a22008-12-03 15:04:09 +01003132static void intel_iommu_unmap_range(struct iommu_domain *domain,
3133 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003134{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003135 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003136 dma_addr_t base;
3137
3138 /* The address might not be aligned */
3139 base = iova & VTD_PAGE_MASK;
3140 size = VTD_PAGE_ALIGN(size);
Joerg Roedeldde57a22008-12-03 15:04:09 +01003141 dma_pte_clear_range(dmar_domain, base, base + size);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003142
Joerg Roedeldde57a22008-12-03 15:04:09 +01003143 if (dmar_domain->max_addr == base + size)
3144 dmar_domain->max_addr = base;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003145}
Kay, Allen M38717942008-09-09 18:37:29 +03003146
Joerg Roedeld14d6572008-12-03 15:06:57 +01003147static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
3148 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03003149{
Joerg Roedeld14d6572008-12-03 15:06:57 +01003150 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03003151 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003152 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003153
Joerg Roedeld14d6572008-12-03 15:06:57 +01003154 pte = addr_to_dma_pte(dmar_domain, iova);
Kay, Allen M38717942008-09-09 18:37:29 +03003155 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003156 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03003157
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003158 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03003159}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003160
3161static struct iommu_ops intel_iommu_ops = {
3162 .domain_init = intel_iommu_domain_init,
3163 .domain_destroy = intel_iommu_domain_destroy,
3164 .attach_dev = intel_iommu_attach_device,
3165 .detach_dev = intel_iommu_detach_device,
3166 .map = intel_iommu_map_range,
3167 .unmap = intel_iommu_unmap_range,
3168 .iova_to_phys = intel_iommu_iova_to_phys,
3169};
David Woodhouse9af88142009-02-13 23:18:03 +00003170
3171static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
3172{
3173 /*
3174 * Mobile 4 Series Chipset neglects to set RWBF capability,
3175 * but needs it:
3176 */
3177 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
3178 rwbf_quirk = 1;
3179}
3180
3181DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);