blob: 4660795353304666a3daedd55a1d388bdfebcaf1 [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 Woodhousee0fc7e0b2009-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 Woodhousee0fc7e0b2009-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 Woodhouse276dbf92009-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 Woodhouse276dbf92009-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 Woodhouse276dbf92009-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 Woodhouse276dbf92009-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.
Chris Wright1672af12009-12-02 12:06:34 -08001533 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001534 */
Chris Wright1672af12009-12-02 12:06:34 -08001535 if (translation != CONTEXT_TT_PASS_THROUGH) {
1536 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1537 pgd = phys_to_virt(dma_pte_addr(pgd));
1538 if (!dma_pte_present(pgd)) {
1539 spin_unlock_irqrestore(&iommu->lock, flags);
1540 return -ENOMEM;
1541 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001542 }
1543 }
1544 }
1545
1546 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001547
Yu Zhao93a23a72009-05-18 13:51:37 +08001548 if (translation != CONTEXT_TT_PASS_THROUGH) {
1549 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1550 translation = info ? CONTEXT_TT_DEV_IOTLB :
1551 CONTEXT_TT_MULTI_LEVEL;
1552 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001553 /*
1554 * In pass through mode, AW must be programmed to indicate the largest
1555 * AGAW value supported by hardware. And ASR is ignored by hardware.
1556 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001557 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001558 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001559 else {
1560 context_set_address_root(context, virt_to_phys(pgd));
1561 context_set_address_width(context, iommu->agaw);
1562 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001563
1564 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001565 context_set_fault_enable(context);
1566 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001567 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001568
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001569 /*
1570 * It's a non-present to present mapping. If hardware doesn't cache
1571 * non-present entry we only need to flush the write-buffer. If the
1572 * _does_ cache non-present entries, then it does so in the special
1573 * domain #0, which we have to flush:
1574 */
1575 if (cap_caching_mode(iommu->cap)) {
1576 iommu->flush.flush_context(iommu, 0,
1577 (((u16)bus) << 8) | devfn,
1578 DMA_CCMD_MASK_NOBIT,
1579 DMA_CCMD_DEVICE_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001580 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001581 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001582 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001583 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001584 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001585 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001586
1587 spin_lock_irqsave(&domain->iommu_lock, flags);
1588 if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
1589 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001590 if (domain->iommu_count == 1)
1591 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001592 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001593 }
1594 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001595 return 0;
1596}
1597
1598static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001599domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1600 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001601{
1602 int ret;
1603 struct pci_dev *tmp, *parent;
1604
David Woodhouse276dbf92009-04-04 01:45:37 +01001605 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001606 pdev->bus->number, pdev->devfn,
1607 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001608 if (ret)
1609 return ret;
1610
1611 /* dependent device mapping */
1612 tmp = pci_find_upstream_pcie_bridge(pdev);
1613 if (!tmp)
1614 return 0;
1615 /* Secondary interface's bus number and devfn 0 */
1616 parent = pdev->bus->self;
1617 while (parent != tmp) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001618 ret = domain_context_mapping_one(domain,
1619 pci_domain_nr(parent->bus),
1620 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001621 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001622 if (ret)
1623 return ret;
1624 parent = parent->bus->self;
1625 }
1626 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
1627 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001628 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001629 tmp->subordinate->number, 0,
1630 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001631 else /* this is a legacy PCI bridge */
1632 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001633 pci_domain_nr(tmp->bus),
1634 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001635 tmp->devfn,
1636 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001637}
1638
Weidong Han5331fe62008-12-08 23:00:00 +08001639static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001640{
1641 int ret;
1642 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001643 struct intel_iommu *iommu;
1644
David Woodhouse276dbf92009-04-04 01:45:37 +01001645 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1646 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001647 if (!iommu)
1648 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001649
David Woodhouse276dbf92009-04-04 01:45:37 +01001650 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001651 if (!ret)
1652 return ret;
1653 /* dependent device mapping */
1654 tmp = pci_find_upstream_pcie_bridge(pdev);
1655 if (!tmp)
1656 return ret;
1657 /* Secondary interface's bus number and devfn 0 */
1658 parent = pdev->bus->self;
1659 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001660 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01001661 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001662 if (!ret)
1663 return ret;
1664 parent = parent->bus->self;
1665 }
1666 if (tmp->is_pcie)
David Woodhouse276dbf92009-04-04 01:45:37 +01001667 return device_context_mapped(iommu, tmp->subordinate->number,
1668 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001669 else
David Woodhouse276dbf92009-04-04 01:45:37 +01001670 return device_context_mapped(iommu, tmp->bus->number,
1671 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001672}
1673
Fenghua Yuf5329592009-08-04 15:09:37 -07001674/* Returns a number of VTD pages, but aligned to MM page size */
1675static inline unsigned long aligned_nrpages(unsigned long host_addr,
1676 size_t size)
1677{
1678 host_addr &= ~PAGE_MASK;
1679 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1680}
1681
David Woodhouse9051aa02009-06-29 12:30:54 +01001682static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1683 struct scatterlist *sg, unsigned long phys_pfn,
1684 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001685{
1686 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001687 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001688 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001689 unsigned long sg_res;
David Woodhousee1605492009-06-29 11:17:38 +01001690
1691 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1692
1693 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1694 return -EINVAL;
1695
1696 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1697
David Woodhouse9051aa02009-06-29 12:30:54 +01001698 if (sg)
1699 sg_res = 0;
1700 else {
1701 sg_res = nr_pages + 1;
1702 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1703 }
1704
David Woodhousee1605492009-06-29 11:17:38 +01001705 while (nr_pages--) {
David Woodhousec85994e2009-07-01 19:21:24 +01001706 uint64_t tmp;
1707
David Woodhousee1605492009-06-29 11:17:38 +01001708 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001709 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001710 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1711 sg->dma_length = sg->length;
1712 pteval = page_to_phys(sg_page(sg)) | prot;
1713 }
1714 if (!pte) {
1715 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
1716 if (!pte)
1717 return -ENOMEM;
1718 }
1719 /* We don't need lock here, nobody else
1720 * touches the iova range
1721 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001722 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001723 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001724 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001725 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1726 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001727 if (dumps) {
1728 dumps--;
1729 debug_dma_dump_mappings(NULL);
1730 }
1731 WARN_ON(1);
1732 }
David Woodhousee1605492009-06-29 11:17:38 +01001733 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +01001734 if (!nr_pages || first_pte_in_page(pte)) {
David Woodhousee1605492009-06-29 11:17:38 +01001735 domain_flush_cache(domain, first_pte,
1736 (void *)pte - (void *)first_pte);
1737 pte = NULL;
1738 }
1739 iov_pfn++;
1740 pteval += VTD_PAGE_SIZE;
1741 sg_res--;
1742 if (!sg_res)
1743 sg = sg_next(sg);
1744 }
1745 return 0;
1746}
1747
David Woodhouse9051aa02009-06-29 12:30:54 +01001748static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1749 struct scatterlist *sg, unsigned long nr_pages,
1750 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001751{
David Woodhouse9051aa02009-06-29 12:30:54 +01001752 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1753}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001754
David Woodhouse9051aa02009-06-29 12:30:54 +01001755static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1756 unsigned long phys_pfn, unsigned long nr_pages,
1757 int prot)
1758{
1759 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001760}
1761
Weidong Hanc7151a82008-12-08 22:51:37 +08001762static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001763{
Weidong Hanc7151a82008-12-08 22:51:37 +08001764 if (!iommu)
1765 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001766
1767 clear_context_table(iommu, bus, devfn);
1768 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001769 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001770 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001771}
1772
1773static void domain_remove_dev_info(struct dmar_domain *domain)
1774{
1775 struct device_domain_info *info;
1776 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001777 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001778
1779 spin_lock_irqsave(&device_domain_lock, flags);
1780 while (!list_empty(&domain->devices)) {
1781 info = list_entry(domain->devices.next,
1782 struct device_domain_info, link);
1783 list_del(&info->link);
1784 list_del(&info->global);
1785 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001786 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001787 spin_unlock_irqrestore(&device_domain_lock, flags);
1788
Yu Zhao93a23a72009-05-18 13:51:37 +08001789 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01001790 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001791 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001792 free_devinfo_mem(info);
1793
1794 spin_lock_irqsave(&device_domain_lock, flags);
1795 }
1796 spin_unlock_irqrestore(&device_domain_lock, flags);
1797}
1798
1799/*
1800 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001801 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001802 */
Kay, Allen M38717942008-09-09 18:37:29 +03001803static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001804find_domain(struct pci_dev *pdev)
1805{
1806 struct device_domain_info *info;
1807
1808 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001809 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001810 if (info)
1811 return info->domain;
1812 return NULL;
1813}
1814
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001815/* domain is initialized */
1816static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1817{
1818 struct dmar_domain *domain, *found = NULL;
1819 struct intel_iommu *iommu;
1820 struct dmar_drhd_unit *drhd;
1821 struct device_domain_info *info, *tmp;
1822 struct pci_dev *dev_tmp;
1823 unsigned long flags;
1824 int bus = 0, devfn = 0;
David Woodhouse276dbf92009-04-04 01:45:37 +01001825 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001826 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001827
1828 domain = find_domain(pdev);
1829 if (domain)
1830 return domain;
1831
David Woodhouse276dbf92009-04-04 01:45:37 +01001832 segment = pci_domain_nr(pdev->bus);
1833
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001834 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1835 if (dev_tmp) {
1836 if (dev_tmp->is_pcie) {
1837 bus = dev_tmp->subordinate->number;
1838 devfn = 0;
1839 } else {
1840 bus = dev_tmp->bus->number;
1841 devfn = dev_tmp->devfn;
1842 }
1843 spin_lock_irqsave(&device_domain_lock, flags);
1844 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001845 if (info->segment == segment &&
1846 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001847 found = info->domain;
1848 break;
1849 }
1850 }
1851 spin_unlock_irqrestore(&device_domain_lock, flags);
1852 /* pcie-pci bridge already has a domain, uses it */
1853 if (found) {
1854 domain = found;
1855 goto found_domain;
1856 }
1857 }
1858
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001859 domain = alloc_domain();
1860 if (!domain)
1861 goto error;
1862
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001863 /* Allocate new domain for the device */
1864 drhd = dmar_find_matched_drhd_unit(pdev);
1865 if (!drhd) {
1866 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
1867 pci_name(pdev));
1868 return NULL;
1869 }
1870 iommu = drhd->iommu;
1871
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001872 ret = iommu_attach_domain(domain, iommu);
1873 if (ret) {
1874 domain_exit(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001875 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001876 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001877
1878 if (domain_init(domain, gaw)) {
1879 domain_exit(domain);
1880 goto error;
1881 }
1882
1883 /* register pcie-to-pci device */
1884 if (dev_tmp) {
1885 info = alloc_devinfo_mem();
1886 if (!info) {
1887 domain_exit(domain);
1888 goto error;
1889 }
David Woodhouse276dbf92009-04-04 01:45:37 +01001890 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001891 info->bus = bus;
1892 info->devfn = devfn;
1893 info->dev = NULL;
1894 info->domain = domain;
1895 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08001896 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001897
1898 /* pcie-to-pci bridge already has a domain, uses it */
1899 found = NULL;
1900 spin_lock_irqsave(&device_domain_lock, flags);
1901 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001902 if (tmp->segment == segment &&
1903 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001904 found = tmp->domain;
1905 break;
1906 }
1907 }
1908 if (found) {
1909 free_devinfo_mem(info);
1910 domain_exit(domain);
1911 domain = found;
1912 } else {
1913 list_add(&info->link, &domain->devices);
1914 list_add(&info->global, &device_domain_list);
1915 }
1916 spin_unlock_irqrestore(&device_domain_lock, flags);
1917 }
1918
1919found_domain:
1920 info = alloc_devinfo_mem();
1921 if (!info)
1922 goto error;
David Woodhouse276dbf92009-04-04 01:45:37 +01001923 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001924 info->bus = pdev->bus->number;
1925 info->devfn = pdev->devfn;
1926 info->dev = pdev;
1927 info->domain = domain;
1928 spin_lock_irqsave(&device_domain_lock, flags);
1929 /* somebody is fast */
1930 found = find_domain(pdev);
1931 if (found != NULL) {
1932 spin_unlock_irqrestore(&device_domain_lock, flags);
1933 if (found != domain) {
1934 domain_exit(domain);
1935 domain = found;
1936 }
1937 free_devinfo_mem(info);
1938 return domain;
1939 }
1940 list_add(&info->link, &domain->devices);
1941 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001942 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001943 spin_unlock_irqrestore(&device_domain_lock, flags);
1944 return domain;
1945error:
1946 /* recheck it here, maybe others set it */
1947 return find_domain(pdev);
1948}
1949
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001950static int iommu_identity_mapping;
David Woodhousee0fc7e0b2009-09-30 09:12:17 -07001951#define IDENTMAP_ALL 1
1952#define IDENTMAP_GFX 2
1953#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001954
David Woodhouseb2132032009-06-26 18:50:28 +01001955static int iommu_domain_identity_map(struct dmar_domain *domain,
1956 unsigned long long start,
1957 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001958{
David Woodhousec5395d52009-06-28 16:35:56 +01001959 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
1960 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001961
David Woodhousec5395d52009-06-28 16:35:56 +01001962 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
1963 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001964 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01001965 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001966 }
1967
David Woodhousec5395d52009-06-28 16:35:56 +01001968 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
1969 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001970 /*
1971 * RMRR range might have overlap with physical memory range,
1972 * clear it first
1973 */
David Woodhousec5395d52009-06-28 16:35:56 +01001974 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001975
David Woodhousec5395d52009-06-28 16:35:56 +01001976 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
1977 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01001978 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01001979}
1980
1981static int iommu_prepare_identity_map(struct pci_dev *pdev,
1982 unsigned long long start,
1983 unsigned long long end)
1984{
1985 struct dmar_domain *domain;
1986 int ret;
1987
David Woodhousec7ab48d2009-06-26 19:10:36 +01001988 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01001989 if (!domain)
1990 return -ENOMEM;
1991
David Woodhouse19943b02009-08-04 16:19:20 +01001992 /* For _hardware_ passthrough, don't bother. But for software
1993 passthrough, we do it anyway -- it may indicate a memory
1994 range which is reserved in E820, so which didn't get set
1995 up to start with in si_domain */
1996 if (domain == si_domain && hw_pass_through) {
1997 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
1998 pci_name(pdev), start, end);
1999 return 0;
2000 }
2001
2002 printk(KERN_INFO
2003 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2004 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002005
David Woodhouse5595b522009-12-02 09:21:55 +00002006 if (end < start) {
2007 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2008 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2009 dmi_get_system_info(DMI_BIOS_VENDOR),
2010 dmi_get_system_info(DMI_BIOS_VERSION),
2011 dmi_get_system_info(DMI_PRODUCT_VERSION));
2012 ret = -EIO;
2013 goto error;
2014 }
2015
David Woodhouse2ff729f2009-08-26 14:25:41 +01002016 if (end >> agaw_to_width(domain->agaw)) {
2017 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2018 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2019 agaw_to_width(domain->agaw),
2020 dmi_get_system_info(DMI_BIOS_VENDOR),
2021 dmi_get_system_info(DMI_BIOS_VERSION),
2022 dmi_get_system_info(DMI_PRODUCT_VERSION));
2023 ret = -EIO;
2024 goto error;
2025 }
David Woodhouse19943b02009-08-04 16:19:20 +01002026
David Woodhouseb2132032009-06-26 18:50:28 +01002027 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002028 if (ret)
2029 goto error;
2030
2031 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002032 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002033 if (ret)
2034 goto error;
2035
2036 return 0;
2037
2038 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002039 domain_exit(domain);
2040 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002041}
2042
2043static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2044 struct pci_dev *pdev)
2045{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002046 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002047 return 0;
2048 return iommu_prepare_identity_map(pdev, rmrr->base_address,
2049 rmrr->end_address + 1);
2050}
2051
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002052#ifdef CONFIG_DMAR_FLOPPY_WA
2053static inline void iommu_prepare_isa(void)
2054{
2055 struct pci_dev *pdev;
2056 int ret;
2057
2058 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2059 if (!pdev)
2060 return;
2061
David Woodhousec7ab48d2009-06-26 19:10:36 +01002062 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002063 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
2064
2065 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002066 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2067 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002068
2069}
2070#else
2071static inline void iommu_prepare_isa(void)
2072{
2073 return;
2074}
2075#endif /* !CONFIG_DMAR_FLPY_WA */
2076
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002077static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002078
2079static int __init si_domain_work_fn(unsigned long start_pfn,
2080 unsigned long end_pfn, void *datax)
2081{
2082 int *ret = datax;
2083
2084 *ret = iommu_domain_identity_map(si_domain,
2085 (uint64_t)start_pfn << PAGE_SHIFT,
2086 (uint64_t)end_pfn << PAGE_SHIFT);
2087 return *ret;
2088
2089}
2090
Matt Kraai071e1372009-08-23 22:30:22 -07002091static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002092{
2093 struct dmar_drhd_unit *drhd;
2094 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002095 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002096
2097 si_domain = alloc_domain();
2098 if (!si_domain)
2099 return -EFAULT;
2100
David Woodhousec7ab48d2009-06-26 19:10:36 +01002101 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002102
2103 for_each_active_iommu(iommu, drhd) {
2104 ret = iommu_attach_domain(si_domain, iommu);
2105 if (ret) {
2106 domain_exit(si_domain);
2107 return -EFAULT;
2108 }
2109 }
2110
2111 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2112 domain_exit(si_domain);
2113 return -EFAULT;
2114 }
2115
2116 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2117
David Woodhouse19943b02009-08-04 16:19:20 +01002118 if (hw)
2119 return 0;
2120
David Woodhousec7ab48d2009-06-26 19:10:36 +01002121 for_each_online_node(nid) {
2122 work_with_active_regions(nid, si_domain_work_fn, &ret);
2123 if (ret)
2124 return ret;
2125 }
2126
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002127 return 0;
2128}
2129
2130static void domain_remove_one_dev_info(struct dmar_domain *domain,
2131 struct pci_dev *pdev);
2132static int identity_mapping(struct pci_dev *pdev)
2133{
2134 struct device_domain_info *info;
2135
2136 if (likely(!iommu_identity_mapping))
2137 return 0;
2138
2139
2140 list_for_each_entry(info, &si_domain->devices, link)
2141 if (info->dev == pdev)
2142 return 1;
2143 return 0;
2144}
2145
2146static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002147 struct pci_dev *pdev,
2148 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002149{
2150 struct device_domain_info *info;
2151 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002152 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002153
2154 info = alloc_devinfo_mem();
2155 if (!info)
2156 return -ENOMEM;
2157
David Woodhouse5fe60f42009-08-09 10:53:41 +01002158 ret = domain_context_mapping(domain, pdev, translation);
2159 if (ret) {
2160 free_devinfo_mem(info);
2161 return ret;
2162 }
2163
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002164 info->segment = pci_domain_nr(pdev->bus);
2165 info->bus = pdev->bus->number;
2166 info->devfn = pdev->devfn;
2167 info->dev = pdev;
2168 info->domain = domain;
2169
2170 spin_lock_irqsave(&device_domain_lock, flags);
2171 list_add(&info->link, &domain->devices);
2172 list_add(&info->global, &device_domain_list);
2173 pdev->dev.archdata.iommu = info;
2174 spin_unlock_irqrestore(&device_domain_lock, flags);
2175
2176 return 0;
2177}
2178
David Woodhouse6941af22009-07-04 18:24:27 +01002179static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2180{
David Woodhousee0fc7e0b2009-09-30 09:12:17 -07002181 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2182 return 1;
2183
2184 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2185 return 1;
2186
2187 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2188 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002189
David Woodhouse3dfc8132009-07-04 19:11:08 +01002190 /*
2191 * We want to start off with all devices in the 1:1 domain, and
2192 * take them out later if we find they can't access all of memory.
2193 *
2194 * However, we can't do this for PCI devices behind bridges,
2195 * because all PCI devices behind the same bridge will end up
2196 * with the same source-id on their transactions.
2197 *
2198 * Practically speaking, we can't change things around for these
2199 * devices at run-time, because we can't be sure there'll be no
2200 * DMA transactions in flight for any of their siblings.
2201 *
2202 * So PCI devices (unless they're on the root bus) as well as
2203 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2204 * the 1:1 domain, just in _case_ one of their siblings turns out
2205 * not to be able to map all of memory.
2206 */
2207 if (!pdev->is_pcie) {
2208 if (!pci_is_root_bus(pdev->bus))
2209 return 0;
2210 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2211 return 0;
2212 } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
2213 return 0;
2214
2215 /*
2216 * At boot time, we don't yet know if devices will be 64-bit capable.
2217 * Assume that they will -- if they turn out not to be, then we can
2218 * take them out of the 1:1 domain later.
2219 */
David Woodhouse6941af22009-07-04 18:24:27 +01002220 if (!startup)
2221 return pdev->dma_mask > DMA_BIT_MASK(32);
2222
2223 return 1;
2224}
2225
Matt Kraai071e1372009-08-23 22:30:22 -07002226static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002227{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002228 struct pci_dev *pdev = NULL;
2229 int ret;
2230
David Woodhouse19943b02009-08-04 16:19:20 +01002231 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002232 if (ret)
2233 return -EFAULT;
2234
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002235 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002236 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse19943b02009-08-04 16:19:20 +01002237 printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
2238 hw ? "hardware" : "software", pci_name(pdev));
David Woodhousec7ab48d2009-06-26 19:10:36 +01002239
David Woodhouse5fe60f42009-08-09 10:53:41 +01002240 ret = domain_add_dev_info(si_domain, pdev,
David Woodhouse19943b02009-08-04 16:19:20 +01002241 hw ? CONTEXT_TT_PASS_THROUGH :
David Woodhouse62edf5d2009-07-04 10:59:46 +01002242 CONTEXT_TT_MULTI_LEVEL);
2243 if (ret)
2244 return ret;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002245 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002246 }
2247
2248 return 0;
2249}
2250
2251int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002252{
2253 struct dmar_drhd_unit *drhd;
2254 struct dmar_rmrr_unit *rmrr;
2255 struct pci_dev *pdev;
2256 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002257 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002258
2259 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002260 * for each drhd
2261 * allocate root
2262 * initialize and program root entry to not present
2263 * endfor
2264 */
2265 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002266 g_num_of_iommus++;
2267 /*
2268 * lock not needed as this is only incremented in the single
2269 * threaded kernel __init code path all other access are read
2270 * only
2271 */
2272 }
2273
Weidong Hand9630fe2008-12-08 11:06:32 +08002274 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2275 GFP_KERNEL);
2276 if (!g_iommus) {
2277 printk(KERN_ERR "Allocating global iommu array failed\n");
2278 ret = -ENOMEM;
2279 goto error;
2280 }
2281
mark gross80b20dd2008-04-18 13:53:58 -07002282 deferred_flush = kzalloc(g_num_of_iommus *
2283 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2284 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002285 ret = -ENOMEM;
2286 goto error;
2287 }
2288
mark gross5e0d2a62008-03-04 15:22:08 -08002289 for_each_drhd_unit(drhd) {
2290 if (drhd->ignored)
2291 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002292
2293 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002294 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002295
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002296 ret = iommu_init_domains(iommu);
2297 if (ret)
2298 goto error;
2299
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002300 /*
2301 * TBD:
2302 * we could share the same root & context tables
2303 * amoung all IOMMU's. Need to Split it later.
2304 */
2305 ret = iommu_alloc_root_entry(iommu);
2306 if (ret) {
2307 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2308 goto error;
2309 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002310 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002311 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002312 }
2313
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002314 /*
2315 * Start from the sane iommu hardware state.
2316 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002317 for_each_drhd_unit(drhd) {
2318 if (drhd->ignored)
2319 continue;
2320
2321 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002322
2323 /*
2324 * If the queued invalidation is already initialized by us
2325 * (for example, while enabling interrupt-remapping) then
2326 * we got the things already rolling from a sane state.
2327 */
2328 if (iommu->qi)
2329 continue;
2330
2331 /*
2332 * Clear any previous faults.
2333 */
2334 dmar_fault(-1, iommu);
2335 /*
2336 * Disable queued invalidation if supported and already enabled
2337 * before OS handover.
2338 */
2339 dmar_disable_qi(iommu);
2340 }
2341
2342 for_each_drhd_unit(drhd) {
2343 if (drhd->ignored)
2344 continue;
2345
2346 iommu = drhd->iommu;
2347
Youquan Songa77b67d2008-10-16 16:31:56 -07002348 if (dmar_enable_qi(iommu)) {
2349 /*
2350 * Queued Invalidate not enabled, use Register Based
2351 * Invalidate
2352 */
2353 iommu->flush.flush_context = __iommu_flush_context;
2354 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
2355 printk(KERN_INFO "IOMMU 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002356 "invalidation\n",
2357 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002358 } else {
2359 iommu->flush.flush_context = qi_flush_context;
2360 iommu->flush.flush_iotlb = qi_flush_iotlb;
2361 printk(KERN_INFO "IOMMU 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002362 "invalidation\n",
2363 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002364 }
2365 }
2366
David Woodhouse19943b02009-08-04 16:19:20 +01002367 if (iommu_pass_through)
David Woodhousee0fc7e0b2009-09-30 09:12:17 -07002368 iommu_identity_mapping |= IDENTMAP_ALL;
2369
David Woodhouse19943b02009-08-04 16:19:20 +01002370#ifdef CONFIG_DMAR_BROKEN_GFX_WA
David Woodhousee0fc7e0b2009-09-30 09:12:17 -07002371 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002372#endif
David Woodhousee0fc7e0b2009-09-30 09:12:17 -07002373
2374 check_tylersburg_isoch();
2375
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002376 /*
2377 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002378 * identity mappings for rmrr, gfx, and isa and may fall back to static
2379 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002380 */
David Woodhouse19943b02009-08-04 16:19:20 +01002381 if (iommu_identity_mapping) {
2382 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2383 if (ret) {
2384 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2385 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002386 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002387 }
David Woodhouse19943b02009-08-04 16:19:20 +01002388 /*
2389 * For each rmrr
2390 * for each dev attached to rmrr
2391 * do
2392 * locate drhd for dev, alloc domain for dev
2393 * allocate free domain
2394 * allocate page table entries for rmrr
2395 * if context not allocated for bus
2396 * allocate and init context
2397 * set present in root table for this bus
2398 * init context with domain, translation etc
2399 * endfor
2400 * endfor
2401 */
2402 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2403 for_each_rmrr_units(rmrr) {
2404 for (i = 0; i < rmrr->devices_cnt; i++) {
2405 pdev = rmrr->devices[i];
2406 /*
2407 * some BIOS lists non-exist devices in DMAR
2408 * table.
2409 */
2410 if (!pdev)
2411 continue;
2412 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2413 if (ret)
2414 printk(KERN_ERR
2415 "IOMMU: mapping reserved region failed\n");
2416 }
2417 }
2418
2419 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002420
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002421 /*
2422 * for each drhd
2423 * enable fault log
2424 * global invalidate context cache
2425 * global invalidate iotlb
2426 * enable translation
2427 */
2428 for_each_drhd_unit(drhd) {
2429 if (drhd->ignored)
2430 continue;
2431 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002432
2433 iommu_flush_write_buffer(iommu);
2434
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002435 ret = dmar_set_interrupt(iommu);
2436 if (ret)
2437 goto error;
2438
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002439 iommu_set_root_entry(iommu);
2440
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002441 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002442 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002443
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002444 ret = iommu_enable_translation(iommu);
2445 if (ret)
2446 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002447
2448 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002449 }
2450
2451 return 0;
2452error:
2453 for_each_drhd_unit(drhd) {
2454 if (drhd->ignored)
2455 continue;
2456 iommu = drhd->iommu;
2457 free_iommu(iommu);
2458 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002459 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002460 return ret;
2461}
2462
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002463/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002464static struct iova *intel_alloc_iova(struct device *dev,
2465 struct dmar_domain *domain,
2466 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002467{
2468 struct pci_dev *pdev = to_pci_dev(dev);
2469 struct iova *iova = NULL;
2470
David Woodhouse875764d2009-06-28 21:20:51 +01002471 /* Restrict dma_mask to the width that the iommu can handle */
2472 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2473
2474 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002475 /*
2476 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002477 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002478 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002479 */
David Woodhouse875764d2009-06-28 21:20:51 +01002480 iova = alloc_iova(&domain->iovad, nrpages,
2481 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2482 if (iova)
2483 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002484 }
David Woodhouse875764d2009-06-28 21:20:51 +01002485 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2486 if (unlikely(!iova)) {
2487 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2488 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002489 return NULL;
2490 }
2491
2492 return iova;
2493}
2494
David Woodhouse147202a2009-07-07 19:43:20 +01002495static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002496{
2497 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002498 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002499
2500 domain = get_domain_for_dev(pdev,
2501 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2502 if (!domain) {
2503 printk(KERN_ERR
2504 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002505 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002506 }
2507
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002508 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002509 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002510 ret = domain_context_mapping(domain, pdev,
2511 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002512 if (ret) {
2513 printk(KERN_ERR
2514 "Domain context map for %s failed",
2515 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002516 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002517 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002518 }
2519
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002520 return domain;
2521}
2522
David Woodhouse147202a2009-07-07 19:43:20 +01002523static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2524{
2525 struct device_domain_info *info;
2526
2527 /* No lock here, assumes no domain exit in normal case */
2528 info = dev->dev.archdata.iommu;
2529 if (likely(info))
2530 return info->domain;
2531
2532 return __get_valid_domain_for_dev(dev);
2533}
2534
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002535static int iommu_dummy(struct pci_dev *pdev)
2536{
2537 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2538}
2539
2540/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002541static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002542{
David Woodhouse73676832009-07-04 14:08:36 +01002543 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002544 int found;
2545
David Woodhouse73676832009-07-04 14:08:36 +01002546 if (unlikely(dev->bus != &pci_bus_type))
2547 return 1;
2548
2549 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002550 if (iommu_dummy(pdev))
2551 return 1;
2552
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002553 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002554 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002555
2556 found = identity_mapping(pdev);
2557 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002558 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002559 return 1;
2560 else {
2561 /*
2562 * 32 bit DMA is removed from si_domain and fall back
2563 * to non-identity mapping.
2564 */
2565 domain_remove_one_dev_info(si_domain, pdev);
2566 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2567 pci_name(pdev));
2568 return 0;
2569 }
2570 } else {
2571 /*
2572 * In case of a detached 64 bit DMA device from vm, the device
2573 * is put into si_domain for identity mapping.
2574 */
David Woodhouse6941af22009-07-04 18:24:27 +01002575 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002576 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002577 ret = domain_add_dev_info(si_domain, pdev,
2578 hw_pass_through ?
2579 CONTEXT_TT_PASS_THROUGH :
2580 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002581 if (!ret) {
2582 printk(KERN_INFO "64bit %s uses identity mapping\n",
2583 pci_name(pdev));
2584 return 1;
2585 }
2586 }
2587 }
2588
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002589 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002590}
2591
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002592static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2593 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002594{
2595 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002596 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002597 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002598 struct iova *iova;
2599 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002600 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002601 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002602 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002603
2604 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002605
David Woodhouse73676832009-07-04 14:08:36 +01002606 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002607 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002608
2609 domain = get_valid_domain_for_dev(pdev);
2610 if (!domain)
2611 return 0;
2612
Weidong Han8c11e792008-12-08 15:29:22 +08002613 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002614 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002615
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002616 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
2617 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002618 if (!iova)
2619 goto error;
2620
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002621 /*
2622 * Check if DMAR supports zero-length reads on write only
2623 * mappings..
2624 */
2625 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002626 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002627 prot |= DMA_PTE_READ;
2628 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2629 prot |= DMA_PTE_WRITE;
2630 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002631 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002632 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002633 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002634 * is not a big problem
2635 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002636 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002637 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002638 if (ret)
2639 goto error;
2640
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002641 /* it's a non-present to present mapping. Only flush if caching mode */
2642 if (cap_caching_mode(iommu->cap))
David Woodhouse03d6a242009-06-28 15:33:46 +01002643 iommu_flush_iotlb_psi(iommu, 0, mm_to_dma_pfn(iova->pfn_lo), size);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002644 else
Weidong Han8c11e792008-12-08 15:29:22 +08002645 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002646
David Woodhouse03d6a242009-06-28 15:33:46 +01002647 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2648 start_paddr += paddr & ~PAGE_MASK;
2649 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002650
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002651error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002652 if (iova)
2653 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002654 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002655 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002656 return 0;
2657}
2658
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002659static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2660 unsigned long offset, size_t size,
2661 enum dma_data_direction dir,
2662 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002663{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002664 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2665 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002666}
2667
mark gross5e0d2a62008-03-04 15:22:08 -08002668static void flush_unmaps(void)
2669{
mark gross80b20dd2008-04-18 13:53:58 -07002670 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002671
mark gross5e0d2a62008-03-04 15:22:08 -08002672 timer_on = 0;
2673
2674 /* just flush them all */
2675 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002676 struct intel_iommu *iommu = g_iommus[i];
2677 if (!iommu)
2678 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002679
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002680 if (!deferred_flush[i].next)
2681 continue;
2682
2683 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002684 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002685 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002686 unsigned long mask;
2687 struct iova *iova = deferred_flush[i].iova[j];
2688
Benjamin LaHaise64de5af2009-09-16 21:05:55 -04002689 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
Yu Zhao93a23a72009-05-18 13:51:37 +08002690 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
Benjamin LaHaise64de5af2009-09-16 21:05:55 -04002691 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
Yu Zhao93a23a72009-05-18 13:51:37 +08002692 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002693 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002694 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002695 }
2696
mark gross5e0d2a62008-03-04 15:22:08 -08002697 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002698}
2699
2700static void flush_unmaps_timeout(unsigned long data)
2701{
mark gross80b20dd2008-04-18 13:53:58 -07002702 unsigned long flags;
2703
2704 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002705 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002706 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002707}
2708
2709static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2710{
2711 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002712 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002713 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002714
2715 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002716 if (list_size == HIGH_WATER_MARK)
2717 flush_unmaps();
2718
Weidong Han8c11e792008-12-08 15:29:22 +08002719 iommu = domain_get_iommu(dom);
2720 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002721
mark gross80b20dd2008-04-18 13:53:58 -07002722 next = deferred_flush[iommu_id].next;
2723 deferred_flush[iommu_id].domain[next] = dom;
2724 deferred_flush[iommu_id].iova[next] = iova;
2725 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002726
2727 if (!timer_on) {
2728 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2729 timer_on = 1;
2730 }
2731 list_size++;
2732 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2733}
2734
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002735static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2736 size_t size, enum dma_data_direction dir,
2737 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002738{
2739 struct pci_dev *pdev = to_pci_dev(dev);
2740 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002741 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002742 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002743 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002744
David Woodhouse73676832009-07-04 14:08:36 +01002745 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002746 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002747
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002748 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002749 BUG_ON(!domain);
2750
Weidong Han8c11e792008-12-08 15:29:22 +08002751 iommu = domain_get_iommu(domain);
2752
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002753 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002754 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2755 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002756 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002757
David Woodhoused794dc92009-06-28 00:27:49 +01002758 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2759 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002760
David Woodhoused794dc92009-06-28 00:27:49 +01002761 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2762 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002763
2764 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002765 dma_pte_clear_range(domain, start_pfn, last_pfn);
2766
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002767 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002768 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2769
mark gross5e0d2a62008-03-04 15:22:08 -08002770 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002771 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
David Woodhoused794dc92009-06-28 00:27:49 +01002772 last_pfn - start_pfn + 1);
mark gross5e0d2a62008-03-04 15:22:08 -08002773 /* free iova */
2774 __free_iova(&domain->iovad, iova);
2775 } else {
2776 add_unmap(domain, iova);
2777 /*
2778 * queue up the release of the unmap to save the 1/6th of the
2779 * cpu used up by the iotlb flush operation...
2780 */
mark gross5e0d2a62008-03-04 15:22:08 -08002781 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002782}
2783
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002784static void *intel_alloc_coherent(struct device *hwdev, size_t size,
2785 dma_addr_t *dma_handle, gfp_t flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002786{
2787 void *vaddr;
2788 int order;
2789
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002790 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002791 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002792
2793 if (!iommu_no_mapping(hwdev))
2794 flags &= ~(GFP_DMA | GFP_DMA32);
2795 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
2796 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
2797 flags |= GFP_DMA;
2798 else
2799 flags |= GFP_DMA32;
2800 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002801
2802 vaddr = (void *)__get_free_pages(flags, order);
2803 if (!vaddr)
2804 return NULL;
2805 memset(vaddr, 0, size);
2806
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002807 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2808 DMA_BIDIRECTIONAL,
2809 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002810 if (*dma_handle)
2811 return vaddr;
2812 free_pages((unsigned long)vaddr, order);
2813 return NULL;
2814}
2815
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002816static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
2817 dma_addr_t dma_handle)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002818{
2819 int order;
2820
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002821 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002822 order = get_order(size);
2823
David Woodhouse0db9b7a2009-07-14 02:01:57 +01002824 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002825 free_pages((unsigned long)vaddr, order);
2826}
2827
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002828static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
2829 int nelems, enum dma_data_direction dir,
2830 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002831{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002832 struct pci_dev *pdev = to_pci_dev(hwdev);
2833 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002834 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002835 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002836 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002837
David Woodhouse73676832009-07-04 14:08:36 +01002838 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002839 return;
2840
2841 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08002842 BUG_ON(!domain);
2843
2844 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002845
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002846 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01002847 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
2848 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002849 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002850
David Woodhoused794dc92009-06-28 00:27:49 +01002851 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2852 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002853
2854 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002855 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002856
David Woodhoused794dc92009-06-28 00:27:49 +01002857 /* free page tables */
2858 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2859
David Woodhouseacea0012009-07-14 01:55:11 +01002860 if (intel_iommu_strict) {
2861 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
2862 last_pfn - start_pfn + 1);
2863 /* free iova */
2864 __free_iova(&domain->iovad, iova);
2865 } else {
2866 add_unmap(domain, iova);
2867 /*
2868 * queue up the release of the unmap to save the 1/6th of the
2869 * cpu used up by the iotlb flush operation...
2870 */
2871 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002872}
2873
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002874static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002875 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002876{
2877 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002878 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002879
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002880 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002881 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00002882 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002883 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002884 }
2885 return nelems;
2886}
2887
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002888static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
2889 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002890{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002891 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002892 struct pci_dev *pdev = to_pci_dev(hwdev);
2893 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002894 size_t size = 0;
2895 int prot = 0;
David Woodhouseb536d242009-06-28 14:49:31 +01002896 size_t offset_pfn = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002897 struct iova *iova = NULL;
2898 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002899 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01002900 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08002901 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002902
2903 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01002904 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002905 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002906
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002907 domain = get_valid_domain_for_dev(pdev);
2908 if (!domain)
2909 return 0;
2910
Weidong Han8c11e792008-12-08 15:29:22 +08002911 iommu = domain_get_iommu(domain);
2912
David Woodhouseb536d242009-06-28 14:49:31 +01002913 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01002914 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002915
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002916 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
2917 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002918 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002919 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002920 return 0;
2921 }
2922
2923 /*
2924 * Check if DMAR supports zero-length reads on write only
2925 * mappings..
2926 */
2927 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002928 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002929 prot |= DMA_PTE_READ;
2930 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2931 prot |= DMA_PTE_WRITE;
2932
David Woodhouseb536d242009-06-28 14:49:31 +01002933 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01002934
Fenghua Yuf5329592009-08-04 15:09:37 -07002935 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01002936 if (unlikely(ret)) {
2937 /* clear the page */
2938 dma_pte_clear_range(domain, start_vpfn,
2939 start_vpfn + size - 1);
2940 /* free page tables */
2941 dma_pte_free_pagetable(domain, start_vpfn,
2942 start_vpfn + size - 1);
2943 /* free iova */
2944 __free_iova(&domain->iovad, iova);
2945 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002946 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002947
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002948 /* it's a non-present to present mapping. Only flush if caching mode */
2949 if (cap_caching_mode(iommu->cap))
David Woodhouse03d6a242009-06-28 15:33:46 +01002950 iommu_flush_iotlb_psi(iommu, 0, start_vpfn, offset_pfn);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002951 else
Weidong Han8c11e792008-12-08 15:29:22 +08002952 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002953
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002954 return nelems;
2955}
2956
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09002957static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
2958{
2959 return !dma_addr;
2960}
2961
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09002962struct dma_map_ops intel_dma_ops = {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002963 .alloc_coherent = intel_alloc_coherent,
2964 .free_coherent = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002965 .map_sg = intel_map_sg,
2966 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002967 .map_page = intel_map_page,
2968 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09002969 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002970};
2971
2972static inline int iommu_domain_cache_init(void)
2973{
2974 int ret = 0;
2975
2976 iommu_domain_cache = kmem_cache_create("iommu_domain",
2977 sizeof(struct dmar_domain),
2978 0,
2979 SLAB_HWCACHE_ALIGN,
2980
2981 NULL);
2982 if (!iommu_domain_cache) {
2983 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
2984 ret = -ENOMEM;
2985 }
2986
2987 return ret;
2988}
2989
2990static inline int iommu_devinfo_cache_init(void)
2991{
2992 int ret = 0;
2993
2994 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
2995 sizeof(struct device_domain_info),
2996 0,
2997 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002998 NULL);
2999 if (!iommu_devinfo_cache) {
3000 printk(KERN_ERR "Couldn't create devinfo cache\n");
3001 ret = -ENOMEM;
3002 }
3003
3004 return ret;
3005}
3006
3007static inline int iommu_iova_cache_init(void)
3008{
3009 int ret = 0;
3010
3011 iommu_iova_cache = kmem_cache_create("iommu_iova",
3012 sizeof(struct iova),
3013 0,
3014 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003015 NULL);
3016 if (!iommu_iova_cache) {
3017 printk(KERN_ERR "Couldn't create iova cache\n");
3018 ret = -ENOMEM;
3019 }
3020
3021 return ret;
3022}
3023
3024static int __init iommu_init_mempool(void)
3025{
3026 int ret;
3027 ret = iommu_iova_cache_init();
3028 if (ret)
3029 return ret;
3030
3031 ret = iommu_domain_cache_init();
3032 if (ret)
3033 goto domain_error;
3034
3035 ret = iommu_devinfo_cache_init();
3036 if (!ret)
3037 return ret;
3038
3039 kmem_cache_destroy(iommu_domain_cache);
3040domain_error:
3041 kmem_cache_destroy(iommu_iova_cache);
3042
3043 return -ENOMEM;
3044}
3045
3046static void __init iommu_exit_mempool(void)
3047{
3048 kmem_cache_destroy(iommu_devinfo_cache);
3049 kmem_cache_destroy(iommu_domain_cache);
3050 kmem_cache_destroy(iommu_iova_cache);
3051
3052}
3053
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003054static void __init init_no_remapping_devices(void)
3055{
3056 struct dmar_drhd_unit *drhd;
3057
3058 for_each_drhd_unit(drhd) {
3059 if (!drhd->include_all) {
3060 int i;
3061 for (i = 0; i < drhd->devices_cnt; i++)
3062 if (drhd->devices[i] != NULL)
3063 break;
3064 /* ignore DMAR unit if no pci devices exist */
3065 if (i == drhd->devices_cnt)
3066 drhd->ignored = 1;
3067 }
3068 }
3069
3070 if (dmar_map_gfx)
3071 return;
3072
3073 for_each_drhd_unit(drhd) {
3074 int i;
3075 if (drhd->ignored || drhd->include_all)
3076 continue;
3077
3078 for (i = 0; i < drhd->devices_cnt; i++)
3079 if (drhd->devices[i] &&
3080 !IS_GFX_DEVICE(drhd->devices[i]))
3081 break;
3082
3083 if (i < drhd->devices_cnt)
3084 continue;
3085
3086 /* bypass IOMMU if it is just for gfx devices */
3087 drhd->ignored = 1;
3088 for (i = 0; i < drhd->devices_cnt; i++) {
3089 if (!drhd->devices[i])
3090 continue;
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07003091 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003092 }
3093 }
3094}
3095
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003096#ifdef CONFIG_SUSPEND
3097static int init_iommu_hw(void)
3098{
3099 struct dmar_drhd_unit *drhd;
3100 struct intel_iommu *iommu = NULL;
3101
3102 for_each_active_iommu(iommu, drhd)
3103 if (iommu->qi)
3104 dmar_reenable_qi(iommu);
3105
3106 for_each_active_iommu(iommu, drhd) {
3107 iommu_flush_write_buffer(iommu);
3108
3109 iommu_set_root_entry(iommu);
3110
3111 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003112 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003113 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003114 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003115 iommu_enable_translation(iommu);
David Woodhouseb94996c2009-09-19 15:28:12 -07003116 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003117 }
3118
3119 return 0;
3120}
3121
3122static void iommu_flush_all(void)
3123{
3124 struct dmar_drhd_unit *drhd;
3125 struct intel_iommu *iommu;
3126
3127 for_each_active_iommu(iommu, drhd) {
3128 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003129 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003130 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003131 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003132 }
3133}
3134
3135static int iommu_suspend(struct sys_device *dev, pm_message_t state)
3136{
3137 struct dmar_drhd_unit *drhd;
3138 struct intel_iommu *iommu = NULL;
3139 unsigned long flag;
3140
3141 for_each_active_iommu(iommu, drhd) {
3142 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3143 GFP_ATOMIC);
3144 if (!iommu->iommu_state)
3145 goto nomem;
3146 }
3147
3148 iommu_flush_all();
3149
3150 for_each_active_iommu(iommu, drhd) {
3151 iommu_disable_translation(iommu);
3152
3153 spin_lock_irqsave(&iommu->register_lock, flag);
3154
3155 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3156 readl(iommu->reg + DMAR_FECTL_REG);
3157 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3158 readl(iommu->reg + DMAR_FEDATA_REG);
3159 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3160 readl(iommu->reg + DMAR_FEADDR_REG);
3161 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3162 readl(iommu->reg + DMAR_FEUADDR_REG);
3163
3164 spin_unlock_irqrestore(&iommu->register_lock, flag);
3165 }
3166 return 0;
3167
3168nomem:
3169 for_each_active_iommu(iommu, drhd)
3170 kfree(iommu->iommu_state);
3171
3172 return -ENOMEM;
3173}
3174
3175static int iommu_resume(struct sys_device *dev)
3176{
3177 struct dmar_drhd_unit *drhd;
3178 struct intel_iommu *iommu = NULL;
3179 unsigned long flag;
3180
3181 if (init_iommu_hw()) {
3182 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
3183 return -EIO;
3184 }
3185
3186 for_each_active_iommu(iommu, drhd) {
3187
3188 spin_lock_irqsave(&iommu->register_lock, flag);
3189
3190 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3191 iommu->reg + DMAR_FECTL_REG);
3192 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3193 iommu->reg + DMAR_FEDATA_REG);
3194 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3195 iommu->reg + DMAR_FEADDR_REG);
3196 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3197 iommu->reg + DMAR_FEUADDR_REG);
3198
3199 spin_unlock_irqrestore(&iommu->register_lock, flag);
3200 }
3201
3202 for_each_active_iommu(iommu, drhd)
3203 kfree(iommu->iommu_state);
3204
3205 return 0;
3206}
3207
3208static struct sysdev_class iommu_sysclass = {
3209 .name = "iommu",
3210 .resume = iommu_resume,
3211 .suspend = iommu_suspend,
3212};
3213
3214static struct sys_device device_iommu = {
3215 .cls = &iommu_sysclass,
3216};
3217
3218static int __init init_iommu_sysfs(void)
3219{
3220 int error;
3221
3222 error = sysdev_class_register(&iommu_sysclass);
3223 if (error)
3224 return error;
3225
3226 error = sysdev_register(&device_iommu);
3227 if (error)
3228 sysdev_class_unregister(&iommu_sysclass);
3229
3230 return error;
3231}
3232
3233#else
3234static int __init init_iommu_sysfs(void)
3235{
3236 return 0;
3237}
3238#endif /* CONFIG_PM */
3239
Fenghua Yu99dcade2009-11-11 07:23:06 -08003240/*
3241 * Here we only respond to action of unbound device from driver.
3242 *
3243 * Added device is not attached to its DMAR domain here yet. That will happen
3244 * when mapping the device to iova.
3245 */
3246static int device_notifier(struct notifier_block *nb,
3247 unsigned long action, void *data)
3248{
3249 struct device *dev = data;
3250 struct pci_dev *pdev = to_pci_dev(dev);
3251 struct dmar_domain *domain;
3252
David Woodhouse44cd6132009-12-02 10:18:30 +00003253 if (iommu_no_mapping(dev))
3254 return 0;
3255
Fenghua Yu99dcade2009-11-11 07:23:06 -08003256 domain = find_domain(pdev);
3257 if (!domain)
3258 return 0;
3259
3260 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through)
3261 domain_remove_one_dev_info(domain, pdev);
3262
3263 return 0;
3264}
3265
3266static struct notifier_block device_nb = {
3267 .notifier_call = device_notifier,
3268};
3269
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003270int __init intel_iommu_init(void)
3271{
3272 int ret = 0;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003273 int force_on = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003274
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003275 /* VT-d is required for a TXT/tboot launch, so enforce that */
3276 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003277
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003278 if (dmar_table_init()) {
3279 if (force_on)
3280 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003281 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003282 }
3283
3284 if (dmar_dev_scope_init()) {
3285 if (force_on)
3286 panic("tboot: Failed to initialize DMAR device scope\n");
3287 return -ENODEV;
3288 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003289
Suresh Siddha2ae21012008-07-10 11:16:43 -07003290 /*
3291 * Check the need for DMA-remapping initialization now.
3292 * Above initialization will also be used by Interrupt-remapping.
3293 */
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003294 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003295 return -ENODEV;
3296
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003297 iommu_init_mempool();
3298 dmar_init_reserved_ranges();
3299
3300 init_no_remapping_devices();
3301
3302 ret = init_dmars();
3303 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003304 if (force_on)
3305 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003306 printk(KERN_ERR "IOMMU: dmar init failed\n");
3307 put_iova_domain(&reserved_iova_list);
3308 iommu_exit_mempool();
3309 return ret;
3310 }
3311 printk(KERN_INFO
3312 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3313
mark gross5e0d2a62008-03-04 15:22:08 -08003314 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003315#ifdef CONFIG_SWIOTLB
3316 swiotlb = 0;
3317#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003318 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003319
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003320 init_iommu_sysfs();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003321
3322 register_iommu(&intel_iommu_ops);
3323
Fenghua Yu99dcade2009-11-11 07:23:06 -08003324 bus_register_notifier(&pci_bus_type, &device_nb);
3325
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003326 return 0;
3327}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003328
Han, Weidong3199aa62009-02-26 17:31:12 +08003329static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3330 struct pci_dev *pdev)
3331{
3332 struct pci_dev *tmp, *parent;
3333
3334 if (!iommu || !pdev)
3335 return;
3336
3337 /* dependent device detach */
3338 tmp = pci_find_upstream_pcie_bridge(pdev);
3339 /* Secondary interface's bus number and devfn 0 */
3340 if (tmp) {
3341 parent = pdev->bus->self;
3342 while (parent != tmp) {
3343 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01003344 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003345 parent = parent->bus->self;
3346 }
3347 if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
3348 iommu_detach_dev(iommu,
3349 tmp->subordinate->number, 0);
3350 else /* this is a legacy PCI bridge */
David Woodhouse276dbf92009-04-04 01:45:37 +01003351 iommu_detach_dev(iommu, tmp->bus->number,
3352 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003353 }
3354}
3355
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003356static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003357 struct pci_dev *pdev)
3358{
3359 struct device_domain_info *info;
3360 struct intel_iommu *iommu;
3361 unsigned long flags;
3362 int found = 0;
3363 struct list_head *entry, *tmp;
3364
David Woodhouse276dbf92009-04-04 01:45:37 +01003365 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3366 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003367 if (!iommu)
3368 return;
3369
3370 spin_lock_irqsave(&device_domain_lock, flags);
3371 list_for_each_safe(entry, tmp, &domain->devices) {
3372 info = list_entry(entry, struct device_domain_info, link);
David Woodhouse276dbf92009-04-04 01:45:37 +01003373 /* No need to compare PCI domain; it has to be the same */
Weidong Hanc7151a82008-12-08 22:51:37 +08003374 if (info->bus == pdev->bus->number &&
3375 info->devfn == pdev->devfn) {
3376 list_del(&info->link);
3377 list_del(&info->global);
3378 if (info->dev)
3379 info->dev->dev.archdata.iommu = NULL;
3380 spin_unlock_irqrestore(&device_domain_lock, flags);
3381
Yu Zhao93a23a72009-05-18 13:51:37 +08003382 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003383 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003384 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003385 free_devinfo_mem(info);
3386
3387 spin_lock_irqsave(&device_domain_lock, flags);
3388
3389 if (found)
3390 break;
3391 else
3392 continue;
3393 }
3394
3395 /* if there is no other devices under the same iommu
3396 * owned by this domain, clear this iommu in iommu_bmp
3397 * update iommu count and coherency
3398 */
David Woodhouse276dbf92009-04-04 01:45:37 +01003399 if (iommu == device_to_iommu(info->segment, info->bus,
3400 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003401 found = 1;
3402 }
3403
3404 if (found == 0) {
3405 unsigned long tmp_flags;
3406 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
3407 clear_bit(iommu->seq_id, &domain->iommu_bmp);
3408 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003409 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003410 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
3411 }
3412
3413 spin_unlock_irqrestore(&device_domain_lock, flags);
3414}
3415
3416static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3417{
3418 struct device_domain_info *info;
3419 struct intel_iommu *iommu;
3420 unsigned long flags1, flags2;
3421
3422 spin_lock_irqsave(&device_domain_lock, flags1);
3423 while (!list_empty(&domain->devices)) {
3424 info = list_entry(domain->devices.next,
3425 struct device_domain_info, link);
3426 list_del(&info->link);
3427 list_del(&info->global);
3428 if (info->dev)
3429 info->dev->dev.archdata.iommu = NULL;
3430
3431 spin_unlock_irqrestore(&device_domain_lock, flags1);
3432
Yu Zhao93a23a72009-05-18 13:51:37 +08003433 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01003434 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003435 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003436 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003437
3438 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003439 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003440 */
3441 spin_lock_irqsave(&domain->iommu_lock, flags2);
3442 if (test_and_clear_bit(iommu->seq_id,
3443 &domain->iommu_bmp)) {
3444 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003445 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003446 }
3447 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3448
3449 free_devinfo_mem(info);
3450 spin_lock_irqsave(&device_domain_lock, flags1);
3451 }
3452 spin_unlock_irqrestore(&device_domain_lock, flags1);
3453}
3454
Weidong Han5e98c4b2008-12-08 23:03:27 +08003455/* domain id for virtual machine, it won't be set in context */
3456static unsigned long vm_domid;
3457
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003458static int vm_domain_min_agaw(struct dmar_domain *domain)
3459{
3460 int i;
3461 int min_agaw = domain->agaw;
3462
3463 i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
3464 for (; i < g_num_of_iommus; ) {
3465 if (min_agaw > g_iommus[i]->agaw)
3466 min_agaw = g_iommus[i]->agaw;
3467
3468 i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
3469 }
3470
3471 return min_agaw;
3472}
3473
Weidong Han5e98c4b2008-12-08 23:03:27 +08003474static struct dmar_domain *iommu_alloc_vm_domain(void)
3475{
3476 struct dmar_domain *domain;
3477
3478 domain = alloc_domain_mem();
3479 if (!domain)
3480 return NULL;
3481
3482 domain->id = vm_domid++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003483 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003484 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
3485 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3486
3487 return domain;
3488}
3489
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003490static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003491{
3492 int adjust_width;
3493
3494 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003495 spin_lock_init(&domain->iommu_lock);
3496
3497 domain_reserve_special_ranges(domain);
3498
3499 /* calculate AGAW */
3500 domain->gaw = guest_width;
3501 adjust_width = guestwidth_to_adjustwidth(guest_width);
3502 domain->agaw = width_to_agaw(adjust_width);
3503
3504 INIT_LIST_HEAD(&domain->devices);
3505
3506 domain->iommu_count = 0;
3507 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003508 domain->iommu_snooping = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003509 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003510 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003511
3512 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003513 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003514 if (!domain->pgd)
3515 return -ENOMEM;
3516 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3517 return 0;
3518}
3519
3520static void iommu_free_vm_domain(struct dmar_domain *domain)
3521{
3522 unsigned long flags;
3523 struct dmar_drhd_unit *drhd;
3524 struct intel_iommu *iommu;
3525 unsigned long i;
3526 unsigned long ndomains;
3527
3528 for_each_drhd_unit(drhd) {
3529 if (drhd->ignored)
3530 continue;
3531 iommu = drhd->iommu;
3532
3533 ndomains = cap_ndoms(iommu->cap);
3534 i = find_first_bit(iommu->domain_ids, ndomains);
3535 for (; i < ndomains; ) {
3536 if (iommu->domains[i] == domain) {
3537 spin_lock_irqsave(&iommu->lock, flags);
3538 clear_bit(i, iommu->domain_ids);
3539 iommu->domains[i] = NULL;
3540 spin_unlock_irqrestore(&iommu->lock, flags);
3541 break;
3542 }
3543 i = find_next_bit(iommu->domain_ids, ndomains, i+1);
3544 }
3545 }
3546}
3547
3548static void vm_domain_exit(struct dmar_domain *domain)
3549{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003550 /* Domain 0 is reserved, so dont process it */
3551 if (!domain)
3552 return;
3553
3554 vm_domain_remove_all_dev_info(domain);
3555 /* destroy iovas */
3556 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003557
3558 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003559 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003560
3561 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003562 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003563
3564 iommu_free_vm_domain(domain);
3565 free_domain_mem(domain);
3566}
3567
Joerg Roedel5d450802008-12-03 14:52:32 +01003568static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003569{
Joerg Roedel5d450802008-12-03 14:52:32 +01003570 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003571
Joerg Roedel5d450802008-12-03 14:52:32 +01003572 dmar_domain = iommu_alloc_vm_domain();
3573 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003574 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003575 "intel_iommu_domain_init: dmar_domain == NULL\n");
3576 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003577 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003578 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003579 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003580 "intel_iommu_domain_init() failed\n");
3581 vm_domain_exit(dmar_domain);
3582 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003583 }
Joerg Roedel5d450802008-12-03 14:52:32 +01003584 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003585
Joerg Roedel5d450802008-12-03 14:52:32 +01003586 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003587}
Kay, Allen M38717942008-09-09 18:37:29 +03003588
Joerg Roedel5d450802008-12-03 14:52:32 +01003589static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003590{
Joerg Roedel5d450802008-12-03 14:52:32 +01003591 struct dmar_domain *dmar_domain = domain->priv;
3592
3593 domain->priv = NULL;
3594 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003595}
Kay, Allen M38717942008-09-09 18:37:29 +03003596
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003597static int intel_iommu_attach_device(struct iommu_domain *domain,
3598 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003599{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003600 struct dmar_domain *dmar_domain = domain->priv;
3601 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003602 struct intel_iommu *iommu;
3603 int addr_width;
3604 u64 end;
Kay, Allen M38717942008-09-09 18:37:29 +03003605
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003606 /* normally pdev is not mapped */
3607 if (unlikely(domain_context_mapped(pdev))) {
3608 struct dmar_domain *old_domain;
3609
3610 old_domain = find_domain(pdev);
3611 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003612 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3613 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3614 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003615 else
3616 domain_remove_dev_info(old_domain);
3617 }
3618 }
3619
David Woodhouse276dbf92009-04-04 01:45:37 +01003620 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3621 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003622 if (!iommu)
3623 return -ENODEV;
3624
3625 /* check if this iommu agaw is sufficient for max mapped address */
3626 addr_width = agaw_to_width(iommu->agaw);
3627 end = DOMAIN_MAX_ADDR(addr_width);
3628 end = end & VTD_PAGE_MASK;
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003629 if (end < dmar_domain->max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003630 printk(KERN_ERR "%s: iommu agaw (%d) is not "
3631 "sufficient for the mapped address (%llx)\n",
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003632 __func__, iommu->agaw, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003633 return -EFAULT;
3634 }
3635
David Woodhouse5fe60f42009-08-09 10:53:41 +01003636 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003637}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003638
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003639static void intel_iommu_detach_device(struct iommu_domain *domain,
3640 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003641{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003642 struct dmar_domain *dmar_domain = domain->priv;
3643 struct pci_dev *pdev = to_pci_dev(dev);
3644
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003645 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003646}
Kay, Allen M38717942008-09-09 18:37:29 +03003647
Joerg Roedeldde57a22008-12-03 15:04:09 +01003648static int intel_iommu_map_range(struct iommu_domain *domain,
3649 unsigned long iova, phys_addr_t hpa,
3650 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003651{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003652 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003653 u64 max_addr;
3654 int addr_width;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003655 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003656 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003657
Joerg Roedeldde57a22008-12-03 15:04:09 +01003658 if (iommu_prot & IOMMU_READ)
3659 prot |= DMA_PTE_READ;
3660 if (iommu_prot & IOMMU_WRITE)
3661 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08003662 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
3663 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003664
David Woodhouse163cc522009-06-28 00:51:17 +01003665 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003666 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003667 int min_agaw;
3668 u64 end;
3669
3670 /* check if minimum agaw is sufficient for mapped address */
Joerg Roedeldde57a22008-12-03 15:04:09 +01003671 min_agaw = vm_domain_min_agaw(dmar_domain);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003672 addr_width = agaw_to_width(min_agaw);
3673 end = DOMAIN_MAX_ADDR(addr_width);
3674 end = end & VTD_PAGE_MASK;
3675 if (end < max_addr) {
3676 printk(KERN_ERR "%s: iommu agaw (%d) is not "
3677 "sufficient for the mapped address (%llx)\n",
3678 __func__, min_agaw, max_addr);
3679 return -EFAULT;
3680 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003681 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003682 }
David Woodhousead051222009-06-28 14:22:28 +01003683 /* Round up size to next multiple of PAGE_SIZE, if it and
3684 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01003685 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01003686 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
3687 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003688 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003689}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003690
Joerg Roedeldde57a22008-12-03 15:04:09 +01003691static void intel_iommu_unmap_range(struct iommu_domain *domain,
3692 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003693{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003694 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003695
Sheng Yang4b99d352009-07-08 11:52:52 +01003696 if (!size)
3697 return;
3698
David Woodhouse163cc522009-06-28 00:51:17 +01003699 dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
3700 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003701
David Woodhouse163cc522009-06-28 00:51:17 +01003702 if (dmar_domain->max_addr == iova + size)
3703 dmar_domain->max_addr = iova;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003704}
Kay, Allen M38717942008-09-09 18:37:29 +03003705
Joerg Roedeld14d6572008-12-03 15:06:57 +01003706static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
3707 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03003708{
Joerg Roedeld14d6572008-12-03 15:06:57 +01003709 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03003710 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003711 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003712
David Woodhouseb026fd22009-06-28 10:37:25 +01003713 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
Kay, Allen M38717942008-09-09 18:37:29 +03003714 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003715 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03003716
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003717 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03003718}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003719
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003720static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
3721 unsigned long cap)
3722{
3723 struct dmar_domain *dmar_domain = domain->priv;
3724
3725 if (cap == IOMMU_CAP_CACHE_COHERENCY)
3726 return dmar_domain->iommu_snooping;
3727
3728 return 0;
3729}
3730
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003731static struct iommu_ops intel_iommu_ops = {
3732 .domain_init = intel_iommu_domain_init,
3733 .domain_destroy = intel_iommu_domain_destroy,
3734 .attach_dev = intel_iommu_attach_device,
3735 .detach_dev = intel_iommu_detach_device,
3736 .map = intel_iommu_map_range,
3737 .unmap = intel_iommu_unmap_range,
3738 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003739 .domain_has_cap = intel_iommu_domain_has_cap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003740};
David Woodhouse9af88142009-02-13 23:18:03 +00003741
3742static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
3743{
3744 /*
3745 * Mobile 4 Series Chipset neglects to set RWBF capability,
3746 * but needs it:
3747 */
3748 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
3749 rwbf_quirk = 1;
3750}
3751
3752DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
David Woodhousee0fc7e0b2009-09-30 09:12:17 -07003753
3754/* On Tylersburg chipsets, some BIOSes have been known to enable the
3755 ISOCH DMAR unit for the Azalia sound device, but not give it any
3756 TLB entries, which causes it to deadlock. Check for that. We do
3757 this in a function called from init_dmars(), instead of in a PCI
3758 quirk, because we don't want to print the obnoxious "BIOS broken"
3759 message if VT-d is actually disabled.
3760*/
3761static void __init check_tylersburg_isoch(void)
3762{
3763 struct pci_dev *pdev;
3764 uint32_t vtisochctrl;
3765
3766 /* If there's no Azalia in the system anyway, forget it. */
3767 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
3768 if (!pdev)
3769 return;
3770 pci_dev_put(pdev);
3771
3772 /* System Management Registers. Might be hidden, in which case
3773 we can't do the sanity check. But that's OK, because the
3774 known-broken BIOSes _don't_ actually hide it, so far. */
3775 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
3776 if (!pdev)
3777 return;
3778
3779 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
3780 pci_dev_put(pdev);
3781 return;
3782 }
3783
3784 pci_dev_put(pdev);
3785
3786 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
3787 if (vtisochctrl & 1)
3788 return;
3789
3790 /* Drop all bits other than the number of TLB entries */
3791 vtisochctrl &= 0x1c;
3792
3793 /* If we have the recommended number of TLB entries (16), fine. */
3794 if (vtisochctrl == 0x10)
3795 return;
3796
3797 /* Zero TLB entries? You get to ride the short bus to school. */
3798 if (!vtisochctrl) {
3799 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
3800 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
3801 dmi_get_system_info(DMI_BIOS_VENDOR),
3802 dmi_get_system_info(DMI_BIOS_VERSION),
3803 dmi_get_system_info(DMI_PRODUCT_VERSION));
3804 iommu_identity_mapping |= IDENTMAP_AZALIA;
3805 return;
3806 }
3807
3808 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
3809 vtisochctrl);
3810}