blob: 83cabdc118dba815d10643179385ce690e7f6b6d [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>
Fenghua Yuf59c7b62009-03-27 14:22:42 -070039#include <linux/sysdev.h>
Shane Wang69575d32009-09-01 18:25:07 -070040#include <linux/tboot.h>
Stephen Rothwelladb2fe02009-08-31 15:24:23 +100041#include <linux/dmi.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070042#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090043#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070044#include "pci.h"
45
Fenghua Yu5b6985c2008-10-16 18:02:32 -070046#define ROOT_SIZE VTD_PAGE_SIZE
47#define CONTEXT_SIZE VTD_PAGE_SIZE
48
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070049#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
50#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070051#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070052
53#define IOAPIC_RANGE_START (0xfee00000)
54#define IOAPIC_RANGE_END (0xfeefffff)
55#define IOVA_START_ADDR (0x1000)
56
57#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
58
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070059#define MAX_AGAW_WIDTH 64
60
David Woodhouse2ebe3152009-09-19 07:34:04 -070061#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
62#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
63
64/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
65 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
66#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
67 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
68#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070069
Mark McLoughlinf27be032008-11-20 15:49:43 +000070#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070071#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070072#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080073
David Woodhousefd18de52009-05-10 23:57:41 +010074
David Woodhousedd4e8312009-06-27 16:21:20 +010075/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
76 are never going to work. */
77static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
78{
79 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
80}
81
82static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
83{
84 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
85}
86static inline unsigned long page_to_dma_pfn(struct page *pg)
87{
88 return mm_to_dma_pfn(page_to_pfn(pg));
89}
90static inline unsigned long virt_to_dma_pfn(void *p)
91{
92 return page_to_dma_pfn(virt_to_page(p));
93}
94
Weidong Hand9630fe2008-12-08 11:06:32 +080095/* global iommu list, set NULL for ignored DMAR units */
96static struct intel_iommu **g_iommus;
97
David Woodhousee0fc7e02009-09-30 09:12:17 -070098static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +000099static int rwbf_quirk;
100
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000101/*
102 * 0: Present
103 * 1-11: Reserved
104 * 12-63: Context Ptr (12 - (haw-1))
105 * 64-127: Reserved
106 */
107struct root_entry {
108 u64 val;
109 u64 rsvd1;
110};
111#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
112static inline bool root_present(struct root_entry *root)
113{
114 return (root->val & 1);
115}
116static inline void set_root_present(struct root_entry *root)
117{
118 root->val |= 1;
119}
120static inline void set_root_value(struct root_entry *root, unsigned long value)
121{
122 root->val |= value & VTD_PAGE_MASK;
123}
124
125static inline struct context_entry *
126get_context_addr_from_root(struct root_entry *root)
127{
128 return (struct context_entry *)
129 (root_present(root)?phys_to_virt(
130 root->val & VTD_PAGE_MASK) :
131 NULL);
132}
133
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000134/*
135 * low 64 bits:
136 * 0: present
137 * 1: fault processing disable
138 * 2-3: translation type
139 * 12-63: address space root
140 * high 64 bits:
141 * 0-2: address width
142 * 3-6: aval
143 * 8-23: domain id
144 */
145struct context_entry {
146 u64 lo;
147 u64 hi;
148};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000149
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000150static inline bool context_present(struct context_entry *context)
151{
152 return (context->lo & 1);
153}
154static inline void context_set_present(struct context_entry *context)
155{
156 context->lo |= 1;
157}
158
159static inline void context_set_fault_enable(struct context_entry *context)
160{
161 context->lo &= (((u64)-1) << 2) | 1;
162}
163
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000164static inline void context_set_translation_type(struct context_entry *context,
165 unsigned long value)
166{
167 context->lo &= (((u64)-1) << 4) | 3;
168 context->lo |= (value & 3) << 2;
169}
170
171static inline void context_set_address_root(struct context_entry *context,
172 unsigned long value)
173{
174 context->lo |= value & VTD_PAGE_MASK;
175}
176
177static inline void context_set_address_width(struct context_entry *context,
178 unsigned long value)
179{
180 context->hi |= value & 7;
181}
182
183static inline void context_set_domain_id(struct context_entry *context,
184 unsigned long value)
185{
186 context->hi |= (value & ((1 << 16) - 1)) << 8;
187}
188
189static inline void context_clear_entry(struct context_entry *context)
190{
191 context->lo = 0;
192 context->hi = 0;
193}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000194
Mark McLoughlin622ba122008-11-20 15:49:46 +0000195/*
196 * 0: readable
197 * 1: writable
198 * 2-6: reserved
199 * 7: super page
Sheng Yang9cf06692009-03-18 15:33:07 +0800200 * 8-10: available
201 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000202 * 12-63: Host physcial address
203 */
204struct dma_pte {
205 u64 val;
206};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000207
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000208static inline void dma_clear_pte(struct dma_pte *pte)
209{
210 pte->val = 0;
211}
212
213static inline void dma_set_pte_readable(struct dma_pte *pte)
214{
215 pte->val |= DMA_PTE_READ;
216}
217
218static inline void dma_set_pte_writable(struct dma_pte *pte)
219{
220 pte->val |= DMA_PTE_WRITE;
221}
222
Sheng Yang9cf06692009-03-18 15:33:07 +0800223static inline void dma_set_pte_snp(struct dma_pte *pte)
224{
225 pte->val |= DMA_PTE_SNP;
226}
227
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000228static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
229{
230 pte->val = (pte->val & ~3) | (prot & 3);
231}
232
233static inline u64 dma_pte_addr(struct dma_pte *pte)
234{
David Woodhousec85994e2009-07-01 19:21:24 +0100235#ifdef CONFIG_64BIT
236 return pte->val & VTD_PAGE_MASK;
237#else
238 /* Must have a full atomic 64-bit read */
239 return __cmpxchg64(pte, 0ULL, 0ULL) & VTD_PAGE_MASK;
240#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000241}
242
David Woodhousedd4e8312009-06-27 16:21:20 +0100243static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000244{
David Woodhousedd4e8312009-06-27 16:21:20 +0100245 pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000246}
247
248static inline bool dma_pte_present(struct dma_pte *pte)
249{
250 return (pte->val & 3) != 0;
251}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000252
David Woodhouse75e6bf92009-07-02 11:21:16 +0100253static inline int first_pte_in_page(struct dma_pte *pte)
254{
255 return !((unsigned long)pte & ~VTD_PAGE_MASK);
256}
257
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700258/*
259 * This domain is a statically identity mapping domain.
260 * 1. This domain creats a static 1:1 mapping to all usable memory.
261 * 2. It maps to each iommu if successful.
262 * 3. Each iommu mapps to this domain if successful.
263 */
David Woodhouse19943b02009-08-04 16:19:20 +0100264static struct dmar_domain *si_domain;
265static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700266
Weidong Han3b5410e2008-12-08 09:17:15 +0800267/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100268#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800269
Weidong Han1ce28fe2008-12-08 16:35:39 +0800270/* domain represents a virtual machine, more than one devices
271 * across iommus may be owned in one domain, e.g. kvm guest.
272 */
273#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
274
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700275/* si_domain contains mulitple devices */
276#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
277
Mark McLoughlin99126f72008-11-20 15:49:47 +0000278struct dmar_domain {
279 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700280 int nid; /* node id */
Weidong Han8c11e792008-12-08 15:29:22 +0800281 unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000282
283 struct list_head devices; /* all devices' list */
284 struct iova_domain iovad; /* iova's that belong to this domain */
285
286 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000287 int gaw; /* max guest address width */
288
289 /* adjusted guest address width, 0 is level 2 30-bit */
290 int agaw;
291
Weidong Han3b5410e2008-12-08 09:17:15 +0800292 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800293
294 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800295 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800296 int iommu_count; /* reference count of iommu */
297 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800298 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000299};
300
Mark McLoughlina647dac2008-11-20 15:49:48 +0000301/* PCI domain-device relationship */
302struct device_domain_info {
303 struct list_head link; /* link to domain siblings */
304 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100305 int segment; /* PCI domain */
306 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000307 u8 devfn; /* PCI devfn number */
308 struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800309 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000310 struct dmar_domain *domain; /* pointer to domain */
311};
312
mark gross5e0d2a62008-03-04 15:22:08 -0800313static void flush_unmaps_timeout(unsigned long data);
314
315DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
316
mark gross80b20dd2008-04-18 13:53:58 -0700317#define HIGH_WATER_MARK 250
318struct deferred_flush_tables {
319 int next;
320 struct iova *iova[HIGH_WATER_MARK];
321 struct dmar_domain *domain[HIGH_WATER_MARK];
322};
323
324static struct deferred_flush_tables *deferred_flush;
325
mark gross5e0d2a62008-03-04 15:22:08 -0800326/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800327static int g_num_of_iommus;
328
329static DEFINE_SPINLOCK(async_umap_flush_lock);
330static LIST_HEAD(unmaps_to_do);
331
332static int timer_on;
333static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800334
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700335static void domain_remove_dev_info(struct dmar_domain *domain);
336
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800337#ifdef CONFIG_DMAR_DEFAULT_ON
338int dmar_disabled = 0;
339#else
340int dmar_disabled = 1;
341#endif /*CONFIG_DMAR_DEFAULT_ON*/
342
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700343static int __initdata dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700344static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800345static int intel_iommu_strict;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700346
347#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
348static DEFINE_SPINLOCK(device_domain_lock);
349static LIST_HEAD(device_domain_list);
350
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100351static struct iommu_ops intel_iommu_ops;
352
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700353static int __init intel_iommu_setup(char *str)
354{
355 if (!str)
356 return -EINVAL;
357 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800358 if (!strncmp(str, "on", 2)) {
359 dmar_disabled = 0;
360 printk(KERN_INFO "Intel-IOMMU: enabled\n");
361 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700362 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800363 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700364 } else if (!strncmp(str, "igfx_off", 8)) {
365 dmar_map_gfx = 0;
366 printk(KERN_INFO
367 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700368 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800369 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700370 "Intel-IOMMU: Forcing DAC for PCI devices\n");
371 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800372 } else if (!strncmp(str, "strict", 6)) {
373 printk(KERN_INFO
374 "Intel-IOMMU: disable batched IOTLB flush\n");
375 intel_iommu_strict = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700376 }
377
378 str += strcspn(str, ",");
379 while (*str == ',')
380 str++;
381 }
382 return 0;
383}
384__setup("intel_iommu=", intel_iommu_setup);
385
386static struct kmem_cache *iommu_domain_cache;
387static struct kmem_cache *iommu_devinfo_cache;
388static struct kmem_cache *iommu_iova_cache;
389
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700390static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep)
391{
392 unsigned int flags;
393 void *vaddr;
394
395 /* trying to avoid low memory issues */
396 flags = current->flags & PF_MEMALLOC;
397 current->flags |= PF_MEMALLOC;
398 vaddr = kmem_cache_alloc(cachep, GFP_ATOMIC);
399 current->flags &= (~PF_MEMALLOC | flags);
400 return vaddr;
401}
402
403
Suresh Siddha4c923d42009-10-02 11:01:24 -0700404static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700405{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700406 unsigned int flags;
Suresh Siddha4c923d42009-10-02 11:01:24 -0700407 struct page *page;
408 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700409
410 /* trying to avoid low memory issues */
411 flags = current->flags & PF_MEMALLOC;
412 current->flags |= PF_MEMALLOC;
Suresh Siddha4c923d42009-10-02 11:01:24 -0700413 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
414 if (page)
415 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700416 current->flags &= (~PF_MEMALLOC | flags);
417 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700418}
419
420static inline void free_pgtable_page(void *vaddr)
421{
422 free_page((unsigned long)vaddr);
423}
424
425static inline void *alloc_domain_mem(void)
426{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700427 return iommu_kmem_cache_alloc(iommu_domain_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700428}
429
Kay, Allen M38717942008-09-09 18:37:29 +0300430static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700431{
432 kmem_cache_free(iommu_domain_cache, vaddr);
433}
434
435static inline void * alloc_devinfo_mem(void)
436{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700437 return iommu_kmem_cache_alloc(iommu_devinfo_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700438}
439
440static inline void free_devinfo_mem(void *vaddr)
441{
442 kmem_cache_free(iommu_devinfo_cache, vaddr);
443}
444
445struct iova *alloc_iova_mem(void)
446{
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700447 return iommu_kmem_cache_alloc(iommu_iova_cache);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700448}
449
450void free_iova_mem(struct iova *iova)
451{
452 kmem_cache_free(iommu_iova_cache, iova);
453}
454
Weidong Han1b573682008-12-08 15:34:06 +0800455
456static inline int width_to_agaw(int width);
457
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700458static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800459{
460 unsigned long sagaw;
461 int agaw = -1;
462
463 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700464 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800465 agaw >= 0; agaw--) {
466 if (test_bit(agaw, &sagaw))
467 break;
468 }
469
470 return agaw;
471}
472
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700473/*
474 * Calculate max SAGAW for each iommu.
475 */
476int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
477{
478 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
479}
480
481/*
482 * calculate agaw for each iommu.
483 * "SAGAW" may be different across iommus, use a default agaw, and
484 * get a supported less agaw for iommus that don't support the default agaw.
485 */
486int iommu_calculate_agaw(struct intel_iommu *iommu)
487{
488 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
489}
490
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700491/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800492static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
493{
494 int iommu_id;
495
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700496 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800497 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700498 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800499
Weidong Han8c11e792008-12-08 15:29:22 +0800500 iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
501 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
502 return NULL;
503
504 return g_iommus[iommu_id];
505}
506
Weidong Han8e6040972008-12-08 15:49:06 +0800507static void domain_update_iommu_coherency(struct dmar_domain *domain)
508{
509 int i;
510
511 domain->iommu_coherency = 1;
512
513 i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
514 for (; i < g_num_of_iommus; ) {
515 if (!ecap_coherent(g_iommus[i]->ecap)) {
516 domain->iommu_coherency = 0;
517 break;
518 }
519 i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
520 }
521}
522
Sheng Yang58c610b2009-03-18 15:33:05 +0800523static void domain_update_iommu_snooping(struct dmar_domain *domain)
524{
525 int i;
526
527 domain->iommu_snooping = 1;
528
529 i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
530 for (; i < g_num_of_iommus; ) {
531 if (!ecap_sc_support(g_iommus[i]->ecap)) {
532 domain->iommu_snooping = 0;
533 break;
534 }
535 i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
536 }
537}
538
539/* Some capabilities may be different across iommus */
540static void domain_update_iommu_cap(struct dmar_domain *domain)
541{
542 domain_update_iommu_coherency(domain);
543 domain_update_iommu_snooping(domain);
544}
545
David Woodhouse276dbf992009-04-04 01:45:37 +0100546static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800547{
548 struct dmar_drhd_unit *drhd = NULL;
549 int i;
550
551 for_each_drhd_unit(drhd) {
552 if (drhd->ignored)
553 continue;
David Woodhouse276dbf992009-04-04 01:45:37 +0100554 if (segment != drhd->segment)
555 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800556
David Woodhouse924b6232009-04-04 00:39:25 +0100557 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000558 if (drhd->devices[i] &&
559 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800560 drhd->devices[i]->devfn == devfn)
561 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700562 if (drhd->devices[i] &&
563 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100564 drhd->devices[i]->subordinate->number <= bus &&
565 drhd->devices[i]->subordinate->subordinate >= bus)
566 return drhd->iommu;
567 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800568
569 if (drhd->include_all)
570 return drhd->iommu;
571 }
572
573 return NULL;
574}
575
Weidong Han5331fe62008-12-08 23:00:00 +0800576static void domain_flush_cache(struct dmar_domain *domain,
577 void *addr, int size)
578{
579 if (!domain->iommu_coherency)
580 clflush_cache_range(addr, size);
581}
582
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700583/* Gets context entry for a given bus and devfn */
584static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
585 u8 bus, u8 devfn)
586{
587 struct root_entry *root;
588 struct context_entry *context;
589 unsigned long phy_addr;
590 unsigned long flags;
591
592 spin_lock_irqsave(&iommu->lock, flags);
593 root = &iommu->root_entry[bus];
594 context = get_context_addr_from_root(root);
595 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700596 context = (struct context_entry *)
597 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700598 if (!context) {
599 spin_unlock_irqrestore(&iommu->lock, flags);
600 return NULL;
601 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700602 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700603 phy_addr = virt_to_phys((void *)context);
604 set_root_value(root, phy_addr);
605 set_root_present(root);
606 __iommu_flush_cache(iommu, root, sizeof(*root));
607 }
608 spin_unlock_irqrestore(&iommu->lock, flags);
609 return &context[devfn];
610}
611
612static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
613{
614 struct root_entry *root;
615 struct context_entry *context;
616 int ret;
617 unsigned long flags;
618
619 spin_lock_irqsave(&iommu->lock, flags);
620 root = &iommu->root_entry[bus];
621 context = get_context_addr_from_root(root);
622 if (!context) {
623 ret = 0;
624 goto out;
625 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000626 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700627out:
628 spin_unlock_irqrestore(&iommu->lock, flags);
629 return ret;
630}
631
632static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
633{
634 struct root_entry *root;
635 struct context_entry *context;
636 unsigned long flags;
637
638 spin_lock_irqsave(&iommu->lock, flags);
639 root = &iommu->root_entry[bus];
640 context = get_context_addr_from_root(root);
641 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000642 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700643 __iommu_flush_cache(iommu, &context[devfn], \
644 sizeof(*context));
645 }
646 spin_unlock_irqrestore(&iommu->lock, flags);
647}
648
649static void free_context_table(struct intel_iommu *iommu)
650{
651 struct root_entry *root;
652 int i;
653 unsigned long flags;
654 struct context_entry *context;
655
656 spin_lock_irqsave(&iommu->lock, flags);
657 if (!iommu->root_entry) {
658 goto out;
659 }
660 for (i = 0; i < ROOT_ENTRY_NR; i++) {
661 root = &iommu->root_entry[i];
662 context = get_context_addr_from_root(root);
663 if (context)
664 free_pgtable_page(context);
665 }
666 free_pgtable_page(iommu->root_entry);
667 iommu->root_entry = NULL;
668out:
669 spin_unlock_irqrestore(&iommu->lock, flags);
670}
671
672/* page table handling */
673#define LEVEL_STRIDE (9)
674#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
675
676static inline int agaw_to_level(int agaw)
677{
678 return agaw + 2;
679}
680
681static inline int agaw_to_width(int agaw)
682{
683 return 30 + agaw * LEVEL_STRIDE;
684
685}
686
687static inline int width_to_agaw(int width)
688{
689 return (width - 30) / LEVEL_STRIDE;
690}
691
692static inline unsigned int level_to_offset_bits(int level)
693{
David Woodhouse6660c632009-06-27 22:41:00 +0100694 return (level - 1) * LEVEL_STRIDE;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700695}
696
David Woodhouse77dfa562009-06-27 16:40:08 +0100697static inline int pfn_level_offset(unsigned long pfn, int level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700698{
David Woodhouse6660c632009-06-27 22:41:00 +0100699 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700700}
701
David Woodhouse6660c632009-06-27 22:41:00 +0100702static inline unsigned long level_mask(int level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700703{
David Woodhouse6660c632009-06-27 22:41:00 +0100704 return -1UL << level_to_offset_bits(level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700705}
706
David Woodhouse6660c632009-06-27 22:41:00 +0100707static inline unsigned long level_size(int level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700708{
David Woodhouse6660c632009-06-27 22:41:00 +0100709 return 1UL << level_to_offset_bits(level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700710}
711
David Woodhouse6660c632009-06-27 22:41:00 +0100712static inline unsigned long align_to_level(unsigned long pfn, int level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700713{
David Woodhouse6660c632009-06-27 22:41:00 +0100714 return (pfn + level_size(level) - 1) & level_mask(level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700715}
716
David Woodhouseb026fd22009-06-28 10:37:25 +0100717static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
718 unsigned long pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700719{
David Woodhouseb026fd22009-06-28 10:37:25 +0100720 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700721 struct dma_pte *parent, *pte = NULL;
722 int level = agaw_to_level(domain->agaw);
723 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700724
725 BUG_ON(!domain->pgd);
David Woodhouseb026fd22009-06-28 10:37:25 +0100726 BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700727 parent = domain->pgd;
728
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700729 while (level > 0) {
730 void *tmp_page;
731
David Woodhouseb026fd22009-06-28 10:37:25 +0100732 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700733 pte = &parent[offset];
734 if (level == 1)
735 break;
736
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000737 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100738 uint64_t pteval;
739
Suresh Siddha4c923d42009-10-02 11:01:24 -0700740 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700741
David Woodhouse206a73c2009-07-01 19:30:28 +0100742 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700743 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100744
David Woodhousec85994e2009-07-01 19:21:24 +0100745 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400746 pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
David Woodhousec85994e2009-07-01 19:21:24 +0100747 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
748 /* Someone else set it while we were thinking; use theirs. */
749 free_pgtable_page(tmp_page);
750 } else {
751 dma_pte_addr(pte);
752 domain_flush_cache(domain, pte, sizeof(*pte));
753 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700754 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000755 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700756 level--;
757 }
758
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700759 return pte;
760}
761
762/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100763static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
764 unsigned long pfn,
765 int level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700766{
767 struct dma_pte *parent, *pte = NULL;
768 int total = agaw_to_level(domain->agaw);
769 int offset;
770
771 parent = domain->pgd;
772 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100773 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700774 pte = &parent[offset];
775 if (level == total)
776 return pte;
777
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000778 if (!dma_pte_present(pte))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700779 break;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000780 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700781 total--;
782 }
783 return NULL;
784}
785
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700786/* clear last level pte, a tlb flush should be followed */
David Woodhouse595badf2009-06-27 22:09:11 +0100787static void dma_pte_clear_range(struct dmar_domain *domain,
788 unsigned long start_pfn,
789 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700790{
David Woodhouse04b18e62009-06-27 19:15:01 +0100791 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100792 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700793
David Woodhouse04b18e62009-06-27 19:15:01 +0100794 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100795 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700796 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100797
David Woodhouse04b18e62009-06-27 19:15:01 +0100798 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700799 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100800 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
801 if (!pte) {
802 start_pfn = align_to_level(start_pfn + 1, 2);
803 continue;
804 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100805 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100806 dma_clear_pte(pte);
807 start_pfn++;
808 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100809 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
810
David Woodhouse310a5ab2009-06-28 18:52:20 +0100811 domain_flush_cache(domain, first_pte,
812 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700813
814 } while (start_pfn && start_pfn <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700815}
816
817/* free page table pages. last level pte should already be cleared */
818static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100819 unsigned long start_pfn,
820 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700821{
David Woodhouse6660c632009-06-27 22:41:00 +0100822 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhousef3a0a522009-06-30 03:40:07 +0100823 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700824 int total = agaw_to_level(domain->agaw);
825 int level;
David Woodhouse6660c632009-06-27 22:41:00 +0100826 unsigned long tmp;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700827
David Woodhouse6660c632009-06-27 22:41:00 +0100828 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
829 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700830 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700831
David Woodhousef3a0a522009-06-30 03:40:07 +0100832 /* We don't need lock here; nobody else touches the iova range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700833 level = 2;
834 while (level <= total) {
David Woodhouse6660c632009-06-27 22:41:00 +0100835 tmp = align_to_level(start_pfn, level);
836
David Woodhousef3a0a522009-06-30 03:40:07 +0100837 /* If we can't even clear one PTE at this level, we're done */
David Woodhouse6660c632009-06-27 22:41:00 +0100838 if (tmp + level_size(level) - 1 > last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700839 return;
840
David Woodhouse59c36282009-09-19 07:36:28 -0700841 do {
David Woodhousef3a0a522009-06-30 03:40:07 +0100842 first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
843 if (!pte) {
844 tmp = align_to_level(tmp + 1, level + 1);
845 continue;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700846 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100847 do {
David Woodhouse6a43e572009-07-02 12:02:34 +0100848 if (dma_pte_present(pte)) {
849 free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
850 dma_clear_pte(pte);
851 }
David Woodhousef3a0a522009-06-30 03:40:07 +0100852 pte++;
853 tmp += level_size(level);
David Woodhouse75e6bf92009-07-02 11:21:16 +0100854 } while (!first_pte_in_page(pte) &&
855 tmp + level_size(level) - 1 <= last_pfn);
856
David Woodhousef3a0a522009-06-30 03:40:07 +0100857 domain_flush_cache(domain, first_pte,
858 (void *)pte - (void *)first_pte);
859
David Woodhouse59c36282009-09-19 07:36:28 -0700860 } while (tmp && tmp + level_size(level) - 1 <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700861 level++;
862 }
863 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100864 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700865 free_pgtable_page(domain->pgd);
866 domain->pgd = NULL;
867 }
868}
869
870/* iommu handling */
871static int iommu_alloc_root_entry(struct intel_iommu *iommu)
872{
873 struct root_entry *root;
874 unsigned long flags;
875
Suresh Siddha4c923d42009-10-02 11:01:24 -0700876 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700877 if (!root)
878 return -ENOMEM;
879
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700880 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700881
882 spin_lock_irqsave(&iommu->lock, flags);
883 iommu->root_entry = root;
884 spin_unlock_irqrestore(&iommu->lock, flags);
885
886 return 0;
887}
888
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700889static void iommu_set_root_entry(struct intel_iommu *iommu)
890{
891 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100892 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700893 unsigned long flag;
894
895 addr = iommu->root_entry;
896
897 spin_lock_irqsave(&iommu->register_lock, flag);
898 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
899
David Woodhousec416daa2009-05-10 20:30:58 +0100900 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700901
902 /* Make sure hardware complete it */
903 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100904 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700905
906 spin_unlock_irqrestore(&iommu->register_lock, flag);
907}
908
909static void iommu_flush_write_buffer(struct intel_iommu *iommu)
910{
911 u32 val;
912 unsigned long flag;
913
David Woodhouse9af88142009-02-13 23:18:03 +0000914 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700915 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700916
917 spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100918 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700919
920 /* Make sure hardware complete it */
921 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100922 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700923
924 spin_unlock_irqrestore(&iommu->register_lock, flag);
925}
926
927/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +0100928static void __iommu_flush_context(struct intel_iommu *iommu,
929 u16 did, u16 source_id, u8 function_mask,
930 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700931{
932 u64 val = 0;
933 unsigned long flag;
934
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700935 switch (type) {
936 case DMA_CCMD_GLOBAL_INVL:
937 val = DMA_CCMD_GLOBAL_INVL;
938 break;
939 case DMA_CCMD_DOMAIN_INVL:
940 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
941 break;
942 case DMA_CCMD_DEVICE_INVL:
943 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
944 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
945 break;
946 default:
947 BUG();
948 }
949 val |= DMA_CCMD_ICC;
950
951 spin_lock_irqsave(&iommu->register_lock, flag);
952 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
953
954 /* Make sure hardware complete it */
955 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
956 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
957
958 spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700959}
960
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700961/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +0100962static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
963 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700964{
965 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
966 u64 val = 0, val_iva = 0;
967 unsigned long flag;
968
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700969 switch (type) {
970 case DMA_TLB_GLOBAL_FLUSH:
971 /* global flush doesn't need set IVA_REG */
972 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
973 break;
974 case DMA_TLB_DSI_FLUSH:
975 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
976 break;
977 case DMA_TLB_PSI_FLUSH:
978 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
979 /* Note: always flush non-leaf currently */
980 val_iva = size_order | addr;
981 break;
982 default:
983 BUG();
984 }
985 /* Note: set drain read/write */
986#if 0
987 /*
988 * This is probably to be super secure.. Looks like we can
989 * ignore it without any impact.
990 */
991 if (cap_read_drain(iommu->cap))
992 val |= DMA_TLB_READ_DRAIN;
993#endif
994 if (cap_write_drain(iommu->cap))
995 val |= DMA_TLB_WRITE_DRAIN;
996
997 spin_lock_irqsave(&iommu->register_lock, flag);
998 /* Note: Only uses first TLB reg currently */
999 if (val_iva)
1000 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1001 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1002
1003 /* Make sure hardware complete it */
1004 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1005 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1006
1007 spin_unlock_irqrestore(&iommu->register_lock, flag);
1008
1009 /* check IOTLB invalidation granularity */
1010 if (DMA_TLB_IAIG(val) == 0)
1011 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1012 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1013 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001014 (unsigned long long)DMA_TLB_IIRG(type),
1015 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001016}
1017
Yu Zhao93a23a72009-05-18 13:51:37 +08001018static struct device_domain_info *iommu_support_dev_iotlb(
1019 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001020{
Yu Zhao93a23a72009-05-18 13:51:37 +08001021 int found = 0;
1022 unsigned long flags;
1023 struct device_domain_info *info;
1024 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1025
1026 if (!ecap_dev_iotlb_support(iommu->ecap))
1027 return NULL;
1028
1029 if (!iommu->qi)
1030 return NULL;
1031
1032 spin_lock_irqsave(&device_domain_lock, flags);
1033 list_for_each_entry(info, &domain->devices, link)
1034 if (info->bus == bus && info->devfn == devfn) {
1035 found = 1;
1036 break;
1037 }
1038 spin_unlock_irqrestore(&device_domain_lock, flags);
1039
1040 if (!found || !info->dev)
1041 return NULL;
1042
1043 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1044 return NULL;
1045
1046 if (!dmar_find_matched_atsr_unit(info->dev))
1047 return NULL;
1048
1049 info->iommu = iommu;
1050
1051 return info;
1052}
1053
1054static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1055{
1056 if (!info)
1057 return;
1058
1059 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1060}
1061
1062static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1063{
1064 if (!info->dev || !pci_ats_enabled(info->dev))
1065 return;
1066
1067 pci_disable_ats(info->dev);
1068}
1069
1070static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1071 u64 addr, unsigned mask)
1072{
1073 u16 sid, qdep;
1074 unsigned long flags;
1075 struct device_domain_info *info;
1076
1077 spin_lock_irqsave(&device_domain_lock, flags);
1078 list_for_each_entry(info, &domain->devices, link) {
1079 if (!info->dev || !pci_ats_enabled(info->dev))
1080 continue;
1081
1082 sid = info->bus << 8 | info->devfn;
1083 qdep = pci_ats_queue_depth(info->dev);
1084 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1085 }
1086 spin_unlock_irqrestore(&device_domain_lock, flags);
1087}
1088
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001089static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
David Woodhouse03d6a242009-06-28 15:33:46 +01001090 unsigned long pfn, unsigned int pages)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001091{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001092 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001093 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001094
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001095 BUG_ON(pages == 0);
1096
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001097 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001098 * Fallback to domain selective flush if no PSI support or the size is
1099 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001100 * PSI requires page size to be 2 ^ x, and the base address is naturally
1101 * aligned to the size
1102 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001103 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1104 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001105 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001106 else
1107 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1108 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001109
1110 /*
1111 * In caching mode, domain ID 0 is reserved for non-present to present
1112 * mapping flush. Device IOTLB doesn't need to be flushed in this case.
1113 */
1114 if (!cap_caching_mode(iommu->cap) || did)
Yu Zhao93a23a72009-05-18 13:51:37 +08001115 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001116}
1117
mark grossf8bab732008-02-08 04:18:38 -08001118static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1119{
1120 u32 pmen;
1121 unsigned long flags;
1122
1123 spin_lock_irqsave(&iommu->register_lock, flags);
1124 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1125 pmen &= ~DMA_PMEN_EPM;
1126 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1127
1128 /* wait for the protected region status bit to clear */
1129 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1130 readl, !(pmen & DMA_PMEN_PRS), pmen);
1131
1132 spin_unlock_irqrestore(&iommu->register_lock, flags);
1133}
1134
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001135static int iommu_enable_translation(struct intel_iommu *iommu)
1136{
1137 u32 sts;
1138 unsigned long flags;
1139
1140 spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001141 iommu->gcmd |= DMA_GCMD_TE;
1142 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001143
1144 /* Make sure hardware complete it */
1145 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001146 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001147
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001148 spin_unlock_irqrestore(&iommu->register_lock, flags);
1149 return 0;
1150}
1151
1152static int iommu_disable_translation(struct intel_iommu *iommu)
1153{
1154 u32 sts;
1155 unsigned long flag;
1156
1157 spin_lock_irqsave(&iommu->register_lock, flag);
1158 iommu->gcmd &= ~DMA_GCMD_TE;
1159 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1160
1161 /* Make sure hardware complete it */
1162 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001163 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001164
1165 spin_unlock_irqrestore(&iommu->register_lock, flag);
1166 return 0;
1167}
1168
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001169
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001170static int iommu_init_domains(struct intel_iommu *iommu)
1171{
1172 unsigned long ndomains;
1173 unsigned long nlongs;
1174
1175 ndomains = cap_ndoms(iommu->cap);
1176 pr_debug("Number of Domains supportd <%ld>\n", ndomains);
1177 nlongs = BITS_TO_LONGS(ndomains);
1178
Donald Dutile94a91b52009-08-20 16:51:34 -04001179 spin_lock_init(&iommu->lock);
1180
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001181 /* TBD: there might be 64K domains,
1182 * consider other allocation for future chip
1183 */
1184 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1185 if (!iommu->domain_ids) {
1186 printk(KERN_ERR "Allocating domain id array failed\n");
1187 return -ENOMEM;
1188 }
1189 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1190 GFP_KERNEL);
1191 if (!iommu->domains) {
1192 printk(KERN_ERR "Allocating domain array failed\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001193 return -ENOMEM;
1194 }
1195
1196 /*
1197 * if Caching mode is set, then invalid translations are tagged
1198 * with domainid 0. Hence we need to pre-allocate it.
1199 */
1200 if (cap_caching_mode(iommu->cap))
1201 set_bit(0, iommu->domain_ids);
1202 return 0;
1203}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001204
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001205
1206static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001207static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001208
1209void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001210{
1211 struct dmar_domain *domain;
1212 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001213 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001214
Donald Dutile94a91b52009-08-20 16:51:34 -04001215 if ((iommu->domains) && (iommu->domain_ids)) {
1216 i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
1217 for (; i < cap_ndoms(iommu->cap); ) {
1218 domain = iommu->domains[i];
1219 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001220
Donald Dutile94a91b52009-08-20 16:51:34 -04001221 spin_lock_irqsave(&domain->iommu_lock, flags);
1222 if (--domain->iommu_count == 0) {
1223 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1224 vm_domain_exit(domain);
1225 else
1226 domain_exit(domain);
1227 }
1228 spin_unlock_irqrestore(&domain->iommu_lock, flags);
1229
1230 i = find_next_bit(iommu->domain_ids,
1231 cap_ndoms(iommu->cap), i+1);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001232 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001233 }
1234
1235 if (iommu->gcmd & DMA_GCMD_TE)
1236 iommu_disable_translation(iommu);
1237
1238 if (iommu->irq) {
1239 set_irq_data(iommu->irq, NULL);
1240 /* This will mask the irq */
1241 free_irq(iommu->irq, iommu);
1242 destroy_irq(iommu->irq);
1243 }
1244
1245 kfree(iommu->domains);
1246 kfree(iommu->domain_ids);
1247
Weidong Hand9630fe2008-12-08 11:06:32 +08001248 g_iommus[iommu->seq_id] = NULL;
1249
1250 /* if all iommus are freed, free g_iommus */
1251 for (i = 0; i < g_num_of_iommus; i++) {
1252 if (g_iommus[i])
1253 break;
1254 }
1255
1256 if (i == g_num_of_iommus)
1257 kfree(g_iommus);
1258
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001259 /* free context mapping */
1260 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001261}
1262
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001263static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001264{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001265 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001266
1267 domain = alloc_domain_mem();
1268 if (!domain)
1269 return NULL;
1270
Suresh Siddha4c923d42009-10-02 11:01:24 -07001271 domain->nid = -1;
Weidong Han8c11e792008-12-08 15:29:22 +08001272 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
Weidong Hand71a2f32008-12-07 21:13:41 +08001273 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001274
1275 return domain;
1276}
1277
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001278static int iommu_attach_domain(struct dmar_domain *domain,
1279 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001280{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001281 int num;
1282 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001283 unsigned long flags;
1284
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001285 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001286
1287 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001288
1289 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1290 if (num >= ndomains) {
1291 spin_unlock_irqrestore(&iommu->lock, flags);
1292 printk(KERN_ERR "IOMMU: no free domain ids\n");
1293 return -ENOMEM;
1294 }
1295
1296 domain->id = num;
1297 set_bit(num, iommu->domain_ids);
1298 set_bit(iommu->seq_id, &domain->iommu_bmp);
1299 iommu->domains[num] = domain;
1300 spin_unlock_irqrestore(&iommu->lock, flags);
1301
1302 return 0;
1303}
1304
1305static void iommu_detach_domain(struct dmar_domain *domain,
1306 struct intel_iommu *iommu)
1307{
1308 unsigned long flags;
1309 int num, ndomains;
1310 int found = 0;
1311
1312 spin_lock_irqsave(&iommu->lock, flags);
1313 ndomains = cap_ndoms(iommu->cap);
1314 num = find_first_bit(iommu->domain_ids, ndomains);
1315 for (; num < ndomains; ) {
1316 if (iommu->domains[num] == domain) {
1317 found = 1;
1318 break;
1319 }
1320 num = find_next_bit(iommu->domain_ids,
1321 cap_ndoms(iommu->cap), num+1);
1322 }
1323
1324 if (found) {
1325 clear_bit(num, iommu->domain_ids);
1326 clear_bit(iommu->seq_id, &domain->iommu_bmp);
1327 iommu->domains[num] = NULL;
1328 }
Weidong Han8c11e792008-12-08 15:29:22 +08001329 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001330}
1331
1332static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001333static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001334
1335static void dmar_init_reserved_ranges(void)
1336{
1337 struct pci_dev *pdev = NULL;
1338 struct iova *iova;
1339 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001340
David Millerf6611972008-02-06 01:36:23 -08001341 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001342
Mark Gross8a443df2008-03-04 14:59:31 -08001343 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1344 &reserved_rbtree_key);
1345
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001346 /* IOAPIC ranges shouldn't be accessed by DMA */
1347 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1348 IOVA_PFN(IOAPIC_RANGE_END));
1349 if (!iova)
1350 printk(KERN_ERR "Reserve IOAPIC range failed\n");
1351
1352 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1353 for_each_pci_dev(pdev) {
1354 struct resource *r;
1355
1356 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1357 r = &pdev->resource[i];
1358 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1359 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001360 iova = reserve_iova(&reserved_iova_list,
1361 IOVA_PFN(r->start),
1362 IOVA_PFN(r->end));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001363 if (!iova)
1364 printk(KERN_ERR "Reserve iova failed\n");
1365 }
1366 }
1367
1368}
1369
1370static void domain_reserve_special_ranges(struct dmar_domain *domain)
1371{
1372 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1373}
1374
1375static inline int guestwidth_to_adjustwidth(int gaw)
1376{
1377 int agaw;
1378 int r = (gaw - 12) % 9;
1379
1380 if (r == 0)
1381 agaw = gaw;
1382 else
1383 agaw = gaw + 9 - r;
1384 if (agaw > 64)
1385 agaw = 64;
1386 return agaw;
1387}
1388
1389static int domain_init(struct dmar_domain *domain, int guest_width)
1390{
1391 struct intel_iommu *iommu;
1392 int adjust_width, agaw;
1393 unsigned long sagaw;
1394
David Millerf6611972008-02-06 01:36:23 -08001395 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001396 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001397
1398 domain_reserve_special_ranges(domain);
1399
1400 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001401 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001402 if (guest_width > cap_mgaw(iommu->cap))
1403 guest_width = cap_mgaw(iommu->cap);
1404 domain->gaw = guest_width;
1405 adjust_width = guestwidth_to_adjustwidth(guest_width);
1406 agaw = width_to_agaw(adjust_width);
1407 sagaw = cap_sagaw(iommu->cap);
1408 if (!test_bit(agaw, &sagaw)) {
1409 /* hardware doesn't support it, choose a bigger one */
1410 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1411 agaw = find_next_bit(&sagaw, 5, agaw);
1412 if (agaw >= 5)
1413 return -ENODEV;
1414 }
1415 domain->agaw = agaw;
1416 INIT_LIST_HEAD(&domain->devices);
1417
Weidong Han8e6040972008-12-08 15:49:06 +08001418 if (ecap_coherent(iommu->ecap))
1419 domain->iommu_coherency = 1;
1420 else
1421 domain->iommu_coherency = 0;
1422
Sheng Yang58c610b2009-03-18 15:33:05 +08001423 if (ecap_sc_support(iommu->ecap))
1424 domain->iommu_snooping = 1;
1425 else
1426 domain->iommu_snooping = 0;
1427
Weidong Hanc7151a82008-12-08 22:51:37 +08001428 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001429 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001430
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001431 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001432 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001433 if (!domain->pgd)
1434 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001435 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001436 return 0;
1437}
1438
1439static void domain_exit(struct dmar_domain *domain)
1440{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001441 struct dmar_drhd_unit *drhd;
1442 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001443
1444 /* Domain 0 is reserved, so dont process it */
1445 if (!domain)
1446 return;
1447
1448 domain_remove_dev_info(domain);
1449 /* destroy iovas */
1450 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001451
1452 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001453 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001454
1455 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001456 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001457
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001458 for_each_active_iommu(iommu, drhd)
1459 if (test_bit(iommu->seq_id, &domain->iommu_bmp))
1460 iommu_detach_domain(domain, iommu);
1461
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001462 free_domain_mem(domain);
1463}
1464
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001465static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1466 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001467{
1468 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001469 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001470 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001471 struct dma_pte *pgd;
1472 unsigned long num;
1473 unsigned long ndomains;
1474 int id;
1475 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001476 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001477
1478 pr_debug("Set context mapping for %02x:%02x.%d\n",
1479 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001480
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001481 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001482 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1483 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001484
David Woodhouse276dbf992009-04-04 01:45:37 +01001485 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001486 if (!iommu)
1487 return -ENODEV;
1488
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001489 context = device_to_context_entry(iommu, bus, devfn);
1490 if (!context)
1491 return -ENOMEM;
1492 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001493 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001494 spin_unlock_irqrestore(&iommu->lock, flags);
1495 return 0;
1496 }
1497
Weidong Hanea6606b2008-12-08 23:08:15 +08001498 id = domain->id;
1499 pgd = domain->pgd;
1500
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001501 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1502 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001503 int found = 0;
1504
1505 /* find an available domain id for this device in iommu */
1506 ndomains = cap_ndoms(iommu->cap);
1507 num = find_first_bit(iommu->domain_ids, ndomains);
1508 for (; num < ndomains; ) {
1509 if (iommu->domains[num] == domain) {
1510 id = num;
1511 found = 1;
1512 break;
1513 }
1514 num = find_next_bit(iommu->domain_ids,
1515 cap_ndoms(iommu->cap), num+1);
1516 }
1517
1518 if (found == 0) {
1519 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1520 if (num >= ndomains) {
1521 spin_unlock_irqrestore(&iommu->lock, flags);
1522 printk(KERN_ERR "IOMMU: no free domain ids\n");
1523 return -EFAULT;
1524 }
1525
1526 set_bit(num, iommu->domain_ids);
1527 iommu->domains[num] = domain;
1528 id = num;
1529 }
1530
1531 /* Skip top levels of page tables for
1532 * iommu which has less agaw than default.
1533 */
1534 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1535 pgd = phys_to_virt(dma_pte_addr(pgd));
1536 if (!dma_pte_present(pgd)) {
1537 spin_unlock_irqrestore(&iommu->lock, flags);
1538 return -ENOMEM;
1539 }
1540 }
1541 }
1542
1543 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001544
Yu Zhao93a23a72009-05-18 13:51:37 +08001545 if (translation != CONTEXT_TT_PASS_THROUGH) {
1546 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1547 translation = info ? CONTEXT_TT_DEV_IOTLB :
1548 CONTEXT_TT_MULTI_LEVEL;
1549 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001550 /*
1551 * In pass through mode, AW must be programmed to indicate the largest
1552 * AGAW value supported by hardware. And ASR is ignored by hardware.
1553 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001554 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001555 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001556 else {
1557 context_set_address_root(context, virt_to_phys(pgd));
1558 context_set_address_width(context, iommu->agaw);
1559 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001560
1561 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001562 context_set_fault_enable(context);
1563 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001564 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001565
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001566 /*
1567 * It's a non-present to present mapping. If hardware doesn't cache
1568 * non-present entry we only need to flush the write-buffer. If the
1569 * _does_ cache non-present entries, then it does so in the special
1570 * domain #0, which we have to flush:
1571 */
1572 if (cap_caching_mode(iommu->cap)) {
1573 iommu->flush.flush_context(iommu, 0,
1574 (((u16)bus) << 8) | devfn,
1575 DMA_CCMD_MASK_NOBIT,
1576 DMA_CCMD_DEVICE_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001577 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001578 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001579 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001580 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001581 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001582 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001583
1584 spin_lock_irqsave(&domain->iommu_lock, flags);
1585 if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
1586 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001587 if (domain->iommu_count == 1)
1588 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001589 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001590 }
1591 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001592 return 0;
1593}
1594
1595static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001596domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1597 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001598{
1599 int ret;
1600 struct pci_dev *tmp, *parent;
1601
David Woodhouse276dbf992009-04-04 01:45:37 +01001602 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001603 pdev->bus->number, pdev->devfn,
1604 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001605 if (ret)
1606 return ret;
1607
1608 /* dependent device mapping */
1609 tmp = pci_find_upstream_pcie_bridge(pdev);
1610 if (!tmp)
1611 return 0;
1612 /* Secondary interface's bus number and devfn 0 */
1613 parent = pdev->bus->self;
1614 while (parent != tmp) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001615 ret = domain_context_mapping_one(domain,
1616 pci_domain_nr(parent->bus),
1617 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001618 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001619 if (ret)
1620 return ret;
1621 parent = parent->bus->self;
1622 }
1623 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
1624 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001625 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001626 tmp->subordinate->number, 0,
1627 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001628 else /* this is a legacy PCI bridge */
1629 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001630 pci_domain_nr(tmp->bus),
1631 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001632 tmp->devfn,
1633 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001634}
1635
Weidong Han5331fe62008-12-08 23:00:00 +08001636static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001637{
1638 int ret;
1639 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001640 struct intel_iommu *iommu;
1641
David Woodhouse276dbf992009-04-04 01:45:37 +01001642 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1643 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001644 if (!iommu)
1645 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001646
David Woodhouse276dbf992009-04-04 01:45:37 +01001647 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001648 if (!ret)
1649 return ret;
1650 /* dependent device mapping */
1651 tmp = pci_find_upstream_pcie_bridge(pdev);
1652 if (!tmp)
1653 return ret;
1654 /* Secondary interface's bus number and devfn 0 */
1655 parent = pdev->bus->self;
1656 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001657 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001658 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001659 if (!ret)
1660 return ret;
1661 parent = parent->bus->self;
1662 }
1663 if (tmp->is_pcie)
David Woodhouse276dbf992009-04-04 01:45:37 +01001664 return device_context_mapped(iommu, tmp->subordinate->number,
1665 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001666 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001667 return device_context_mapped(iommu, tmp->bus->number,
1668 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001669}
1670
Fenghua Yuf5329592009-08-04 15:09:37 -07001671/* Returns a number of VTD pages, but aligned to MM page size */
1672static inline unsigned long aligned_nrpages(unsigned long host_addr,
1673 size_t size)
1674{
1675 host_addr &= ~PAGE_MASK;
1676 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1677}
1678
David Woodhouse9051aa02009-06-29 12:30:54 +01001679static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1680 struct scatterlist *sg, unsigned long phys_pfn,
1681 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001682{
1683 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001684 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001685 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001686 unsigned long sg_res;
David Woodhousee1605492009-06-29 11:17:38 +01001687
1688 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1689
1690 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1691 return -EINVAL;
1692
1693 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1694
David Woodhouse9051aa02009-06-29 12:30:54 +01001695 if (sg)
1696 sg_res = 0;
1697 else {
1698 sg_res = nr_pages + 1;
1699 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1700 }
1701
David Woodhousee1605492009-06-29 11:17:38 +01001702 while (nr_pages--) {
David Woodhousec85994e2009-07-01 19:21:24 +01001703 uint64_t tmp;
1704
David Woodhousee1605492009-06-29 11:17:38 +01001705 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001706 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001707 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1708 sg->dma_length = sg->length;
1709 pteval = page_to_phys(sg_page(sg)) | prot;
1710 }
1711 if (!pte) {
1712 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
1713 if (!pte)
1714 return -ENOMEM;
1715 }
1716 /* We don't need lock here, nobody else
1717 * touches the iova range
1718 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001719 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001720 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001721 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001722 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1723 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001724 if (dumps) {
1725 dumps--;
1726 debug_dma_dump_mappings(NULL);
1727 }
1728 WARN_ON(1);
1729 }
David Woodhousee1605492009-06-29 11:17:38 +01001730 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +01001731 if (!nr_pages || first_pte_in_page(pte)) {
David Woodhousee1605492009-06-29 11:17:38 +01001732 domain_flush_cache(domain, first_pte,
1733 (void *)pte - (void *)first_pte);
1734 pte = NULL;
1735 }
1736 iov_pfn++;
1737 pteval += VTD_PAGE_SIZE;
1738 sg_res--;
1739 if (!sg_res)
1740 sg = sg_next(sg);
1741 }
1742 return 0;
1743}
1744
David Woodhouse9051aa02009-06-29 12:30:54 +01001745static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1746 struct scatterlist *sg, unsigned long nr_pages,
1747 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001748{
David Woodhouse9051aa02009-06-29 12:30:54 +01001749 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1750}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001751
David Woodhouse9051aa02009-06-29 12:30:54 +01001752static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1753 unsigned long phys_pfn, unsigned long nr_pages,
1754 int prot)
1755{
1756 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001757}
1758
Weidong Hanc7151a82008-12-08 22:51:37 +08001759static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001760{
Weidong Hanc7151a82008-12-08 22:51:37 +08001761 if (!iommu)
1762 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001763
1764 clear_context_table(iommu, bus, devfn);
1765 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001766 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001767 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001768}
1769
1770static void domain_remove_dev_info(struct dmar_domain *domain)
1771{
1772 struct device_domain_info *info;
1773 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001774 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001775
1776 spin_lock_irqsave(&device_domain_lock, flags);
1777 while (!list_empty(&domain->devices)) {
1778 info = list_entry(domain->devices.next,
1779 struct device_domain_info, link);
1780 list_del(&info->link);
1781 list_del(&info->global);
1782 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001783 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001784 spin_unlock_irqrestore(&device_domain_lock, flags);
1785
Yu Zhao93a23a72009-05-18 13:51:37 +08001786 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01001787 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001788 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001789 free_devinfo_mem(info);
1790
1791 spin_lock_irqsave(&device_domain_lock, flags);
1792 }
1793 spin_unlock_irqrestore(&device_domain_lock, flags);
1794}
1795
1796/*
1797 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001798 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001799 */
Kay, Allen M38717942008-09-09 18:37:29 +03001800static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001801find_domain(struct pci_dev *pdev)
1802{
1803 struct device_domain_info *info;
1804
1805 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001806 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001807 if (info)
1808 return info->domain;
1809 return NULL;
1810}
1811
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001812/* domain is initialized */
1813static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1814{
1815 struct dmar_domain *domain, *found = NULL;
1816 struct intel_iommu *iommu;
1817 struct dmar_drhd_unit *drhd;
1818 struct device_domain_info *info, *tmp;
1819 struct pci_dev *dev_tmp;
1820 unsigned long flags;
1821 int bus = 0, devfn = 0;
David Woodhouse276dbf992009-04-04 01:45:37 +01001822 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001823 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001824
1825 domain = find_domain(pdev);
1826 if (domain)
1827 return domain;
1828
David Woodhouse276dbf992009-04-04 01:45:37 +01001829 segment = pci_domain_nr(pdev->bus);
1830
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001831 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1832 if (dev_tmp) {
1833 if (dev_tmp->is_pcie) {
1834 bus = dev_tmp->subordinate->number;
1835 devfn = 0;
1836 } else {
1837 bus = dev_tmp->bus->number;
1838 devfn = dev_tmp->devfn;
1839 }
1840 spin_lock_irqsave(&device_domain_lock, flags);
1841 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001842 if (info->segment == segment &&
1843 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001844 found = info->domain;
1845 break;
1846 }
1847 }
1848 spin_unlock_irqrestore(&device_domain_lock, flags);
1849 /* pcie-pci bridge already has a domain, uses it */
1850 if (found) {
1851 domain = found;
1852 goto found_domain;
1853 }
1854 }
1855
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001856 domain = alloc_domain();
1857 if (!domain)
1858 goto error;
1859
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001860 /* Allocate new domain for the device */
1861 drhd = dmar_find_matched_drhd_unit(pdev);
1862 if (!drhd) {
1863 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
1864 pci_name(pdev));
1865 return NULL;
1866 }
1867 iommu = drhd->iommu;
1868
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001869 ret = iommu_attach_domain(domain, iommu);
1870 if (ret) {
1871 domain_exit(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001872 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001873 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001874
1875 if (domain_init(domain, gaw)) {
1876 domain_exit(domain);
1877 goto error;
1878 }
1879
1880 /* register pcie-to-pci device */
1881 if (dev_tmp) {
1882 info = alloc_devinfo_mem();
1883 if (!info) {
1884 domain_exit(domain);
1885 goto error;
1886 }
David Woodhouse276dbf992009-04-04 01:45:37 +01001887 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001888 info->bus = bus;
1889 info->devfn = devfn;
1890 info->dev = NULL;
1891 info->domain = domain;
1892 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08001893 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001894
1895 /* pcie-to-pci bridge already has a domain, uses it */
1896 found = NULL;
1897 spin_lock_irqsave(&device_domain_lock, flags);
1898 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001899 if (tmp->segment == segment &&
1900 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001901 found = tmp->domain;
1902 break;
1903 }
1904 }
1905 if (found) {
1906 free_devinfo_mem(info);
1907 domain_exit(domain);
1908 domain = found;
1909 } else {
1910 list_add(&info->link, &domain->devices);
1911 list_add(&info->global, &device_domain_list);
1912 }
1913 spin_unlock_irqrestore(&device_domain_lock, flags);
1914 }
1915
1916found_domain:
1917 info = alloc_devinfo_mem();
1918 if (!info)
1919 goto error;
David Woodhouse276dbf992009-04-04 01:45:37 +01001920 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001921 info->bus = pdev->bus->number;
1922 info->devfn = pdev->devfn;
1923 info->dev = pdev;
1924 info->domain = domain;
1925 spin_lock_irqsave(&device_domain_lock, flags);
1926 /* somebody is fast */
1927 found = find_domain(pdev);
1928 if (found != NULL) {
1929 spin_unlock_irqrestore(&device_domain_lock, flags);
1930 if (found != domain) {
1931 domain_exit(domain);
1932 domain = found;
1933 }
1934 free_devinfo_mem(info);
1935 return domain;
1936 }
1937 list_add(&info->link, &domain->devices);
1938 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001939 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001940 spin_unlock_irqrestore(&device_domain_lock, flags);
1941 return domain;
1942error:
1943 /* recheck it here, maybe others set it */
1944 return find_domain(pdev);
1945}
1946
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001947static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07001948#define IDENTMAP_ALL 1
1949#define IDENTMAP_GFX 2
1950#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001951
David Woodhouseb2132032009-06-26 18:50:28 +01001952static int iommu_domain_identity_map(struct dmar_domain *domain,
1953 unsigned long long start,
1954 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001955{
David Woodhousec5395d52009-06-28 16:35:56 +01001956 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
1957 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001958
David Woodhousec5395d52009-06-28 16:35:56 +01001959 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
1960 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001961 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01001962 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001963 }
1964
David Woodhousec5395d52009-06-28 16:35:56 +01001965 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
1966 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001967 /*
1968 * RMRR range might have overlap with physical memory range,
1969 * clear it first
1970 */
David Woodhousec5395d52009-06-28 16:35:56 +01001971 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001972
David Woodhousec5395d52009-06-28 16:35:56 +01001973 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
1974 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01001975 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01001976}
1977
1978static int iommu_prepare_identity_map(struct pci_dev *pdev,
1979 unsigned long long start,
1980 unsigned long long end)
1981{
1982 struct dmar_domain *domain;
1983 int ret;
1984
David Woodhousec7ab48d2009-06-26 19:10:36 +01001985 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01001986 if (!domain)
1987 return -ENOMEM;
1988
David Woodhouse19943b02009-08-04 16:19:20 +01001989 /* For _hardware_ passthrough, don't bother. But for software
1990 passthrough, we do it anyway -- it may indicate a memory
1991 range which is reserved in E820, so which didn't get set
1992 up to start with in si_domain */
1993 if (domain == si_domain && hw_pass_through) {
1994 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
1995 pci_name(pdev), start, end);
1996 return 0;
1997 }
1998
1999 printk(KERN_INFO
2000 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2001 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002002
David Woodhouse5595b522009-12-02 09:21:55 +00002003 if (end < start) {
2004 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2005 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2006 dmi_get_system_info(DMI_BIOS_VENDOR),
2007 dmi_get_system_info(DMI_BIOS_VERSION),
2008 dmi_get_system_info(DMI_PRODUCT_VERSION));
2009 ret = -EIO;
2010 goto error;
2011 }
2012
David Woodhouse2ff729f2009-08-26 14:25:41 +01002013 if (end >> agaw_to_width(domain->agaw)) {
2014 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2015 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2016 agaw_to_width(domain->agaw),
2017 dmi_get_system_info(DMI_BIOS_VENDOR),
2018 dmi_get_system_info(DMI_BIOS_VERSION),
2019 dmi_get_system_info(DMI_PRODUCT_VERSION));
2020 ret = -EIO;
2021 goto error;
2022 }
David Woodhouse19943b02009-08-04 16:19:20 +01002023
David Woodhouseb2132032009-06-26 18:50:28 +01002024 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002025 if (ret)
2026 goto error;
2027
2028 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002029 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002030 if (ret)
2031 goto error;
2032
2033 return 0;
2034
2035 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002036 domain_exit(domain);
2037 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002038}
2039
2040static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2041 struct pci_dev *pdev)
2042{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002043 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002044 return 0;
2045 return iommu_prepare_identity_map(pdev, rmrr->base_address,
2046 rmrr->end_address + 1);
2047}
2048
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002049#ifdef CONFIG_DMAR_FLOPPY_WA
2050static inline void iommu_prepare_isa(void)
2051{
2052 struct pci_dev *pdev;
2053 int ret;
2054
2055 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2056 if (!pdev)
2057 return;
2058
David Woodhousec7ab48d2009-06-26 19:10:36 +01002059 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002060 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
2061
2062 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002063 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2064 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002065
2066}
2067#else
2068static inline void iommu_prepare_isa(void)
2069{
2070 return;
2071}
2072#endif /* !CONFIG_DMAR_FLPY_WA */
2073
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002074static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002075
2076static int __init si_domain_work_fn(unsigned long start_pfn,
2077 unsigned long end_pfn, void *datax)
2078{
2079 int *ret = datax;
2080
2081 *ret = iommu_domain_identity_map(si_domain,
2082 (uint64_t)start_pfn << PAGE_SHIFT,
2083 (uint64_t)end_pfn << PAGE_SHIFT);
2084 return *ret;
2085
2086}
2087
Matt Kraai071e1372009-08-23 22:30:22 -07002088static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002089{
2090 struct dmar_drhd_unit *drhd;
2091 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002092 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002093
2094 si_domain = alloc_domain();
2095 if (!si_domain)
2096 return -EFAULT;
2097
David Woodhousec7ab48d2009-06-26 19:10:36 +01002098 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002099
2100 for_each_active_iommu(iommu, drhd) {
2101 ret = iommu_attach_domain(si_domain, iommu);
2102 if (ret) {
2103 domain_exit(si_domain);
2104 return -EFAULT;
2105 }
2106 }
2107
2108 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2109 domain_exit(si_domain);
2110 return -EFAULT;
2111 }
2112
2113 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2114
David Woodhouse19943b02009-08-04 16:19:20 +01002115 if (hw)
2116 return 0;
2117
David Woodhousec7ab48d2009-06-26 19:10:36 +01002118 for_each_online_node(nid) {
2119 work_with_active_regions(nid, si_domain_work_fn, &ret);
2120 if (ret)
2121 return ret;
2122 }
2123
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002124 return 0;
2125}
2126
2127static void domain_remove_one_dev_info(struct dmar_domain *domain,
2128 struct pci_dev *pdev);
2129static int identity_mapping(struct pci_dev *pdev)
2130{
2131 struct device_domain_info *info;
2132
2133 if (likely(!iommu_identity_mapping))
2134 return 0;
2135
2136
2137 list_for_each_entry(info, &si_domain->devices, link)
2138 if (info->dev == pdev)
2139 return 1;
2140 return 0;
2141}
2142
2143static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002144 struct pci_dev *pdev,
2145 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002146{
2147 struct device_domain_info *info;
2148 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002149 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002150
2151 info = alloc_devinfo_mem();
2152 if (!info)
2153 return -ENOMEM;
2154
David Woodhouse5fe60f42009-08-09 10:53:41 +01002155 ret = domain_context_mapping(domain, pdev, translation);
2156 if (ret) {
2157 free_devinfo_mem(info);
2158 return ret;
2159 }
2160
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002161 info->segment = pci_domain_nr(pdev->bus);
2162 info->bus = pdev->bus->number;
2163 info->devfn = pdev->devfn;
2164 info->dev = pdev;
2165 info->domain = domain;
2166
2167 spin_lock_irqsave(&device_domain_lock, flags);
2168 list_add(&info->link, &domain->devices);
2169 list_add(&info->global, &device_domain_list);
2170 pdev->dev.archdata.iommu = info;
2171 spin_unlock_irqrestore(&device_domain_lock, flags);
2172
2173 return 0;
2174}
2175
David Woodhouse6941af22009-07-04 18:24:27 +01002176static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2177{
David Woodhousee0fc7e02009-09-30 09:12:17 -07002178 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2179 return 1;
2180
2181 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2182 return 1;
2183
2184 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2185 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002186
David Woodhouse3dfc8132009-07-04 19:11:08 +01002187 /*
2188 * We want to start off with all devices in the 1:1 domain, and
2189 * take them out later if we find they can't access all of memory.
2190 *
2191 * However, we can't do this for PCI devices behind bridges,
2192 * because all PCI devices behind the same bridge will end up
2193 * with the same source-id on their transactions.
2194 *
2195 * Practically speaking, we can't change things around for these
2196 * devices at run-time, because we can't be sure there'll be no
2197 * DMA transactions in flight for any of their siblings.
2198 *
2199 * So PCI devices (unless they're on the root bus) as well as
2200 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2201 * the 1:1 domain, just in _case_ one of their siblings turns out
2202 * not to be able to map all of memory.
2203 */
2204 if (!pdev->is_pcie) {
2205 if (!pci_is_root_bus(pdev->bus))
2206 return 0;
2207 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2208 return 0;
2209 } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
2210 return 0;
2211
2212 /*
2213 * At boot time, we don't yet know if devices will be 64-bit capable.
2214 * Assume that they will -- if they turn out not to be, then we can
2215 * take them out of the 1:1 domain later.
2216 */
David Woodhouse6941af22009-07-04 18:24:27 +01002217 if (!startup)
2218 return pdev->dma_mask > DMA_BIT_MASK(32);
2219
2220 return 1;
2221}
2222
Matt Kraai071e1372009-08-23 22:30:22 -07002223static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002224{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002225 struct pci_dev *pdev = NULL;
2226 int ret;
2227
David Woodhouse19943b02009-08-04 16:19:20 +01002228 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002229 if (ret)
2230 return -EFAULT;
2231
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002232 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002233 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse19943b02009-08-04 16:19:20 +01002234 printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
2235 hw ? "hardware" : "software", pci_name(pdev));
David Woodhousec7ab48d2009-06-26 19:10:36 +01002236
David Woodhouse5fe60f42009-08-09 10:53:41 +01002237 ret = domain_add_dev_info(si_domain, pdev,
David Woodhouse19943b02009-08-04 16:19:20 +01002238 hw ? CONTEXT_TT_PASS_THROUGH :
David Woodhouse62edf5d2009-07-04 10:59:46 +01002239 CONTEXT_TT_MULTI_LEVEL);
2240 if (ret)
2241 return ret;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002242 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002243 }
2244
2245 return 0;
2246}
2247
2248int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002249{
2250 struct dmar_drhd_unit *drhd;
2251 struct dmar_rmrr_unit *rmrr;
2252 struct pci_dev *pdev;
2253 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002254 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002255
2256 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002257 * for each drhd
2258 * allocate root
2259 * initialize and program root entry to not present
2260 * endfor
2261 */
2262 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002263 g_num_of_iommus++;
2264 /*
2265 * lock not needed as this is only incremented in the single
2266 * threaded kernel __init code path all other access are read
2267 * only
2268 */
2269 }
2270
Weidong Hand9630fe2008-12-08 11:06:32 +08002271 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2272 GFP_KERNEL);
2273 if (!g_iommus) {
2274 printk(KERN_ERR "Allocating global iommu array failed\n");
2275 ret = -ENOMEM;
2276 goto error;
2277 }
2278
mark gross80b20dd2008-04-18 13:53:58 -07002279 deferred_flush = kzalloc(g_num_of_iommus *
2280 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2281 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002282 ret = -ENOMEM;
2283 goto error;
2284 }
2285
mark gross5e0d2a62008-03-04 15:22:08 -08002286 for_each_drhd_unit(drhd) {
2287 if (drhd->ignored)
2288 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002289
2290 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002291 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002292
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002293 ret = iommu_init_domains(iommu);
2294 if (ret)
2295 goto error;
2296
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002297 /*
2298 * TBD:
2299 * we could share the same root & context tables
2300 * amoung all IOMMU's. Need to Split it later.
2301 */
2302 ret = iommu_alloc_root_entry(iommu);
2303 if (ret) {
2304 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2305 goto error;
2306 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002307 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002308 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002309 }
2310
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002311 /*
2312 * Start from the sane iommu hardware state.
2313 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002314 for_each_drhd_unit(drhd) {
2315 if (drhd->ignored)
2316 continue;
2317
2318 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002319
2320 /*
2321 * If the queued invalidation is already initialized by us
2322 * (for example, while enabling interrupt-remapping) then
2323 * we got the things already rolling from a sane state.
2324 */
2325 if (iommu->qi)
2326 continue;
2327
2328 /*
2329 * Clear any previous faults.
2330 */
2331 dmar_fault(-1, iommu);
2332 /*
2333 * Disable queued invalidation if supported and already enabled
2334 * before OS handover.
2335 */
2336 dmar_disable_qi(iommu);
2337 }
2338
2339 for_each_drhd_unit(drhd) {
2340 if (drhd->ignored)
2341 continue;
2342
2343 iommu = drhd->iommu;
2344
Youquan Songa77b67d2008-10-16 16:31:56 -07002345 if (dmar_enable_qi(iommu)) {
2346 /*
2347 * Queued Invalidate not enabled, use Register Based
2348 * Invalidate
2349 */
2350 iommu->flush.flush_context = __iommu_flush_context;
2351 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
2352 printk(KERN_INFO "IOMMU 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002353 "invalidation\n",
2354 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002355 } else {
2356 iommu->flush.flush_context = qi_flush_context;
2357 iommu->flush.flush_iotlb = qi_flush_iotlb;
2358 printk(KERN_INFO "IOMMU 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002359 "invalidation\n",
2360 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002361 }
2362 }
2363
David Woodhouse19943b02009-08-04 16:19:20 +01002364 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002365 iommu_identity_mapping |= IDENTMAP_ALL;
2366
David Woodhouse19943b02009-08-04 16:19:20 +01002367#ifdef CONFIG_DMAR_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002368 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002369#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002370
2371 check_tylersburg_isoch();
2372
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002373 /*
2374 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002375 * identity mappings for rmrr, gfx, and isa and may fall back to static
2376 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002377 */
David Woodhouse19943b02009-08-04 16:19:20 +01002378 if (iommu_identity_mapping) {
2379 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2380 if (ret) {
2381 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2382 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002383 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002384 }
David Woodhouse19943b02009-08-04 16:19:20 +01002385 /*
2386 * For each rmrr
2387 * for each dev attached to rmrr
2388 * do
2389 * locate drhd for dev, alloc domain for dev
2390 * allocate free domain
2391 * allocate page table entries for rmrr
2392 * if context not allocated for bus
2393 * allocate and init context
2394 * set present in root table for this bus
2395 * init context with domain, translation etc
2396 * endfor
2397 * endfor
2398 */
2399 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2400 for_each_rmrr_units(rmrr) {
2401 for (i = 0; i < rmrr->devices_cnt; i++) {
2402 pdev = rmrr->devices[i];
2403 /*
2404 * some BIOS lists non-exist devices in DMAR
2405 * table.
2406 */
2407 if (!pdev)
2408 continue;
2409 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2410 if (ret)
2411 printk(KERN_ERR
2412 "IOMMU: mapping reserved region failed\n");
2413 }
2414 }
2415
2416 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002417
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002418 /*
2419 * for each drhd
2420 * enable fault log
2421 * global invalidate context cache
2422 * global invalidate iotlb
2423 * enable translation
2424 */
2425 for_each_drhd_unit(drhd) {
2426 if (drhd->ignored)
2427 continue;
2428 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002429
2430 iommu_flush_write_buffer(iommu);
2431
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002432 ret = dmar_set_interrupt(iommu);
2433 if (ret)
2434 goto error;
2435
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002436 iommu_set_root_entry(iommu);
2437
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002438 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002439 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002440
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002441 ret = iommu_enable_translation(iommu);
2442 if (ret)
2443 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002444
2445 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002446 }
2447
2448 return 0;
2449error:
2450 for_each_drhd_unit(drhd) {
2451 if (drhd->ignored)
2452 continue;
2453 iommu = drhd->iommu;
2454 free_iommu(iommu);
2455 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002456 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002457 return ret;
2458}
2459
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002460/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002461static struct iova *intel_alloc_iova(struct device *dev,
2462 struct dmar_domain *domain,
2463 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002464{
2465 struct pci_dev *pdev = to_pci_dev(dev);
2466 struct iova *iova = NULL;
2467
David Woodhouse875764d2009-06-28 21:20:51 +01002468 /* Restrict dma_mask to the width that the iommu can handle */
2469 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2470
2471 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002472 /*
2473 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002474 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002475 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002476 */
David Woodhouse875764d2009-06-28 21:20:51 +01002477 iova = alloc_iova(&domain->iovad, nrpages,
2478 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2479 if (iova)
2480 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002481 }
David Woodhouse875764d2009-06-28 21:20:51 +01002482 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2483 if (unlikely(!iova)) {
2484 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2485 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002486 return NULL;
2487 }
2488
2489 return iova;
2490}
2491
David Woodhouse147202a2009-07-07 19:43:20 +01002492static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002493{
2494 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002495 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002496
2497 domain = get_domain_for_dev(pdev,
2498 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2499 if (!domain) {
2500 printk(KERN_ERR
2501 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002502 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002503 }
2504
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002505 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002506 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002507 ret = domain_context_mapping(domain, pdev,
2508 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002509 if (ret) {
2510 printk(KERN_ERR
2511 "Domain context map for %s failed",
2512 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002513 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002514 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002515 }
2516
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002517 return domain;
2518}
2519
David Woodhouse147202a2009-07-07 19:43:20 +01002520static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2521{
2522 struct device_domain_info *info;
2523
2524 /* No lock here, assumes no domain exit in normal case */
2525 info = dev->dev.archdata.iommu;
2526 if (likely(info))
2527 return info->domain;
2528
2529 return __get_valid_domain_for_dev(dev);
2530}
2531
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002532static int iommu_dummy(struct pci_dev *pdev)
2533{
2534 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2535}
2536
2537/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002538static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002539{
David Woodhouse73676832009-07-04 14:08:36 +01002540 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002541 int found;
2542
David Woodhouse73676832009-07-04 14:08:36 +01002543 if (unlikely(dev->bus != &pci_bus_type))
2544 return 1;
2545
2546 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002547 if (iommu_dummy(pdev))
2548 return 1;
2549
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002550 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002551 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002552
2553 found = identity_mapping(pdev);
2554 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002555 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002556 return 1;
2557 else {
2558 /*
2559 * 32 bit DMA is removed from si_domain and fall back
2560 * to non-identity mapping.
2561 */
2562 domain_remove_one_dev_info(si_domain, pdev);
2563 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2564 pci_name(pdev));
2565 return 0;
2566 }
2567 } else {
2568 /*
2569 * In case of a detached 64 bit DMA device from vm, the device
2570 * is put into si_domain for identity mapping.
2571 */
David Woodhouse6941af22009-07-04 18:24:27 +01002572 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002573 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002574 ret = domain_add_dev_info(si_domain, pdev,
2575 hw_pass_through ?
2576 CONTEXT_TT_PASS_THROUGH :
2577 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002578 if (!ret) {
2579 printk(KERN_INFO "64bit %s uses identity mapping\n",
2580 pci_name(pdev));
2581 return 1;
2582 }
2583 }
2584 }
2585
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002586 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002587}
2588
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002589static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2590 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002591{
2592 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002593 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002594 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002595 struct iova *iova;
2596 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002597 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002598 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002599 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002600
2601 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002602
David Woodhouse73676832009-07-04 14:08:36 +01002603 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002604 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002605
2606 domain = get_valid_domain_for_dev(pdev);
2607 if (!domain)
2608 return 0;
2609
Weidong Han8c11e792008-12-08 15:29:22 +08002610 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002611 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002612
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002613 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
2614 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002615 if (!iova)
2616 goto error;
2617
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002618 /*
2619 * Check if DMAR supports zero-length reads on write only
2620 * mappings..
2621 */
2622 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002623 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002624 prot |= DMA_PTE_READ;
2625 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2626 prot |= DMA_PTE_WRITE;
2627 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002628 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002629 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002630 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002631 * is not a big problem
2632 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002633 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002634 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002635 if (ret)
2636 goto error;
2637
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002638 /* it's a non-present to present mapping. Only flush if caching mode */
2639 if (cap_caching_mode(iommu->cap))
David Woodhouse03d6a242009-06-28 15:33:46 +01002640 iommu_flush_iotlb_psi(iommu, 0, mm_to_dma_pfn(iova->pfn_lo), size);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002641 else
Weidong Han8c11e792008-12-08 15:29:22 +08002642 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002643
David Woodhouse03d6a242009-06-28 15:33:46 +01002644 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2645 start_paddr += paddr & ~PAGE_MASK;
2646 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002647
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002648error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002649 if (iova)
2650 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002651 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002652 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002653 return 0;
2654}
2655
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002656static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2657 unsigned long offset, size_t size,
2658 enum dma_data_direction dir,
2659 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002660{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002661 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2662 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002663}
2664
mark gross5e0d2a62008-03-04 15:22:08 -08002665static void flush_unmaps(void)
2666{
mark gross80b20dd2008-04-18 13:53:58 -07002667 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002668
mark gross5e0d2a62008-03-04 15:22:08 -08002669 timer_on = 0;
2670
2671 /* just flush them all */
2672 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002673 struct intel_iommu *iommu = g_iommus[i];
2674 if (!iommu)
2675 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002676
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002677 if (!deferred_flush[i].next)
2678 continue;
2679
2680 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002681 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002682 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002683 unsigned long mask;
2684 struct iova *iova = deferred_flush[i].iova[j];
2685
Benjamin LaHaise64de5af2009-09-16 21:05:55 -04002686 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
Yu Zhao93a23a72009-05-18 13:51:37 +08002687 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
Benjamin LaHaise64de5af2009-09-16 21:05:55 -04002688 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
Yu Zhao93a23a72009-05-18 13:51:37 +08002689 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002690 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002691 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002692 }
2693
mark gross5e0d2a62008-03-04 15:22:08 -08002694 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002695}
2696
2697static void flush_unmaps_timeout(unsigned long data)
2698{
mark gross80b20dd2008-04-18 13:53:58 -07002699 unsigned long flags;
2700
2701 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002702 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002703 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002704}
2705
2706static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2707{
2708 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002709 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002710 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002711
2712 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002713 if (list_size == HIGH_WATER_MARK)
2714 flush_unmaps();
2715
Weidong Han8c11e792008-12-08 15:29:22 +08002716 iommu = domain_get_iommu(dom);
2717 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002718
mark gross80b20dd2008-04-18 13:53:58 -07002719 next = deferred_flush[iommu_id].next;
2720 deferred_flush[iommu_id].domain[next] = dom;
2721 deferred_flush[iommu_id].iova[next] = iova;
2722 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002723
2724 if (!timer_on) {
2725 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2726 timer_on = 1;
2727 }
2728 list_size++;
2729 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2730}
2731
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002732static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2733 size_t size, enum dma_data_direction dir,
2734 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002735{
2736 struct pci_dev *pdev = to_pci_dev(dev);
2737 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002738 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002739 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002740 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002741
David Woodhouse73676832009-07-04 14:08:36 +01002742 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002743 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002744
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002745 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002746 BUG_ON(!domain);
2747
Weidong Han8c11e792008-12-08 15:29:22 +08002748 iommu = domain_get_iommu(domain);
2749
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002750 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002751 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2752 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002753 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002754
David Woodhoused794dc92009-06-28 00:27:49 +01002755 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2756 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002757
David Woodhoused794dc92009-06-28 00:27:49 +01002758 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2759 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002760
2761 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002762 dma_pte_clear_range(domain, start_pfn, last_pfn);
2763
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002764 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002765 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2766
mark gross5e0d2a62008-03-04 15:22:08 -08002767 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002768 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
David Woodhoused794dc92009-06-28 00:27:49 +01002769 last_pfn - start_pfn + 1);
mark gross5e0d2a62008-03-04 15:22:08 -08002770 /* free iova */
2771 __free_iova(&domain->iovad, iova);
2772 } else {
2773 add_unmap(domain, iova);
2774 /*
2775 * queue up the release of the unmap to save the 1/6th of the
2776 * cpu used up by the iotlb flush operation...
2777 */
mark gross5e0d2a62008-03-04 15:22:08 -08002778 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002779}
2780
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002781static void *intel_alloc_coherent(struct device *hwdev, size_t size,
2782 dma_addr_t *dma_handle, gfp_t flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002783{
2784 void *vaddr;
2785 int order;
2786
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002787 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002788 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002789
2790 if (!iommu_no_mapping(hwdev))
2791 flags &= ~(GFP_DMA | GFP_DMA32);
2792 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
2793 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
2794 flags |= GFP_DMA;
2795 else
2796 flags |= GFP_DMA32;
2797 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002798
2799 vaddr = (void *)__get_free_pages(flags, order);
2800 if (!vaddr)
2801 return NULL;
2802 memset(vaddr, 0, size);
2803
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002804 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2805 DMA_BIDIRECTIONAL,
2806 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002807 if (*dma_handle)
2808 return vaddr;
2809 free_pages((unsigned long)vaddr, order);
2810 return NULL;
2811}
2812
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002813static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
2814 dma_addr_t dma_handle)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002815{
2816 int order;
2817
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002818 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002819 order = get_order(size);
2820
David Woodhouse0db9b7a2009-07-14 02:01:57 +01002821 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002822 free_pages((unsigned long)vaddr, order);
2823}
2824
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002825static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
2826 int nelems, enum dma_data_direction dir,
2827 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002828{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002829 struct pci_dev *pdev = to_pci_dev(hwdev);
2830 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002831 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002832 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002833 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002834
David Woodhouse73676832009-07-04 14:08:36 +01002835 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002836 return;
2837
2838 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08002839 BUG_ON(!domain);
2840
2841 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002842
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002843 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01002844 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
2845 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002846 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002847
David Woodhoused794dc92009-06-28 00:27:49 +01002848 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2849 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002850
2851 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002852 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002853
David Woodhoused794dc92009-06-28 00:27:49 +01002854 /* free page tables */
2855 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2856
David Woodhouseacea0012009-07-14 01:55:11 +01002857 if (intel_iommu_strict) {
2858 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
2859 last_pfn - start_pfn + 1);
2860 /* free iova */
2861 __free_iova(&domain->iovad, iova);
2862 } else {
2863 add_unmap(domain, iova);
2864 /*
2865 * queue up the release of the unmap to save the 1/6th of the
2866 * cpu used up by the iotlb flush operation...
2867 */
2868 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002869}
2870
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002871static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002872 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002873{
2874 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002875 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002876
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002877 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002878 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00002879 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002880 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002881 }
2882 return nelems;
2883}
2884
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002885static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
2886 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002887{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002888 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002889 struct pci_dev *pdev = to_pci_dev(hwdev);
2890 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002891 size_t size = 0;
2892 int prot = 0;
David Woodhouseb536d242009-06-28 14:49:31 +01002893 size_t offset_pfn = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002894 struct iova *iova = NULL;
2895 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002896 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01002897 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08002898 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002899
2900 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01002901 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002902 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002903
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002904 domain = get_valid_domain_for_dev(pdev);
2905 if (!domain)
2906 return 0;
2907
Weidong Han8c11e792008-12-08 15:29:22 +08002908 iommu = domain_get_iommu(domain);
2909
David Woodhouseb536d242009-06-28 14:49:31 +01002910 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01002911 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002912
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002913 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
2914 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002915 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002916 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002917 return 0;
2918 }
2919
2920 /*
2921 * Check if DMAR supports zero-length reads on write only
2922 * mappings..
2923 */
2924 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002925 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002926 prot |= DMA_PTE_READ;
2927 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2928 prot |= DMA_PTE_WRITE;
2929
David Woodhouseb536d242009-06-28 14:49:31 +01002930 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01002931
Fenghua Yuf5329592009-08-04 15:09:37 -07002932 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01002933 if (unlikely(ret)) {
2934 /* clear the page */
2935 dma_pte_clear_range(domain, start_vpfn,
2936 start_vpfn + size - 1);
2937 /* free page tables */
2938 dma_pte_free_pagetable(domain, start_vpfn,
2939 start_vpfn + size - 1);
2940 /* free iova */
2941 __free_iova(&domain->iovad, iova);
2942 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002943 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002944
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002945 /* it's a non-present to present mapping. Only flush if caching mode */
2946 if (cap_caching_mode(iommu->cap))
David Woodhouse03d6a242009-06-28 15:33:46 +01002947 iommu_flush_iotlb_psi(iommu, 0, start_vpfn, offset_pfn);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002948 else
Weidong Han8c11e792008-12-08 15:29:22 +08002949 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002950
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002951 return nelems;
2952}
2953
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09002954static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
2955{
2956 return !dma_addr;
2957}
2958
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09002959struct dma_map_ops intel_dma_ops = {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002960 .alloc_coherent = intel_alloc_coherent,
2961 .free_coherent = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002962 .map_sg = intel_map_sg,
2963 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002964 .map_page = intel_map_page,
2965 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09002966 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002967};
2968
2969static inline int iommu_domain_cache_init(void)
2970{
2971 int ret = 0;
2972
2973 iommu_domain_cache = kmem_cache_create("iommu_domain",
2974 sizeof(struct dmar_domain),
2975 0,
2976 SLAB_HWCACHE_ALIGN,
2977
2978 NULL);
2979 if (!iommu_domain_cache) {
2980 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
2981 ret = -ENOMEM;
2982 }
2983
2984 return ret;
2985}
2986
2987static inline int iommu_devinfo_cache_init(void)
2988{
2989 int ret = 0;
2990
2991 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
2992 sizeof(struct device_domain_info),
2993 0,
2994 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002995 NULL);
2996 if (!iommu_devinfo_cache) {
2997 printk(KERN_ERR "Couldn't create devinfo cache\n");
2998 ret = -ENOMEM;
2999 }
3000
3001 return ret;
3002}
3003
3004static inline int iommu_iova_cache_init(void)
3005{
3006 int ret = 0;
3007
3008 iommu_iova_cache = kmem_cache_create("iommu_iova",
3009 sizeof(struct iova),
3010 0,
3011 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003012 NULL);
3013 if (!iommu_iova_cache) {
3014 printk(KERN_ERR "Couldn't create iova cache\n");
3015 ret = -ENOMEM;
3016 }
3017
3018 return ret;
3019}
3020
3021static int __init iommu_init_mempool(void)
3022{
3023 int ret;
3024 ret = iommu_iova_cache_init();
3025 if (ret)
3026 return ret;
3027
3028 ret = iommu_domain_cache_init();
3029 if (ret)
3030 goto domain_error;
3031
3032 ret = iommu_devinfo_cache_init();
3033 if (!ret)
3034 return ret;
3035
3036 kmem_cache_destroy(iommu_domain_cache);
3037domain_error:
3038 kmem_cache_destroy(iommu_iova_cache);
3039
3040 return -ENOMEM;
3041}
3042
3043static void __init iommu_exit_mempool(void)
3044{
3045 kmem_cache_destroy(iommu_devinfo_cache);
3046 kmem_cache_destroy(iommu_domain_cache);
3047 kmem_cache_destroy(iommu_iova_cache);
3048
3049}
3050
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003051static void __init init_no_remapping_devices(void)
3052{
3053 struct dmar_drhd_unit *drhd;
3054
3055 for_each_drhd_unit(drhd) {
3056 if (!drhd->include_all) {
3057 int i;
3058 for (i = 0; i < drhd->devices_cnt; i++)
3059 if (drhd->devices[i] != NULL)
3060 break;
3061 /* ignore DMAR unit if no pci devices exist */
3062 if (i == drhd->devices_cnt)
3063 drhd->ignored = 1;
3064 }
3065 }
3066
3067 if (dmar_map_gfx)
3068 return;
3069
3070 for_each_drhd_unit(drhd) {
3071 int i;
3072 if (drhd->ignored || drhd->include_all)
3073 continue;
3074
3075 for (i = 0; i < drhd->devices_cnt; i++)
3076 if (drhd->devices[i] &&
3077 !IS_GFX_DEVICE(drhd->devices[i]))
3078 break;
3079
3080 if (i < drhd->devices_cnt)
3081 continue;
3082
3083 /* bypass IOMMU if it is just for gfx devices */
3084 drhd->ignored = 1;
3085 for (i = 0; i < drhd->devices_cnt; i++) {
3086 if (!drhd->devices[i])
3087 continue;
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07003088 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003089 }
3090 }
3091}
3092
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003093#ifdef CONFIG_SUSPEND
3094static int init_iommu_hw(void)
3095{
3096 struct dmar_drhd_unit *drhd;
3097 struct intel_iommu *iommu = NULL;
3098
3099 for_each_active_iommu(iommu, drhd)
3100 if (iommu->qi)
3101 dmar_reenable_qi(iommu);
3102
3103 for_each_active_iommu(iommu, drhd) {
3104 iommu_flush_write_buffer(iommu);
3105
3106 iommu_set_root_entry(iommu);
3107
3108 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003109 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003110 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003111 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003112 iommu_enable_translation(iommu);
David Woodhouseb94996c2009-09-19 15:28:12 -07003113 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003114 }
3115
3116 return 0;
3117}
3118
3119static void iommu_flush_all(void)
3120{
3121 struct dmar_drhd_unit *drhd;
3122 struct intel_iommu *iommu;
3123
3124 for_each_active_iommu(iommu, drhd) {
3125 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003126 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003127 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003128 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003129 }
3130}
3131
3132static int iommu_suspend(struct sys_device *dev, pm_message_t state)
3133{
3134 struct dmar_drhd_unit *drhd;
3135 struct intel_iommu *iommu = NULL;
3136 unsigned long flag;
3137
3138 for_each_active_iommu(iommu, drhd) {
3139 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3140 GFP_ATOMIC);
3141 if (!iommu->iommu_state)
3142 goto nomem;
3143 }
3144
3145 iommu_flush_all();
3146
3147 for_each_active_iommu(iommu, drhd) {
3148 iommu_disable_translation(iommu);
3149
3150 spin_lock_irqsave(&iommu->register_lock, flag);
3151
3152 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3153 readl(iommu->reg + DMAR_FECTL_REG);
3154 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3155 readl(iommu->reg + DMAR_FEDATA_REG);
3156 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3157 readl(iommu->reg + DMAR_FEADDR_REG);
3158 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3159 readl(iommu->reg + DMAR_FEUADDR_REG);
3160
3161 spin_unlock_irqrestore(&iommu->register_lock, flag);
3162 }
3163 return 0;
3164
3165nomem:
3166 for_each_active_iommu(iommu, drhd)
3167 kfree(iommu->iommu_state);
3168
3169 return -ENOMEM;
3170}
3171
3172static int iommu_resume(struct sys_device *dev)
3173{
3174 struct dmar_drhd_unit *drhd;
3175 struct intel_iommu *iommu = NULL;
3176 unsigned long flag;
3177
3178 if (init_iommu_hw()) {
3179 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
3180 return -EIO;
3181 }
3182
3183 for_each_active_iommu(iommu, drhd) {
3184
3185 spin_lock_irqsave(&iommu->register_lock, flag);
3186
3187 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3188 iommu->reg + DMAR_FECTL_REG);
3189 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3190 iommu->reg + DMAR_FEDATA_REG);
3191 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3192 iommu->reg + DMAR_FEADDR_REG);
3193 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3194 iommu->reg + DMAR_FEUADDR_REG);
3195
3196 spin_unlock_irqrestore(&iommu->register_lock, flag);
3197 }
3198
3199 for_each_active_iommu(iommu, drhd)
3200 kfree(iommu->iommu_state);
3201
3202 return 0;
3203}
3204
3205static struct sysdev_class iommu_sysclass = {
3206 .name = "iommu",
3207 .resume = iommu_resume,
3208 .suspend = iommu_suspend,
3209};
3210
3211static struct sys_device device_iommu = {
3212 .cls = &iommu_sysclass,
3213};
3214
3215static int __init init_iommu_sysfs(void)
3216{
3217 int error;
3218
3219 error = sysdev_class_register(&iommu_sysclass);
3220 if (error)
3221 return error;
3222
3223 error = sysdev_register(&device_iommu);
3224 if (error)
3225 sysdev_class_unregister(&iommu_sysclass);
3226
3227 return error;
3228}
3229
3230#else
3231static int __init init_iommu_sysfs(void)
3232{
3233 return 0;
3234}
3235#endif /* CONFIG_PM */
3236
Fenghua Yu99dcade2009-11-11 07:23:06 -08003237/*
3238 * Here we only respond to action of unbound device from driver.
3239 *
3240 * Added device is not attached to its DMAR domain here yet. That will happen
3241 * when mapping the device to iova.
3242 */
3243static int device_notifier(struct notifier_block *nb,
3244 unsigned long action, void *data)
3245{
3246 struct device *dev = data;
3247 struct pci_dev *pdev = to_pci_dev(dev);
3248 struct dmar_domain *domain;
3249
3250 domain = find_domain(pdev);
3251 if (!domain)
3252 return 0;
3253
3254 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through)
3255 domain_remove_one_dev_info(domain, pdev);
3256
3257 return 0;
3258}
3259
3260static struct notifier_block device_nb = {
3261 .notifier_call = device_notifier,
3262};
3263
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003264int __init intel_iommu_init(void)
3265{
3266 int ret = 0;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003267 int force_on = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003268
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003269 /* VT-d is required for a TXT/tboot launch, so enforce that */
3270 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003271
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003272 if (dmar_table_init()) {
3273 if (force_on)
3274 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003275 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003276 }
3277
3278 if (dmar_dev_scope_init()) {
3279 if (force_on)
3280 panic("tboot: Failed to initialize DMAR device scope\n");
3281 return -ENODEV;
3282 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003283
Suresh Siddha2ae21012008-07-10 11:16:43 -07003284 /*
3285 * Check the need for DMA-remapping initialization now.
3286 * Above initialization will also be used by Interrupt-remapping.
3287 */
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003288 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003289 return -ENODEV;
3290
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003291 iommu_init_mempool();
3292 dmar_init_reserved_ranges();
3293
3294 init_no_remapping_devices();
3295
3296 ret = init_dmars();
3297 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003298 if (force_on)
3299 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003300 printk(KERN_ERR "IOMMU: dmar init failed\n");
3301 put_iova_domain(&reserved_iova_list);
3302 iommu_exit_mempool();
3303 return ret;
3304 }
3305 printk(KERN_INFO
3306 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3307
mark gross5e0d2a62008-03-04 15:22:08 -08003308 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003309#ifdef CONFIG_SWIOTLB
3310 swiotlb = 0;
3311#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003312 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003313
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003314 init_iommu_sysfs();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003315
3316 register_iommu(&intel_iommu_ops);
3317
Fenghua Yu99dcade2009-11-11 07:23:06 -08003318 bus_register_notifier(&pci_bus_type, &device_nb);
3319
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003320 return 0;
3321}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003322
Han, Weidong3199aa62009-02-26 17:31:12 +08003323static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3324 struct pci_dev *pdev)
3325{
3326 struct pci_dev *tmp, *parent;
3327
3328 if (!iommu || !pdev)
3329 return;
3330
3331 /* dependent device detach */
3332 tmp = pci_find_upstream_pcie_bridge(pdev);
3333 /* Secondary interface's bus number and devfn 0 */
3334 if (tmp) {
3335 parent = pdev->bus->self;
3336 while (parent != tmp) {
3337 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01003338 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003339 parent = parent->bus->self;
3340 }
3341 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
3342 iommu_detach_dev(iommu,
3343 tmp->subordinate->number, 0);
3344 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01003345 iommu_detach_dev(iommu, tmp->bus->number,
3346 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003347 }
3348}
3349
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003350static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003351 struct pci_dev *pdev)
3352{
3353 struct device_domain_info *info;
3354 struct intel_iommu *iommu;
3355 unsigned long flags;
3356 int found = 0;
3357 struct list_head *entry, *tmp;
3358
David Woodhouse276dbf992009-04-04 01:45:37 +01003359 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3360 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003361 if (!iommu)
3362 return;
3363
3364 spin_lock_irqsave(&device_domain_lock, flags);
3365 list_for_each_safe(entry, tmp, &domain->devices) {
3366 info = list_entry(entry, struct device_domain_info, link);
David Woodhouse276dbf992009-04-04 01:45:37 +01003367 /* No need to compare PCI domain; it has to be the same */
Weidong Hanc7151a82008-12-08 22:51:37 +08003368 if (info->bus == pdev->bus->number &&
3369 info->devfn == pdev->devfn) {
3370 list_del(&info->link);
3371 list_del(&info->global);
3372 if (info->dev)
3373 info->dev->dev.archdata.iommu = NULL;
3374 spin_unlock_irqrestore(&device_domain_lock, flags);
3375
Yu Zhao93a23a72009-05-18 13:51:37 +08003376 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003377 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003378 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003379 free_devinfo_mem(info);
3380
3381 spin_lock_irqsave(&device_domain_lock, flags);
3382
3383 if (found)
3384 break;
3385 else
3386 continue;
3387 }
3388
3389 /* if there is no other devices under the same iommu
3390 * owned by this domain, clear this iommu in iommu_bmp
3391 * update iommu count and coherency
3392 */
David Woodhouse276dbf992009-04-04 01:45:37 +01003393 if (iommu == device_to_iommu(info->segment, info->bus,
3394 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003395 found = 1;
3396 }
3397
3398 if (found == 0) {
3399 unsigned long tmp_flags;
3400 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
3401 clear_bit(iommu->seq_id, &domain->iommu_bmp);
3402 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003403 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003404 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
3405 }
3406
3407 spin_unlock_irqrestore(&device_domain_lock, flags);
3408}
3409
3410static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3411{
3412 struct device_domain_info *info;
3413 struct intel_iommu *iommu;
3414 unsigned long flags1, flags2;
3415
3416 spin_lock_irqsave(&device_domain_lock, flags1);
3417 while (!list_empty(&domain->devices)) {
3418 info = list_entry(domain->devices.next,
3419 struct device_domain_info, link);
3420 list_del(&info->link);
3421 list_del(&info->global);
3422 if (info->dev)
3423 info->dev->dev.archdata.iommu = NULL;
3424
3425 spin_unlock_irqrestore(&device_domain_lock, flags1);
3426
Yu Zhao93a23a72009-05-18 13:51:37 +08003427 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01003428 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003429 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003430 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003431
3432 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003433 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003434 */
3435 spin_lock_irqsave(&domain->iommu_lock, flags2);
3436 if (test_and_clear_bit(iommu->seq_id,
3437 &domain->iommu_bmp)) {
3438 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003439 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003440 }
3441 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3442
3443 free_devinfo_mem(info);
3444 spin_lock_irqsave(&device_domain_lock, flags1);
3445 }
3446 spin_unlock_irqrestore(&device_domain_lock, flags1);
3447}
3448
Weidong Han5e98c4b2008-12-08 23:03:27 +08003449/* domain id for virtual machine, it won't be set in context */
3450static unsigned long vm_domid;
3451
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003452static int vm_domain_min_agaw(struct dmar_domain *domain)
3453{
3454 int i;
3455 int min_agaw = domain->agaw;
3456
3457 i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
3458 for (; i < g_num_of_iommus; ) {
3459 if (min_agaw > g_iommus[i]->agaw)
3460 min_agaw = g_iommus[i]->agaw;
3461
3462 i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
3463 }
3464
3465 return min_agaw;
3466}
3467
Weidong Han5e98c4b2008-12-08 23:03:27 +08003468static struct dmar_domain *iommu_alloc_vm_domain(void)
3469{
3470 struct dmar_domain *domain;
3471
3472 domain = alloc_domain_mem();
3473 if (!domain)
3474 return NULL;
3475
3476 domain->id = vm_domid++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003477 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003478 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
3479 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3480
3481 return domain;
3482}
3483
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003484static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003485{
3486 int adjust_width;
3487
3488 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003489 spin_lock_init(&domain->iommu_lock);
3490
3491 domain_reserve_special_ranges(domain);
3492
3493 /* calculate AGAW */
3494 domain->gaw = guest_width;
3495 adjust_width = guestwidth_to_adjustwidth(guest_width);
3496 domain->agaw = width_to_agaw(adjust_width);
3497
3498 INIT_LIST_HEAD(&domain->devices);
3499
3500 domain->iommu_count = 0;
3501 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003502 domain->iommu_snooping = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003503 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003504 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003505
3506 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003507 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003508 if (!domain->pgd)
3509 return -ENOMEM;
3510 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3511 return 0;
3512}
3513
3514static void iommu_free_vm_domain(struct dmar_domain *domain)
3515{
3516 unsigned long flags;
3517 struct dmar_drhd_unit *drhd;
3518 struct intel_iommu *iommu;
3519 unsigned long i;
3520 unsigned long ndomains;
3521
3522 for_each_drhd_unit(drhd) {
3523 if (drhd->ignored)
3524 continue;
3525 iommu = drhd->iommu;
3526
3527 ndomains = cap_ndoms(iommu->cap);
3528 i = find_first_bit(iommu->domain_ids, ndomains);
3529 for (; i < ndomains; ) {
3530 if (iommu->domains[i] == domain) {
3531 spin_lock_irqsave(&iommu->lock, flags);
3532 clear_bit(i, iommu->domain_ids);
3533 iommu->domains[i] = NULL;
3534 spin_unlock_irqrestore(&iommu->lock, flags);
3535 break;
3536 }
3537 i = find_next_bit(iommu->domain_ids, ndomains, i+1);
3538 }
3539 }
3540}
3541
3542static void vm_domain_exit(struct dmar_domain *domain)
3543{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003544 /* Domain 0 is reserved, so dont process it */
3545 if (!domain)
3546 return;
3547
3548 vm_domain_remove_all_dev_info(domain);
3549 /* destroy iovas */
3550 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003551
3552 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003553 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003554
3555 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003556 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003557
3558 iommu_free_vm_domain(domain);
3559 free_domain_mem(domain);
3560}
3561
Joerg Roedel5d450802008-12-03 14:52:32 +01003562static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003563{
Joerg Roedel5d450802008-12-03 14:52:32 +01003564 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003565
Joerg Roedel5d450802008-12-03 14:52:32 +01003566 dmar_domain = iommu_alloc_vm_domain();
3567 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003568 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003569 "intel_iommu_domain_init: dmar_domain == NULL\n");
3570 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003571 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003572 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003573 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003574 "intel_iommu_domain_init() failed\n");
3575 vm_domain_exit(dmar_domain);
3576 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003577 }
Joerg Roedel5d450802008-12-03 14:52:32 +01003578 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003579
Joerg Roedel5d450802008-12-03 14:52:32 +01003580 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003581}
Kay, Allen M38717942008-09-09 18:37:29 +03003582
Joerg Roedel5d450802008-12-03 14:52:32 +01003583static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003584{
Joerg Roedel5d450802008-12-03 14:52:32 +01003585 struct dmar_domain *dmar_domain = domain->priv;
3586
3587 domain->priv = NULL;
3588 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003589}
Kay, Allen M38717942008-09-09 18:37:29 +03003590
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003591static int intel_iommu_attach_device(struct iommu_domain *domain,
3592 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003593{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003594 struct dmar_domain *dmar_domain = domain->priv;
3595 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003596 struct intel_iommu *iommu;
3597 int addr_width;
3598 u64 end;
Kay, Allen M38717942008-09-09 18:37:29 +03003599
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003600 /* normally pdev is not mapped */
3601 if (unlikely(domain_context_mapped(pdev))) {
3602 struct dmar_domain *old_domain;
3603
3604 old_domain = find_domain(pdev);
3605 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003606 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3607 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3608 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003609 else
3610 domain_remove_dev_info(old_domain);
3611 }
3612 }
3613
David Woodhouse276dbf992009-04-04 01:45:37 +01003614 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3615 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003616 if (!iommu)
3617 return -ENODEV;
3618
3619 /* check if this iommu agaw is sufficient for max mapped address */
3620 addr_width = agaw_to_width(iommu->agaw);
3621 end = DOMAIN_MAX_ADDR(addr_width);
3622 end = end & VTD_PAGE_MASK;
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003623 if (end < dmar_domain->max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003624 printk(KERN_ERR "%s: iommu agaw (%d) is not "
3625 "sufficient for the mapped address (%llx)\n",
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003626 __func__, iommu->agaw, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003627 return -EFAULT;
3628 }
3629
David Woodhouse5fe60f42009-08-09 10:53:41 +01003630 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003631}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003632
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003633static void intel_iommu_detach_device(struct iommu_domain *domain,
3634 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003635{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003636 struct dmar_domain *dmar_domain = domain->priv;
3637 struct pci_dev *pdev = to_pci_dev(dev);
3638
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003639 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003640}
Kay, Allen M38717942008-09-09 18:37:29 +03003641
Joerg Roedeldde57a22008-12-03 15:04:09 +01003642static int intel_iommu_map_range(struct iommu_domain *domain,
3643 unsigned long iova, phys_addr_t hpa,
3644 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003645{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003646 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003647 u64 max_addr;
3648 int addr_width;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003649 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003650 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003651
Joerg Roedeldde57a22008-12-03 15:04:09 +01003652 if (iommu_prot & IOMMU_READ)
3653 prot |= DMA_PTE_READ;
3654 if (iommu_prot & IOMMU_WRITE)
3655 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08003656 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
3657 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003658
David Woodhouse163cc522009-06-28 00:51:17 +01003659 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003660 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003661 int min_agaw;
3662 u64 end;
3663
3664 /* check if minimum agaw is sufficient for mapped address */
Joerg Roedeldde57a22008-12-03 15:04:09 +01003665 min_agaw = vm_domain_min_agaw(dmar_domain);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003666 addr_width = agaw_to_width(min_agaw);
3667 end = DOMAIN_MAX_ADDR(addr_width);
3668 end = end & VTD_PAGE_MASK;
3669 if (end < max_addr) {
3670 printk(KERN_ERR "%s: iommu agaw (%d) is not "
3671 "sufficient for the mapped address (%llx)\n",
3672 __func__, min_agaw, max_addr);
3673 return -EFAULT;
3674 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003675 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003676 }
David Woodhousead051222009-06-28 14:22:28 +01003677 /* Round up size to next multiple of PAGE_SIZE, if it and
3678 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01003679 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01003680 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
3681 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003682 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003683}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003684
Joerg Roedeldde57a22008-12-03 15:04:09 +01003685static void intel_iommu_unmap_range(struct iommu_domain *domain,
3686 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003687{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003688 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003689
Sheng Yang4b99d352009-07-08 11:52:52 +01003690 if (!size)
3691 return;
3692
David Woodhouse163cc522009-06-28 00:51:17 +01003693 dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
3694 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003695
David Woodhouse163cc522009-06-28 00:51:17 +01003696 if (dmar_domain->max_addr == iova + size)
3697 dmar_domain->max_addr = iova;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003698}
Kay, Allen M38717942008-09-09 18:37:29 +03003699
Joerg Roedeld14d6572008-12-03 15:06:57 +01003700static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
3701 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03003702{
Joerg Roedeld14d6572008-12-03 15:06:57 +01003703 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03003704 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003705 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003706
David Woodhouseb026fd22009-06-28 10:37:25 +01003707 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
Kay, Allen M38717942008-09-09 18:37:29 +03003708 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003709 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03003710
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003711 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03003712}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003713
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003714static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
3715 unsigned long cap)
3716{
3717 struct dmar_domain *dmar_domain = domain->priv;
3718
3719 if (cap == IOMMU_CAP_CACHE_COHERENCY)
3720 return dmar_domain->iommu_snooping;
3721
3722 return 0;
3723}
3724
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003725static struct iommu_ops intel_iommu_ops = {
3726 .domain_init = intel_iommu_domain_init,
3727 .domain_destroy = intel_iommu_domain_destroy,
3728 .attach_dev = intel_iommu_attach_device,
3729 .detach_dev = intel_iommu_detach_device,
3730 .map = intel_iommu_map_range,
3731 .unmap = intel_iommu_unmap_range,
3732 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003733 .domain_has_cap = intel_iommu_domain_has_cap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003734};
David Woodhouse9af88142009-02-13 23:18:03 +00003735
3736static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
3737{
3738 /*
3739 * Mobile 4 Series Chipset neglects to set RWBF capability,
3740 * but needs it:
3741 */
3742 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
3743 rwbf_quirk = 1;
3744}
3745
3746DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07003747
3748/* On Tylersburg chipsets, some BIOSes have been known to enable the
3749 ISOCH DMAR unit for the Azalia sound device, but not give it any
3750 TLB entries, which causes it to deadlock. Check for that. We do
3751 this in a function called from init_dmars(), instead of in a PCI
3752 quirk, because we don't want to print the obnoxious "BIOS broken"
3753 message if VT-d is actually disabled.
3754*/
3755static void __init check_tylersburg_isoch(void)
3756{
3757 struct pci_dev *pdev;
3758 uint32_t vtisochctrl;
3759
3760 /* If there's no Azalia in the system anyway, forget it. */
3761 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
3762 if (!pdev)
3763 return;
3764 pci_dev_put(pdev);
3765
3766 /* System Management Registers. Might be hidden, in which case
3767 we can't do the sanity check. But that's OK, because the
3768 known-broken BIOSes _don't_ actually hide it, so far. */
3769 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
3770 if (!pdev)
3771 return;
3772
3773 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
3774 pci_dev_put(pdev);
3775 return;
3776 }
3777
3778 pci_dev_put(pdev);
3779
3780 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
3781 if (vtisochctrl & 1)
3782 return;
3783
3784 /* Drop all bits other than the number of TLB entries */
3785 vtisochctrl &= 0x1c;
3786
3787 /* If we have the recommended number of TLB entries (16), fine. */
3788 if (vtisochctrl == 0x10)
3789 return;
3790
3791 /* Zero TLB entries? You get to ride the short bus to school. */
3792 if (!vtisochctrl) {
3793 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
3794 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
3795 dmi_get_system_info(DMI_BIOS_VENDOR),
3796 dmi_get_system_info(DMI_BIOS_VERSION),
3797 dmi_get_system_info(DMI_PRODUCT_VERSION));
3798 iommu_identity_mapping |= IDENTMAP_AZALIA;
3799 return;
3800 }
3801
3802 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
3803 vtisochctrl);
3804}