blob: fdb2cef2b908c0eb49af219538bc470d306810ed [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>
Rafael J. Wysocki134fac32011-03-23 22:16:14 +010039#include <linux/syscore_ops.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>
Joerg Roedel5cdede22011-04-04 15:55:18 +020042#include <linux/pci-ats.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070043#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090044#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070045#include "pci.h"
46
Fenghua Yu5b6985c2008-10-16 18:02:32 -070047#define ROOT_SIZE VTD_PAGE_SIZE
48#define CONTEXT_SIZE VTD_PAGE_SIZE
49
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070050#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
51#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070052#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070053
54#define IOAPIC_RANGE_START (0xfee00000)
55#define IOAPIC_RANGE_END (0xfeefffff)
56#define IOVA_START_ADDR (0x1000)
57
58#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
59
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070060#define MAX_AGAW_WIDTH 64
61
David Woodhouse2ebe3152009-09-19 07:34:04 -070062#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
63#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
64
65/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
66 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
67#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
68 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
69#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070070
Mark McLoughlinf27be032008-11-20 15:49:43 +000071#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070072#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070073#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080074
Andrew Mortondf08cdc2010-09-22 13:05:11 -070075/* page table handling */
76#define LEVEL_STRIDE (9)
77#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
78
79static inline int agaw_to_level(int agaw)
80{
81 return agaw + 2;
82}
83
84static inline int agaw_to_width(int agaw)
85{
86 return 30 + agaw * LEVEL_STRIDE;
87}
88
89static inline int width_to_agaw(int width)
90{
91 return (width - 30) / LEVEL_STRIDE;
92}
93
94static inline unsigned int level_to_offset_bits(int level)
95{
96 return (level - 1) * LEVEL_STRIDE;
97}
98
99static inline int pfn_level_offset(unsigned long pfn, int level)
100{
101 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
102}
103
104static inline unsigned long level_mask(int level)
105{
106 return -1UL << level_to_offset_bits(level);
107}
108
109static inline unsigned long level_size(int level)
110{
111 return 1UL << level_to_offset_bits(level);
112}
113
114static inline unsigned long align_to_level(unsigned long pfn, int level)
115{
116 return (pfn + level_size(level) - 1) & level_mask(level);
117}
David Woodhousefd18de52009-05-10 23:57:41 +0100118
David Woodhousedd4e8312009-06-27 16:21:20 +0100119/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
120 are never going to work. */
121static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
122{
123 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
124}
125
126static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
127{
128 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
129}
130static inline unsigned long page_to_dma_pfn(struct page *pg)
131{
132 return mm_to_dma_pfn(page_to_pfn(pg));
133}
134static inline unsigned long virt_to_dma_pfn(void *p)
135{
136 return page_to_dma_pfn(virt_to_page(p));
137}
138
Weidong Hand9630fe2008-12-08 11:06:32 +0800139/* global iommu list, set NULL for ignored DMAR units */
140static struct intel_iommu **g_iommus;
141
David Woodhousee0fc7e02009-09-30 09:12:17 -0700142static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000143static int rwbf_quirk;
144
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000145/*
146 * 0: Present
147 * 1-11: Reserved
148 * 12-63: Context Ptr (12 - (haw-1))
149 * 64-127: Reserved
150 */
151struct root_entry {
152 u64 val;
153 u64 rsvd1;
154};
155#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
156static inline bool root_present(struct root_entry *root)
157{
158 return (root->val & 1);
159}
160static inline void set_root_present(struct root_entry *root)
161{
162 root->val |= 1;
163}
164static inline void set_root_value(struct root_entry *root, unsigned long value)
165{
166 root->val |= value & VTD_PAGE_MASK;
167}
168
169static inline struct context_entry *
170get_context_addr_from_root(struct root_entry *root)
171{
172 return (struct context_entry *)
173 (root_present(root)?phys_to_virt(
174 root->val & VTD_PAGE_MASK) :
175 NULL);
176}
177
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000178/*
179 * low 64 bits:
180 * 0: present
181 * 1: fault processing disable
182 * 2-3: translation type
183 * 12-63: address space root
184 * high 64 bits:
185 * 0-2: address width
186 * 3-6: aval
187 * 8-23: domain id
188 */
189struct context_entry {
190 u64 lo;
191 u64 hi;
192};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000193
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000194static inline bool context_present(struct context_entry *context)
195{
196 return (context->lo & 1);
197}
198static inline void context_set_present(struct context_entry *context)
199{
200 context->lo |= 1;
201}
202
203static inline void context_set_fault_enable(struct context_entry *context)
204{
205 context->lo &= (((u64)-1) << 2) | 1;
206}
207
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000208static inline void context_set_translation_type(struct context_entry *context,
209 unsigned long value)
210{
211 context->lo &= (((u64)-1) << 4) | 3;
212 context->lo |= (value & 3) << 2;
213}
214
215static inline void context_set_address_root(struct context_entry *context,
216 unsigned long value)
217{
218 context->lo |= value & VTD_PAGE_MASK;
219}
220
221static inline void context_set_address_width(struct context_entry *context,
222 unsigned long value)
223{
224 context->hi |= value & 7;
225}
226
227static inline void context_set_domain_id(struct context_entry *context,
228 unsigned long value)
229{
230 context->hi |= (value & ((1 << 16) - 1)) << 8;
231}
232
233static inline void context_clear_entry(struct context_entry *context)
234{
235 context->lo = 0;
236 context->hi = 0;
237}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000238
Mark McLoughlin622ba122008-11-20 15:49:46 +0000239/*
240 * 0: readable
241 * 1: writable
242 * 2-6: reserved
243 * 7: super page
Sheng Yang9cf066972009-03-18 15:33:07 +0800244 * 8-10: available
245 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000246 * 12-63: Host physcial address
247 */
248struct dma_pte {
249 u64 val;
250};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000251
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000252static inline void dma_clear_pte(struct dma_pte *pte)
253{
254 pte->val = 0;
255}
256
257static inline void dma_set_pte_readable(struct dma_pte *pte)
258{
259 pte->val |= DMA_PTE_READ;
260}
261
262static inline void dma_set_pte_writable(struct dma_pte *pte)
263{
264 pte->val |= DMA_PTE_WRITE;
265}
266
Sheng Yang9cf066972009-03-18 15:33:07 +0800267static inline void dma_set_pte_snp(struct dma_pte *pte)
268{
269 pte->val |= DMA_PTE_SNP;
270}
271
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000272static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
273{
274 pte->val = (pte->val & ~3) | (prot & 3);
275}
276
277static inline u64 dma_pte_addr(struct dma_pte *pte)
278{
David Woodhousec85994e2009-07-01 19:21:24 +0100279#ifdef CONFIG_64BIT
280 return pte->val & VTD_PAGE_MASK;
281#else
282 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100283 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100284#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000285}
286
David Woodhousedd4e8312009-06-27 16:21:20 +0100287static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000288{
David Woodhousedd4e8312009-06-27 16:21:20 +0100289 pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000290}
291
292static inline bool dma_pte_present(struct dma_pte *pte)
293{
294 return (pte->val & 3) != 0;
295}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000296
David Woodhouse75e6bf92009-07-02 11:21:16 +0100297static inline int first_pte_in_page(struct dma_pte *pte)
298{
299 return !((unsigned long)pte & ~VTD_PAGE_MASK);
300}
301
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700302/*
303 * This domain is a statically identity mapping domain.
304 * 1. This domain creats a static 1:1 mapping to all usable memory.
305 * 2. It maps to each iommu if successful.
306 * 3. Each iommu mapps to this domain if successful.
307 */
David Woodhouse19943b02009-08-04 16:19:20 +0100308static struct dmar_domain *si_domain;
309static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700310
Weidong Han3b5410e2008-12-08 09:17:15 +0800311/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100312#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800313
Weidong Han1ce28fe2008-12-08 16:35:39 +0800314/* domain represents a virtual machine, more than one devices
315 * across iommus may be owned in one domain, e.g. kvm guest.
316 */
317#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
318
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700319/* si_domain contains mulitple devices */
320#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
321
Mark McLoughlin99126f72008-11-20 15:49:47 +0000322struct dmar_domain {
323 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700324 int nid; /* node id */
Weidong Han8c11e792008-12-08 15:29:22 +0800325 unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000326
327 struct list_head devices; /* all devices' list */
328 struct iova_domain iovad; /* iova's that belong to this domain */
329
330 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000331 int gaw; /* max guest address width */
332
333 /* adjusted guest address width, 0 is level 2 30-bit */
334 int agaw;
335
Weidong Han3b5410e2008-12-08 09:17:15 +0800336 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800337
338 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800339 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800340 int iommu_count; /* reference count of iommu */
341 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800342 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000343};
344
Mark McLoughlina647dac2008-11-20 15:49:48 +0000345/* PCI domain-device relationship */
346struct device_domain_info {
347 struct list_head link; /* link to domain siblings */
348 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100349 int segment; /* PCI domain */
350 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000351 u8 devfn; /* PCI devfn number */
Stefan Assmann45e829e2009-12-03 06:49:24 -0500352 struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800353 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000354 struct dmar_domain *domain; /* pointer to domain */
355};
356
mark gross5e0d2a62008-03-04 15:22:08 -0800357static void flush_unmaps_timeout(unsigned long data);
358
359DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
360
mark gross80b20dd2008-04-18 13:53:58 -0700361#define HIGH_WATER_MARK 250
362struct deferred_flush_tables {
363 int next;
364 struct iova *iova[HIGH_WATER_MARK];
365 struct dmar_domain *domain[HIGH_WATER_MARK];
366};
367
368static struct deferred_flush_tables *deferred_flush;
369
mark gross5e0d2a62008-03-04 15:22:08 -0800370/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800371static int g_num_of_iommus;
372
373static DEFINE_SPINLOCK(async_umap_flush_lock);
374static LIST_HEAD(unmaps_to_do);
375
376static int timer_on;
377static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800378
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700379static void domain_remove_dev_info(struct dmar_domain *domain);
380
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800381#ifdef CONFIG_DMAR_DEFAULT_ON
382int dmar_disabled = 0;
383#else
384int dmar_disabled = 1;
385#endif /*CONFIG_DMAR_DEFAULT_ON*/
386
David Woodhouse2d9e6672010-06-15 10:57:57 +0100387static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700388static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800389static int intel_iommu_strict;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700390
391#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
392static DEFINE_SPINLOCK(device_domain_lock);
393static LIST_HEAD(device_domain_list);
394
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100395static struct iommu_ops intel_iommu_ops;
396
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700397static int __init intel_iommu_setup(char *str)
398{
399 if (!str)
400 return -EINVAL;
401 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800402 if (!strncmp(str, "on", 2)) {
403 dmar_disabled = 0;
404 printk(KERN_INFO "Intel-IOMMU: enabled\n");
405 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700406 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800407 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700408 } else if (!strncmp(str, "igfx_off", 8)) {
409 dmar_map_gfx = 0;
410 printk(KERN_INFO
411 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700412 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800413 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700414 "Intel-IOMMU: Forcing DAC for PCI devices\n");
415 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800416 } else if (!strncmp(str, "strict", 6)) {
417 printk(KERN_INFO
418 "Intel-IOMMU: disable batched IOTLB flush\n");
419 intel_iommu_strict = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700420 }
421
422 str += strcspn(str, ",");
423 while (*str == ',')
424 str++;
425 }
426 return 0;
427}
428__setup("intel_iommu=", intel_iommu_setup);
429
430static struct kmem_cache *iommu_domain_cache;
431static struct kmem_cache *iommu_devinfo_cache;
432static struct kmem_cache *iommu_iova_cache;
433
Suresh Siddha4c923d42009-10-02 11:01:24 -0700434static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700435{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700436 struct page *page;
437 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700438
Suresh Siddha4c923d42009-10-02 11:01:24 -0700439 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
440 if (page)
441 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700442 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700443}
444
445static inline void free_pgtable_page(void *vaddr)
446{
447 free_page((unsigned long)vaddr);
448}
449
450static inline void *alloc_domain_mem(void)
451{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900452 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700453}
454
Kay, Allen M38717942008-09-09 18:37:29 +0300455static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700456{
457 kmem_cache_free(iommu_domain_cache, vaddr);
458}
459
460static inline void * alloc_devinfo_mem(void)
461{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900462 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700463}
464
465static inline void free_devinfo_mem(void *vaddr)
466{
467 kmem_cache_free(iommu_devinfo_cache, vaddr);
468}
469
470struct iova *alloc_iova_mem(void)
471{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900472 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700473}
474
475void free_iova_mem(struct iova *iova)
476{
477 kmem_cache_free(iommu_iova_cache, iova);
478}
479
Weidong Han1b573682008-12-08 15:34:06 +0800480
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700481static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800482{
483 unsigned long sagaw;
484 int agaw = -1;
485
486 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700487 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800488 agaw >= 0; agaw--) {
489 if (test_bit(agaw, &sagaw))
490 break;
491 }
492
493 return agaw;
494}
495
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700496/*
497 * Calculate max SAGAW for each iommu.
498 */
499int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
500{
501 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
502}
503
504/*
505 * calculate agaw for each iommu.
506 * "SAGAW" may be different across iommus, use a default agaw, and
507 * get a supported less agaw for iommus that don't support the default agaw.
508 */
509int iommu_calculate_agaw(struct intel_iommu *iommu)
510{
511 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
512}
513
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700514/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800515static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
516{
517 int iommu_id;
518
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700519 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800520 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700521 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800522
Weidong Han8c11e792008-12-08 15:29:22 +0800523 iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
524 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
525 return NULL;
526
527 return g_iommus[iommu_id];
528}
529
Weidong Han8e6040972008-12-08 15:49:06 +0800530static void domain_update_iommu_coherency(struct dmar_domain *domain)
531{
532 int i;
533
534 domain->iommu_coherency = 1;
535
Akinobu Mitaa45946a2010-03-11 14:04:08 -0800536 for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e6040972008-12-08 15:49:06 +0800537 if (!ecap_coherent(g_iommus[i]->ecap)) {
538 domain->iommu_coherency = 0;
539 break;
540 }
Weidong Han8e6040972008-12-08 15:49:06 +0800541 }
542}
543
Sheng Yang58c610b2009-03-18 15:33:05 +0800544static void domain_update_iommu_snooping(struct dmar_domain *domain)
545{
546 int i;
547
548 domain->iommu_snooping = 1;
549
Akinobu Mitaa45946a2010-03-11 14:04:08 -0800550 for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800551 if (!ecap_sc_support(g_iommus[i]->ecap)) {
552 domain->iommu_snooping = 0;
553 break;
554 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800555 }
556}
557
558/* Some capabilities may be different across iommus */
559static void domain_update_iommu_cap(struct dmar_domain *domain)
560{
561 domain_update_iommu_coherency(domain);
562 domain_update_iommu_snooping(domain);
563}
564
David Woodhouse276dbf992009-04-04 01:45:37 +0100565static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800566{
567 struct dmar_drhd_unit *drhd = NULL;
568 int i;
569
570 for_each_drhd_unit(drhd) {
571 if (drhd->ignored)
572 continue;
David Woodhouse276dbf992009-04-04 01:45:37 +0100573 if (segment != drhd->segment)
574 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800575
David Woodhouse924b6232009-04-04 00:39:25 +0100576 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000577 if (drhd->devices[i] &&
578 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800579 drhd->devices[i]->devfn == devfn)
580 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700581 if (drhd->devices[i] &&
582 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100583 drhd->devices[i]->subordinate->number <= bus &&
584 drhd->devices[i]->subordinate->subordinate >= bus)
585 return drhd->iommu;
586 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800587
588 if (drhd->include_all)
589 return drhd->iommu;
590 }
591
592 return NULL;
593}
594
Weidong Han5331fe62008-12-08 23:00:00 +0800595static void domain_flush_cache(struct dmar_domain *domain,
596 void *addr, int size)
597{
598 if (!domain->iommu_coherency)
599 clflush_cache_range(addr, size);
600}
601
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700602/* Gets context entry for a given bus and devfn */
603static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
604 u8 bus, u8 devfn)
605{
606 struct root_entry *root;
607 struct context_entry *context;
608 unsigned long phy_addr;
609 unsigned long flags;
610
611 spin_lock_irqsave(&iommu->lock, flags);
612 root = &iommu->root_entry[bus];
613 context = get_context_addr_from_root(root);
614 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700615 context = (struct context_entry *)
616 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700617 if (!context) {
618 spin_unlock_irqrestore(&iommu->lock, flags);
619 return NULL;
620 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700621 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700622 phy_addr = virt_to_phys((void *)context);
623 set_root_value(root, phy_addr);
624 set_root_present(root);
625 __iommu_flush_cache(iommu, root, sizeof(*root));
626 }
627 spin_unlock_irqrestore(&iommu->lock, flags);
628 return &context[devfn];
629}
630
631static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
632{
633 struct root_entry *root;
634 struct context_entry *context;
635 int ret;
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) {
642 ret = 0;
643 goto out;
644 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000645 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700646out:
647 spin_unlock_irqrestore(&iommu->lock, flags);
648 return ret;
649}
650
651static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
652{
653 struct root_entry *root;
654 struct context_entry *context;
655 unsigned long flags;
656
657 spin_lock_irqsave(&iommu->lock, flags);
658 root = &iommu->root_entry[bus];
659 context = get_context_addr_from_root(root);
660 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000661 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700662 __iommu_flush_cache(iommu, &context[devfn], \
663 sizeof(*context));
664 }
665 spin_unlock_irqrestore(&iommu->lock, flags);
666}
667
668static void free_context_table(struct intel_iommu *iommu)
669{
670 struct root_entry *root;
671 int i;
672 unsigned long flags;
673 struct context_entry *context;
674
675 spin_lock_irqsave(&iommu->lock, flags);
676 if (!iommu->root_entry) {
677 goto out;
678 }
679 for (i = 0; i < ROOT_ENTRY_NR; i++) {
680 root = &iommu->root_entry[i];
681 context = get_context_addr_from_root(root);
682 if (context)
683 free_pgtable_page(context);
684 }
685 free_pgtable_page(iommu->root_entry);
686 iommu->root_entry = NULL;
687out:
688 spin_unlock_irqrestore(&iommu->lock, flags);
689}
690
David Woodhouseb026fd22009-06-28 10:37:25 +0100691static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
692 unsigned long pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700693{
David Woodhouseb026fd22009-06-28 10:37:25 +0100694 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700695 struct dma_pte *parent, *pte = NULL;
696 int level = agaw_to_level(domain->agaw);
697 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700698
699 BUG_ON(!domain->pgd);
David Woodhouseb026fd22009-06-28 10:37:25 +0100700 BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700701 parent = domain->pgd;
702
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700703 while (level > 0) {
704 void *tmp_page;
705
David Woodhouseb026fd22009-06-28 10:37:25 +0100706 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700707 pte = &parent[offset];
708 if (level == 1)
709 break;
710
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000711 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100712 uint64_t pteval;
713
Suresh Siddha4c923d42009-10-02 11:01:24 -0700714 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700715
David Woodhouse206a73c12009-07-01 19:30:28 +0100716 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700717 return NULL;
David Woodhouse206a73c12009-07-01 19:30:28 +0100718
David Woodhousec85994e2009-07-01 19:21:24 +0100719 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400720 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 +0100721 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
722 /* Someone else set it while we were thinking; use theirs. */
723 free_pgtable_page(tmp_page);
724 } else {
725 dma_pte_addr(pte);
726 domain_flush_cache(domain, pte, sizeof(*pte));
727 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700728 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000729 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700730 level--;
731 }
732
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700733 return pte;
734}
735
736/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100737static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
738 unsigned long pfn,
739 int level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700740{
741 struct dma_pte *parent, *pte = NULL;
742 int total = agaw_to_level(domain->agaw);
743 int offset;
744
745 parent = domain->pgd;
746 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100747 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700748 pte = &parent[offset];
749 if (level == total)
750 return pte;
751
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000752 if (!dma_pte_present(pte))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700753 break;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000754 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700755 total--;
756 }
757 return NULL;
758}
759
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700760/* clear last level pte, a tlb flush should be followed */
David Woodhouse595badf2009-06-27 22:09:11 +0100761static void dma_pte_clear_range(struct dmar_domain *domain,
762 unsigned long start_pfn,
763 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700764{
David Woodhouse04b18e62009-06-27 19:15:01 +0100765 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100766 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700767
David Woodhouse04b18e62009-06-27 19:15:01 +0100768 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100769 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700770 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100771
David Woodhouse04b18e62009-06-27 19:15:01 +0100772 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700773 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100774 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
775 if (!pte) {
776 start_pfn = align_to_level(start_pfn + 1, 2);
777 continue;
778 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100779 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100780 dma_clear_pte(pte);
781 start_pfn++;
782 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100783 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
784
David Woodhouse310a5ab2009-06-28 18:52:20 +0100785 domain_flush_cache(domain, first_pte,
786 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700787
788 } while (start_pfn && start_pfn <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700789}
790
791/* free page table pages. last level pte should already be cleared */
792static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100793 unsigned long start_pfn,
794 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700795{
David Woodhouse6660c632009-06-27 22:41:00 +0100796 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhousef3a0a522009-06-30 03:40:07 +0100797 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700798 int total = agaw_to_level(domain->agaw);
799 int level;
David Woodhouse6660c632009-06-27 22:41:00 +0100800 unsigned long tmp;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700801
David Woodhouse6660c632009-06-27 22:41:00 +0100802 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
803 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700804 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700805
David Woodhousef3a0a522009-06-30 03:40:07 +0100806 /* We don't need lock here; nobody else touches the iova range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700807 level = 2;
808 while (level <= total) {
David Woodhouse6660c632009-06-27 22:41:00 +0100809 tmp = align_to_level(start_pfn, level);
810
David Woodhousef3a0a522009-06-30 03:40:07 +0100811 /* If we can't even clear one PTE at this level, we're done */
David Woodhouse6660c632009-06-27 22:41:00 +0100812 if (tmp + level_size(level) - 1 > last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700813 return;
814
David Woodhouse59c36282009-09-19 07:36:28 -0700815 do {
David Woodhousef3a0a522009-06-30 03:40:07 +0100816 first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
817 if (!pte) {
818 tmp = align_to_level(tmp + 1, level + 1);
819 continue;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700820 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100821 do {
David Woodhouse6a43e572009-07-02 12:02:34 +0100822 if (dma_pte_present(pte)) {
823 free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
824 dma_clear_pte(pte);
825 }
David Woodhousef3a0a522009-06-30 03:40:07 +0100826 pte++;
827 tmp += level_size(level);
David Woodhouse75e6bf92009-07-02 11:21:16 +0100828 } while (!first_pte_in_page(pte) &&
829 tmp + level_size(level) - 1 <= last_pfn);
830
David Woodhousef3a0a522009-06-30 03:40:07 +0100831 domain_flush_cache(domain, first_pte,
832 (void *)pte - (void *)first_pte);
833
David Woodhouse59c36282009-09-19 07:36:28 -0700834 } while (tmp && tmp + level_size(level) - 1 <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700835 level++;
836 }
837 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100838 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700839 free_pgtable_page(domain->pgd);
840 domain->pgd = NULL;
841 }
842}
843
844/* iommu handling */
845static int iommu_alloc_root_entry(struct intel_iommu *iommu)
846{
847 struct root_entry *root;
848 unsigned long flags;
849
Suresh Siddha4c923d42009-10-02 11:01:24 -0700850 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700851 if (!root)
852 return -ENOMEM;
853
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700854 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700855
856 spin_lock_irqsave(&iommu->lock, flags);
857 iommu->root_entry = root;
858 spin_unlock_irqrestore(&iommu->lock, flags);
859
860 return 0;
861}
862
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700863static void iommu_set_root_entry(struct intel_iommu *iommu)
864{
865 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100866 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700867 unsigned long flag;
868
869 addr = iommu->root_entry;
870
871 spin_lock_irqsave(&iommu->register_lock, flag);
872 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
873
David Woodhousec416daa2009-05-10 20:30:58 +0100874 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700875
876 /* Make sure hardware complete it */
877 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100878 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700879
880 spin_unlock_irqrestore(&iommu->register_lock, flag);
881}
882
883static void iommu_flush_write_buffer(struct intel_iommu *iommu)
884{
885 u32 val;
886 unsigned long flag;
887
David Woodhouse9af88142009-02-13 23:18:03 +0000888 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700889 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700890
891 spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100892 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700893
894 /* Make sure hardware complete it */
895 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100896 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700897
898 spin_unlock_irqrestore(&iommu->register_lock, flag);
899}
900
901/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +0100902static void __iommu_flush_context(struct intel_iommu *iommu,
903 u16 did, u16 source_id, u8 function_mask,
904 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700905{
906 u64 val = 0;
907 unsigned long flag;
908
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700909 switch (type) {
910 case DMA_CCMD_GLOBAL_INVL:
911 val = DMA_CCMD_GLOBAL_INVL;
912 break;
913 case DMA_CCMD_DOMAIN_INVL:
914 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
915 break;
916 case DMA_CCMD_DEVICE_INVL:
917 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
918 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
919 break;
920 default:
921 BUG();
922 }
923 val |= DMA_CCMD_ICC;
924
925 spin_lock_irqsave(&iommu->register_lock, flag);
926 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
927
928 /* Make sure hardware complete it */
929 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
930 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
931
932 spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700933}
934
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700935/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +0100936static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
937 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700938{
939 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
940 u64 val = 0, val_iva = 0;
941 unsigned long flag;
942
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700943 switch (type) {
944 case DMA_TLB_GLOBAL_FLUSH:
945 /* global flush doesn't need set IVA_REG */
946 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
947 break;
948 case DMA_TLB_DSI_FLUSH:
949 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
950 break;
951 case DMA_TLB_PSI_FLUSH:
952 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
953 /* Note: always flush non-leaf currently */
954 val_iva = size_order | addr;
955 break;
956 default:
957 BUG();
958 }
959 /* Note: set drain read/write */
960#if 0
961 /*
962 * This is probably to be super secure.. Looks like we can
963 * ignore it without any impact.
964 */
965 if (cap_read_drain(iommu->cap))
966 val |= DMA_TLB_READ_DRAIN;
967#endif
968 if (cap_write_drain(iommu->cap))
969 val |= DMA_TLB_WRITE_DRAIN;
970
971 spin_lock_irqsave(&iommu->register_lock, flag);
972 /* Note: Only uses first TLB reg currently */
973 if (val_iva)
974 dmar_writeq(iommu->reg + tlb_offset, val_iva);
975 dmar_writeq(iommu->reg + tlb_offset + 8, val);
976
977 /* Make sure hardware complete it */
978 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
979 dmar_readq, (!(val & DMA_TLB_IVT)), val);
980
981 spin_unlock_irqrestore(&iommu->register_lock, flag);
982
983 /* check IOTLB invalidation granularity */
984 if (DMA_TLB_IAIG(val) == 0)
985 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
986 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
987 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700988 (unsigned long long)DMA_TLB_IIRG(type),
989 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700990}
991
Yu Zhao93a23a72009-05-18 13:51:37 +0800992static struct device_domain_info *iommu_support_dev_iotlb(
993 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700994{
Yu Zhao93a23a72009-05-18 13:51:37 +0800995 int found = 0;
996 unsigned long flags;
997 struct device_domain_info *info;
998 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
999
1000 if (!ecap_dev_iotlb_support(iommu->ecap))
1001 return NULL;
1002
1003 if (!iommu->qi)
1004 return NULL;
1005
1006 spin_lock_irqsave(&device_domain_lock, flags);
1007 list_for_each_entry(info, &domain->devices, link)
1008 if (info->bus == bus && info->devfn == devfn) {
1009 found = 1;
1010 break;
1011 }
1012 spin_unlock_irqrestore(&device_domain_lock, flags);
1013
1014 if (!found || !info->dev)
1015 return NULL;
1016
1017 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1018 return NULL;
1019
1020 if (!dmar_find_matched_atsr_unit(info->dev))
1021 return NULL;
1022
1023 info->iommu = iommu;
1024
1025 return info;
1026}
1027
1028static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1029{
1030 if (!info)
1031 return;
1032
1033 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1034}
1035
1036static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1037{
1038 if (!info->dev || !pci_ats_enabled(info->dev))
1039 return;
1040
1041 pci_disable_ats(info->dev);
1042}
1043
1044static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1045 u64 addr, unsigned mask)
1046{
1047 u16 sid, qdep;
1048 unsigned long flags;
1049 struct device_domain_info *info;
1050
1051 spin_lock_irqsave(&device_domain_lock, flags);
1052 list_for_each_entry(info, &domain->devices, link) {
1053 if (!info->dev || !pci_ats_enabled(info->dev))
1054 continue;
1055
1056 sid = info->bus << 8 | info->devfn;
1057 qdep = pci_ats_queue_depth(info->dev);
1058 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1059 }
1060 spin_unlock_irqrestore(&device_domain_lock, flags);
1061}
1062
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001063static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001064 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001065{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001066 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001067 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001068
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001069 BUG_ON(pages == 0);
1070
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001071 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001072 * Fallback to domain selective flush if no PSI support or the size is
1073 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001074 * PSI requires page size to be 2 ^ x, and the base address is naturally
1075 * aligned to the size
1076 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001077 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1078 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001079 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001080 else
1081 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1082 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001083
1084 /*
Nadav Amit82653632010-04-01 13:24:40 +03001085 * In caching mode, changes of pages from non-present to present require
1086 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001087 */
Nadav Amit82653632010-04-01 13:24:40 +03001088 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001089 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001090}
1091
mark grossf8bab732008-02-08 04:18:38 -08001092static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1093{
1094 u32 pmen;
1095 unsigned long flags;
1096
1097 spin_lock_irqsave(&iommu->register_lock, flags);
1098 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1099 pmen &= ~DMA_PMEN_EPM;
1100 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1101
1102 /* wait for the protected region status bit to clear */
1103 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1104 readl, !(pmen & DMA_PMEN_PRS), pmen);
1105
1106 spin_unlock_irqrestore(&iommu->register_lock, flags);
1107}
1108
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001109static int iommu_enable_translation(struct intel_iommu *iommu)
1110{
1111 u32 sts;
1112 unsigned long flags;
1113
1114 spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001115 iommu->gcmd |= DMA_GCMD_TE;
1116 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001117
1118 /* Make sure hardware complete it */
1119 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001120 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001121
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001122 spin_unlock_irqrestore(&iommu->register_lock, flags);
1123 return 0;
1124}
1125
1126static int iommu_disable_translation(struct intel_iommu *iommu)
1127{
1128 u32 sts;
1129 unsigned long flag;
1130
1131 spin_lock_irqsave(&iommu->register_lock, flag);
1132 iommu->gcmd &= ~DMA_GCMD_TE;
1133 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1134
1135 /* Make sure hardware complete it */
1136 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001137 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001138
1139 spin_unlock_irqrestore(&iommu->register_lock, flag);
1140 return 0;
1141}
1142
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001143
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001144static int iommu_init_domains(struct intel_iommu *iommu)
1145{
1146 unsigned long ndomains;
1147 unsigned long nlongs;
1148
1149 ndomains = cap_ndoms(iommu->cap);
Yinghai Lu680a7522010-04-08 19:58:23 +01001150 pr_debug("IOMMU %d: Number of Domains supportd <%ld>\n", iommu->seq_id,
1151 ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001152 nlongs = BITS_TO_LONGS(ndomains);
1153
Donald Dutile94a91b52009-08-20 16:51:34 -04001154 spin_lock_init(&iommu->lock);
1155
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001156 /* TBD: there might be 64K domains,
1157 * consider other allocation for future chip
1158 */
1159 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1160 if (!iommu->domain_ids) {
1161 printk(KERN_ERR "Allocating domain id array failed\n");
1162 return -ENOMEM;
1163 }
1164 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1165 GFP_KERNEL);
1166 if (!iommu->domains) {
1167 printk(KERN_ERR "Allocating domain array failed\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001168 return -ENOMEM;
1169 }
1170
1171 /*
1172 * if Caching mode is set, then invalid translations are tagged
1173 * with domainid 0. Hence we need to pre-allocate it.
1174 */
1175 if (cap_caching_mode(iommu->cap))
1176 set_bit(0, iommu->domain_ids);
1177 return 0;
1178}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001179
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001180
1181static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001182static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001183
1184void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001185{
1186 struct dmar_domain *domain;
1187 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001188 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001189
Donald Dutile94a91b52009-08-20 16:51:34 -04001190 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001191 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001192 domain = iommu->domains[i];
1193 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001194
Donald Dutile94a91b52009-08-20 16:51:34 -04001195 spin_lock_irqsave(&domain->iommu_lock, flags);
1196 if (--domain->iommu_count == 0) {
1197 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1198 vm_domain_exit(domain);
1199 else
1200 domain_exit(domain);
1201 }
1202 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001203 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001204 }
1205
1206 if (iommu->gcmd & DMA_GCMD_TE)
1207 iommu_disable_translation(iommu);
1208
1209 if (iommu->irq) {
Thomas Gleixnerdced35a2011-03-28 17:49:12 +02001210 irq_set_handler_data(iommu->irq, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001211 /* This will mask the irq */
1212 free_irq(iommu->irq, iommu);
1213 destroy_irq(iommu->irq);
1214 }
1215
1216 kfree(iommu->domains);
1217 kfree(iommu->domain_ids);
1218
Weidong Hand9630fe2008-12-08 11:06:32 +08001219 g_iommus[iommu->seq_id] = NULL;
1220
1221 /* if all iommus are freed, free g_iommus */
1222 for (i = 0; i < g_num_of_iommus; i++) {
1223 if (g_iommus[i])
1224 break;
1225 }
1226
1227 if (i == g_num_of_iommus)
1228 kfree(g_iommus);
1229
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001230 /* free context mapping */
1231 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001232}
1233
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001234static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001235{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001236 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001237
1238 domain = alloc_domain_mem();
1239 if (!domain)
1240 return NULL;
1241
Suresh Siddha4c923d42009-10-02 11:01:24 -07001242 domain->nid = -1;
Weidong Han8c11e792008-12-08 15:29:22 +08001243 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
Weidong Hand71a2f32008-12-07 21:13:41 +08001244 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001245
1246 return domain;
1247}
1248
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001249static int iommu_attach_domain(struct dmar_domain *domain,
1250 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001251{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001252 int num;
1253 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001254 unsigned long flags;
1255
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001256 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001257
1258 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001259
1260 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1261 if (num >= ndomains) {
1262 spin_unlock_irqrestore(&iommu->lock, flags);
1263 printk(KERN_ERR "IOMMU: no free domain ids\n");
1264 return -ENOMEM;
1265 }
1266
1267 domain->id = num;
1268 set_bit(num, iommu->domain_ids);
1269 set_bit(iommu->seq_id, &domain->iommu_bmp);
1270 iommu->domains[num] = domain;
1271 spin_unlock_irqrestore(&iommu->lock, flags);
1272
1273 return 0;
1274}
1275
1276static void iommu_detach_domain(struct dmar_domain *domain,
1277 struct intel_iommu *iommu)
1278{
1279 unsigned long flags;
1280 int num, ndomains;
1281 int found = 0;
1282
1283 spin_lock_irqsave(&iommu->lock, flags);
1284 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001285 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001286 if (iommu->domains[num] == domain) {
1287 found = 1;
1288 break;
1289 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001290 }
1291
1292 if (found) {
1293 clear_bit(num, iommu->domain_ids);
1294 clear_bit(iommu->seq_id, &domain->iommu_bmp);
1295 iommu->domains[num] = NULL;
1296 }
Weidong Han8c11e792008-12-08 15:29:22 +08001297 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001298}
1299
1300static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001301static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001302
1303static void dmar_init_reserved_ranges(void)
1304{
1305 struct pci_dev *pdev = NULL;
1306 struct iova *iova;
1307 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001308
David Millerf6611972008-02-06 01:36:23 -08001309 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001310
Mark Gross8a443df2008-03-04 14:59:31 -08001311 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1312 &reserved_rbtree_key);
1313
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001314 /* IOAPIC ranges shouldn't be accessed by DMA */
1315 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1316 IOVA_PFN(IOAPIC_RANGE_END));
1317 if (!iova)
1318 printk(KERN_ERR "Reserve IOAPIC range failed\n");
1319
1320 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1321 for_each_pci_dev(pdev) {
1322 struct resource *r;
1323
1324 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1325 r = &pdev->resource[i];
1326 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1327 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001328 iova = reserve_iova(&reserved_iova_list,
1329 IOVA_PFN(r->start),
1330 IOVA_PFN(r->end));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001331 if (!iova)
1332 printk(KERN_ERR "Reserve iova failed\n");
1333 }
1334 }
1335
1336}
1337
1338static void domain_reserve_special_ranges(struct dmar_domain *domain)
1339{
1340 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1341}
1342
1343static inline int guestwidth_to_adjustwidth(int gaw)
1344{
1345 int agaw;
1346 int r = (gaw - 12) % 9;
1347
1348 if (r == 0)
1349 agaw = gaw;
1350 else
1351 agaw = gaw + 9 - r;
1352 if (agaw > 64)
1353 agaw = 64;
1354 return agaw;
1355}
1356
1357static int domain_init(struct dmar_domain *domain, int guest_width)
1358{
1359 struct intel_iommu *iommu;
1360 int adjust_width, agaw;
1361 unsigned long sagaw;
1362
David Millerf6611972008-02-06 01:36:23 -08001363 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001364 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001365
1366 domain_reserve_special_ranges(domain);
1367
1368 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001369 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001370 if (guest_width > cap_mgaw(iommu->cap))
1371 guest_width = cap_mgaw(iommu->cap);
1372 domain->gaw = guest_width;
1373 adjust_width = guestwidth_to_adjustwidth(guest_width);
1374 agaw = width_to_agaw(adjust_width);
1375 sagaw = cap_sagaw(iommu->cap);
1376 if (!test_bit(agaw, &sagaw)) {
1377 /* hardware doesn't support it, choose a bigger one */
1378 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1379 agaw = find_next_bit(&sagaw, 5, agaw);
1380 if (agaw >= 5)
1381 return -ENODEV;
1382 }
1383 domain->agaw = agaw;
1384 INIT_LIST_HEAD(&domain->devices);
1385
Weidong Han8e6040972008-12-08 15:49:06 +08001386 if (ecap_coherent(iommu->ecap))
1387 domain->iommu_coherency = 1;
1388 else
1389 domain->iommu_coherency = 0;
1390
Sheng Yang58c610b2009-03-18 15:33:05 +08001391 if (ecap_sc_support(iommu->ecap))
1392 domain->iommu_snooping = 1;
1393 else
1394 domain->iommu_snooping = 0;
1395
Weidong Hanc7151a82008-12-08 22:51:37 +08001396 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001397 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001398
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001399 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001400 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001401 if (!domain->pgd)
1402 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001403 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001404 return 0;
1405}
1406
1407static void domain_exit(struct dmar_domain *domain)
1408{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001409 struct dmar_drhd_unit *drhd;
1410 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001411
1412 /* Domain 0 is reserved, so dont process it */
1413 if (!domain)
1414 return;
1415
1416 domain_remove_dev_info(domain);
1417 /* destroy iovas */
1418 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001419
1420 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001421 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001422
1423 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001424 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001425
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001426 for_each_active_iommu(iommu, drhd)
1427 if (test_bit(iommu->seq_id, &domain->iommu_bmp))
1428 iommu_detach_domain(domain, iommu);
1429
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001430 free_domain_mem(domain);
1431}
1432
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001433static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1434 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001435{
1436 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001437 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001438 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001439 struct dma_pte *pgd;
1440 unsigned long num;
1441 unsigned long ndomains;
1442 int id;
1443 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001444 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001445
1446 pr_debug("Set context mapping for %02x:%02x.%d\n",
1447 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001448
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001449 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001450 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1451 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001452
David Woodhouse276dbf992009-04-04 01:45:37 +01001453 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001454 if (!iommu)
1455 return -ENODEV;
1456
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001457 context = device_to_context_entry(iommu, bus, devfn);
1458 if (!context)
1459 return -ENOMEM;
1460 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001461 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001462 spin_unlock_irqrestore(&iommu->lock, flags);
1463 return 0;
1464 }
1465
Weidong Hanea6606b2008-12-08 23:08:15 +08001466 id = domain->id;
1467 pgd = domain->pgd;
1468
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001469 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1470 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001471 int found = 0;
1472
1473 /* find an available domain id for this device in iommu */
1474 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001475 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001476 if (iommu->domains[num] == domain) {
1477 id = num;
1478 found = 1;
1479 break;
1480 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001481 }
1482
1483 if (found == 0) {
1484 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1485 if (num >= ndomains) {
1486 spin_unlock_irqrestore(&iommu->lock, flags);
1487 printk(KERN_ERR "IOMMU: no free domain ids\n");
1488 return -EFAULT;
1489 }
1490
1491 set_bit(num, iommu->domain_ids);
1492 iommu->domains[num] = domain;
1493 id = num;
1494 }
1495
1496 /* Skip top levels of page tables for
1497 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001498 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001499 */
Chris Wright1672af12009-12-02 12:06:34 -08001500 if (translation != CONTEXT_TT_PASS_THROUGH) {
1501 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1502 pgd = phys_to_virt(dma_pte_addr(pgd));
1503 if (!dma_pte_present(pgd)) {
1504 spin_unlock_irqrestore(&iommu->lock, flags);
1505 return -ENOMEM;
1506 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001507 }
1508 }
1509 }
1510
1511 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001512
Yu Zhao93a23a72009-05-18 13:51:37 +08001513 if (translation != CONTEXT_TT_PASS_THROUGH) {
1514 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1515 translation = info ? CONTEXT_TT_DEV_IOTLB :
1516 CONTEXT_TT_MULTI_LEVEL;
1517 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001518 /*
1519 * In pass through mode, AW must be programmed to indicate the largest
1520 * AGAW value supported by hardware. And ASR is ignored by hardware.
1521 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001522 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001523 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001524 else {
1525 context_set_address_root(context, virt_to_phys(pgd));
1526 context_set_address_width(context, iommu->agaw);
1527 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001528
1529 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001530 context_set_fault_enable(context);
1531 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001532 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001533
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001534 /*
1535 * It's a non-present to present mapping. If hardware doesn't cache
1536 * non-present entry we only need to flush the write-buffer. If the
1537 * _does_ cache non-present entries, then it does so in the special
1538 * domain #0, which we have to flush:
1539 */
1540 if (cap_caching_mode(iommu->cap)) {
1541 iommu->flush.flush_context(iommu, 0,
1542 (((u16)bus) << 8) | devfn,
1543 DMA_CCMD_MASK_NOBIT,
1544 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001545 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001546 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001547 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001548 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001549 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001550 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001551
1552 spin_lock_irqsave(&domain->iommu_lock, flags);
1553 if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
1554 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001555 if (domain->iommu_count == 1)
1556 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001557 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001558 }
1559 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001560 return 0;
1561}
1562
1563static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001564domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1565 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001566{
1567 int ret;
1568 struct pci_dev *tmp, *parent;
1569
David Woodhouse276dbf992009-04-04 01:45:37 +01001570 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001571 pdev->bus->number, pdev->devfn,
1572 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001573 if (ret)
1574 return ret;
1575
1576 /* dependent device mapping */
1577 tmp = pci_find_upstream_pcie_bridge(pdev);
1578 if (!tmp)
1579 return 0;
1580 /* Secondary interface's bus number and devfn 0 */
1581 parent = pdev->bus->self;
1582 while (parent != tmp) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001583 ret = domain_context_mapping_one(domain,
1584 pci_domain_nr(parent->bus),
1585 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001586 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001587 if (ret)
1588 return ret;
1589 parent = parent->bus->self;
1590 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001591 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001592 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001593 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001594 tmp->subordinate->number, 0,
1595 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001596 else /* this is a legacy PCI bridge */
1597 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001598 pci_domain_nr(tmp->bus),
1599 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001600 tmp->devfn,
1601 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001602}
1603
Weidong Han5331fe62008-12-08 23:00:00 +08001604static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001605{
1606 int ret;
1607 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001608 struct intel_iommu *iommu;
1609
David Woodhouse276dbf992009-04-04 01:45:37 +01001610 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1611 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001612 if (!iommu)
1613 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001614
David Woodhouse276dbf992009-04-04 01:45:37 +01001615 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001616 if (!ret)
1617 return ret;
1618 /* dependent device mapping */
1619 tmp = pci_find_upstream_pcie_bridge(pdev);
1620 if (!tmp)
1621 return ret;
1622 /* Secondary interface's bus number and devfn 0 */
1623 parent = pdev->bus->self;
1624 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001625 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001626 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001627 if (!ret)
1628 return ret;
1629 parent = parent->bus->self;
1630 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001631 if (pci_is_pcie(tmp))
David Woodhouse276dbf992009-04-04 01:45:37 +01001632 return device_context_mapped(iommu, tmp->subordinate->number,
1633 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001634 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001635 return device_context_mapped(iommu, tmp->bus->number,
1636 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001637}
1638
Fenghua Yuf5329592009-08-04 15:09:37 -07001639/* Returns a number of VTD pages, but aligned to MM page size */
1640static inline unsigned long aligned_nrpages(unsigned long host_addr,
1641 size_t size)
1642{
1643 host_addr &= ~PAGE_MASK;
1644 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1645}
1646
David Woodhouse9051aa02009-06-29 12:30:54 +01001647static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1648 struct scatterlist *sg, unsigned long phys_pfn,
1649 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001650{
1651 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001652 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001653 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001654 unsigned long sg_res;
David Woodhousee1605492009-06-29 11:17:38 +01001655
1656 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1657
1658 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1659 return -EINVAL;
1660
1661 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1662
David Woodhouse9051aa02009-06-29 12:30:54 +01001663 if (sg)
1664 sg_res = 0;
1665 else {
1666 sg_res = nr_pages + 1;
1667 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1668 }
1669
David Woodhousee1605492009-06-29 11:17:38 +01001670 while (nr_pages--) {
David Woodhousec85994e2009-07-01 19:21:24 +01001671 uint64_t tmp;
1672
David Woodhousee1605492009-06-29 11:17:38 +01001673 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001674 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001675 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1676 sg->dma_length = sg->length;
1677 pteval = page_to_phys(sg_page(sg)) | prot;
1678 }
1679 if (!pte) {
1680 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
1681 if (!pte)
1682 return -ENOMEM;
1683 }
1684 /* We don't need lock here, nobody else
1685 * touches the iova range
1686 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001687 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001688 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001689 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001690 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1691 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001692 if (dumps) {
1693 dumps--;
1694 debug_dma_dump_mappings(NULL);
1695 }
1696 WARN_ON(1);
1697 }
David Woodhousee1605492009-06-29 11:17:38 +01001698 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +01001699 if (!nr_pages || first_pte_in_page(pte)) {
David Woodhousee1605492009-06-29 11:17:38 +01001700 domain_flush_cache(domain, first_pte,
1701 (void *)pte - (void *)first_pte);
1702 pte = NULL;
1703 }
1704 iov_pfn++;
1705 pteval += VTD_PAGE_SIZE;
1706 sg_res--;
1707 if (!sg_res)
1708 sg = sg_next(sg);
1709 }
1710 return 0;
1711}
1712
David Woodhouse9051aa02009-06-29 12:30:54 +01001713static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1714 struct scatterlist *sg, unsigned long nr_pages,
1715 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001716{
David Woodhouse9051aa02009-06-29 12:30:54 +01001717 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1718}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001719
David Woodhouse9051aa02009-06-29 12:30:54 +01001720static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1721 unsigned long phys_pfn, unsigned long nr_pages,
1722 int prot)
1723{
1724 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001725}
1726
Weidong Hanc7151a82008-12-08 22:51:37 +08001727static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001728{
Weidong Hanc7151a82008-12-08 22:51:37 +08001729 if (!iommu)
1730 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001731
1732 clear_context_table(iommu, bus, devfn);
1733 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001734 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001735 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001736}
1737
1738static void domain_remove_dev_info(struct dmar_domain *domain)
1739{
1740 struct device_domain_info *info;
1741 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001742 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001743
1744 spin_lock_irqsave(&device_domain_lock, flags);
1745 while (!list_empty(&domain->devices)) {
1746 info = list_entry(domain->devices.next,
1747 struct device_domain_info, link);
1748 list_del(&info->link);
1749 list_del(&info->global);
1750 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001751 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001752 spin_unlock_irqrestore(&device_domain_lock, flags);
1753
Yu Zhao93a23a72009-05-18 13:51:37 +08001754 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01001755 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001756 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001757 free_devinfo_mem(info);
1758
1759 spin_lock_irqsave(&device_domain_lock, flags);
1760 }
1761 spin_unlock_irqrestore(&device_domain_lock, flags);
1762}
1763
1764/*
1765 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001766 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001767 */
Kay, Allen M38717942008-09-09 18:37:29 +03001768static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001769find_domain(struct pci_dev *pdev)
1770{
1771 struct device_domain_info *info;
1772
1773 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001774 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001775 if (info)
1776 return info->domain;
1777 return NULL;
1778}
1779
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001780/* domain is initialized */
1781static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1782{
1783 struct dmar_domain *domain, *found = NULL;
1784 struct intel_iommu *iommu;
1785 struct dmar_drhd_unit *drhd;
1786 struct device_domain_info *info, *tmp;
1787 struct pci_dev *dev_tmp;
1788 unsigned long flags;
1789 int bus = 0, devfn = 0;
David Woodhouse276dbf992009-04-04 01:45:37 +01001790 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001791 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001792
1793 domain = find_domain(pdev);
1794 if (domain)
1795 return domain;
1796
David Woodhouse276dbf992009-04-04 01:45:37 +01001797 segment = pci_domain_nr(pdev->bus);
1798
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001799 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1800 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001801 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001802 bus = dev_tmp->subordinate->number;
1803 devfn = 0;
1804 } else {
1805 bus = dev_tmp->bus->number;
1806 devfn = dev_tmp->devfn;
1807 }
1808 spin_lock_irqsave(&device_domain_lock, flags);
1809 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001810 if (info->segment == segment &&
1811 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001812 found = info->domain;
1813 break;
1814 }
1815 }
1816 spin_unlock_irqrestore(&device_domain_lock, flags);
1817 /* pcie-pci bridge already has a domain, uses it */
1818 if (found) {
1819 domain = found;
1820 goto found_domain;
1821 }
1822 }
1823
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001824 domain = alloc_domain();
1825 if (!domain)
1826 goto error;
1827
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001828 /* Allocate new domain for the device */
1829 drhd = dmar_find_matched_drhd_unit(pdev);
1830 if (!drhd) {
1831 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
1832 pci_name(pdev));
1833 return NULL;
1834 }
1835 iommu = drhd->iommu;
1836
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001837 ret = iommu_attach_domain(domain, iommu);
1838 if (ret) {
1839 domain_exit(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001840 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001841 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001842
1843 if (domain_init(domain, gaw)) {
1844 domain_exit(domain);
1845 goto error;
1846 }
1847
1848 /* register pcie-to-pci device */
1849 if (dev_tmp) {
1850 info = alloc_devinfo_mem();
1851 if (!info) {
1852 domain_exit(domain);
1853 goto error;
1854 }
David Woodhouse276dbf992009-04-04 01:45:37 +01001855 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001856 info->bus = bus;
1857 info->devfn = devfn;
1858 info->dev = NULL;
1859 info->domain = domain;
1860 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08001861 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001862
1863 /* pcie-to-pci bridge already has a domain, uses it */
1864 found = NULL;
1865 spin_lock_irqsave(&device_domain_lock, flags);
1866 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001867 if (tmp->segment == segment &&
1868 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001869 found = tmp->domain;
1870 break;
1871 }
1872 }
1873 if (found) {
Jiri Slaby00dfff72010-06-14 17:17:32 +02001874 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001875 free_devinfo_mem(info);
1876 domain_exit(domain);
1877 domain = found;
1878 } else {
1879 list_add(&info->link, &domain->devices);
1880 list_add(&info->global, &device_domain_list);
Jiri Slaby00dfff72010-06-14 17:17:32 +02001881 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001882 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001883 }
1884
1885found_domain:
1886 info = alloc_devinfo_mem();
1887 if (!info)
1888 goto error;
David Woodhouse276dbf992009-04-04 01:45:37 +01001889 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001890 info->bus = pdev->bus->number;
1891 info->devfn = pdev->devfn;
1892 info->dev = pdev;
1893 info->domain = domain;
1894 spin_lock_irqsave(&device_domain_lock, flags);
1895 /* somebody is fast */
1896 found = find_domain(pdev);
1897 if (found != NULL) {
1898 spin_unlock_irqrestore(&device_domain_lock, flags);
1899 if (found != domain) {
1900 domain_exit(domain);
1901 domain = found;
1902 }
1903 free_devinfo_mem(info);
1904 return domain;
1905 }
1906 list_add(&info->link, &domain->devices);
1907 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001908 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001909 spin_unlock_irqrestore(&device_domain_lock, flags);
1910 return domain;
1911error:
1912 /* recheck it here, maybe others set it */
1913 return find_domain(pdev);
1914}
1915
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001916static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07001917#define IDENTMAP_ALL 1
1918#define IDENTMAP_GFX 2
1919#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001920
David Woodhouseb2132032009-06-26 18:50:28 +01001921static int iommu_domain_identity_map(struct dmar_domain *domain,
1922 unsigned long long start,
1923 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001924{
David Woodhousec5395d52009-06-28 16:35:56 +01001925 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
1926 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001927
David Woodhousec5395d52009-06-28 16:35:56 +01001928 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
1929 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001930 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01001931 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001932 }
1933
David Woodhousec5395d52009-06-28 16:35:56 +01001934 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
1935 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001936 /*
1937 * RMRR range might have overlap with physical memory range,
1938 * clear it first
1939 */
David Woodhousec5395d52009-06-28 16:35:56 +01001940 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001941
David Woodhousec5395d52009-06-28 16:35:56 +01001942 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
1943 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01001944 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01001945}
1946
1947static int iommu_prepare_identity_map(struct pci_dev *pdev,
1948 unsigned long long start,
1949 unsigned long long end)
1950{
1951 struct dmar_domain *domain;
1952 int ret;
1953
David Woodhousec7ab48d2009-06-26 19:10:36 +01001954 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01001955 if (!domain)
1956 return -ENOMEM;
1957
David Woodhouse19943b02009-08-04 16:19:20 +01001958 /* For _hardware_ passthrough, don't bother. But for software
1959 passthrough, we do it anyway -- it may indicate a memory
1960 range which is reserved in E820, so which didn't get set
1961 up to start with in si_domain */
1962 if (domain == si_domain && hw_pass_through) {
1963 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
1964 pci_name(pdev), start, end);
1965 return 0;
1966 }
1967
1968 printk(KERN_INFO
1969 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
1970 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01001971
David Woodhouse5595b522009-12-02 09:21:55 +00001972 if (end < start) {
1973 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
1974 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
1975 dmi_get_system_info(DMI_BIOS_VENDOR),
1976 dmi_get_system_info(DMI_BIOS_VERSION),
1977 dmi_get_system_info(DMI_PRODUCT_VERSION));
1978 ret = -EIO;
1979 goto error;
1980 }
1981
David Woodhouse2ff729f2009-08-26 14:25:41 +01001982 if (end >> agaw_to_width(domain->agaw)) {
1983 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
1984 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
1985 agaw_to_width(domain->agaw),
1986 dmi_get_system_info(DMI_BIOS_VENDOR),
1987 dmi_get_system_info(DMI_BIOS_VERSION),
1988 dmi_get_system_info(DMI_PRODUCT_VERSION));
1989 ret = -EIO;
1990 goto error;
1991 }
David Woodhouse19943b02009-08-04 16:19:20 +01001992
David Woodhouseb2132032009-06-26 18:50:28 +01001993 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001994 if (ret)
1995 goto error;
1996
1997 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001998 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01001999 if (ret)
2000 goto error;
2001
2002 return 0;
2003
2004 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002005 domain_exit(domain);
2006 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002007}
2008
2009static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2010 struct pci_dev *pdev)
2011{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002012 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002013 return 0;
2014 return iommu_prepare_identity_map(pdev, rmrr->base_address,
2015 rmrr->end_address + 1);
2016}
2017
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002018#ifdef CONFIG_DMAR_FLOPPY_WA
2019static inline void iommu_prepare_isa(void)
2020{
2021 struct pci_dev *pdev;
2022 int ret;
2023
2024 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2025 if (!pdev)
2026 return;
2027
David Woodhousec7ab48d2009-06-26 19:10:36 +01002028 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002029 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
2030
2031 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002032 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2033 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002034
2035}
2036#else
2037static inline void iommu_prepare_isa(void)
2038{
2039 return;
2040}
2041#endif /* !CONFIG_DMAR_FLPY_WA */
2042
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002043static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002044
2045static int __init si_domain_work_fn(unsigned long start_pfn,
2046 unsigned long end_pfn, void *datax)
2047{
2048 int *ret = datax;
2049
2050 *ret = iommu_domain_identity_map(si_domain,
2051 (uint64_t)start_pfn << PAGE_SHIFT,
2052 (uint64_t)end_pfn << PAGE_SHIFT);
2053 return *ret;
2054
2055}
2056
Matt Kraai071e1372009-08-23 22:30:22 -07002057static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002058{
2059 struct dmar_drhd_unit *drhd;
2060 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002061 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002062
2063 si_domain = alloc_domain();
2064 if (!si_domain)
2065 return -EFAULT;
2066
David Woodhousec7ab48d2009-06-26 19:10:36 +01002067 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002068
2069 for_each_active_iommu(iommu, drhd) {
2070 ret = iommu_attach_domain(si_domain, iommu);
2071 if (ret) {
2072 domain_exit(si_domain);
2073 return -EFAULT;
2074 }
2075 }
2076
2077 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2078 domain_exit(si_domain);
2079 return -EFAULT;
2080 }
2081
2082 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2083
David Woodhouse19943b02009-08-04 16:19:20 +01002084 if (hw)
2085 return 0;
2086
David Woodhousec7ab48d2009-06-26 19:10:36 +01002087 for_each_online_node(nid) {
2088 work_with_active_regions(nid, si_domain_work_fn, &ret);
2089 if (ret)
2090 return ret;
2091 }
2092
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002093 return 0;
2094}
2095
2096static void domain_remove_one_dev_info(struct dmar_domain *domain,
2097 struct pci_dev *pdev);
2098static int identity_mapping(struct pci_dev *pdev)
2099{
2100 struct device_domain_info *info;
2101
2102 if (likely(!iommu_identity_mapping))
2103 return 0;
2104
2105
2106 list_for_each_entry(info, &si_domain->devices, link)
2107 if (info->dev == pdev)
2108 return 1;
2109 return 0;
2110}
2111
2112static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002113 struct pci_dev *pdev,
2114 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002115{
2116 struct device_domain_info *info;
2117 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002118 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002119
2120 info = alloc_devinfo_mem();
2121 if (!info)
2122 return -ENOMEM;
2123
David Woodhouse5fe60f42009-08-09 10:53:41 +01002124 ret = domain_context_mapping(domain, pdev, translation);
2125 if (ret) {
2126 free_devinfo_mem(info);
2127 return ret;
2128 }
2129
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002130 info->segment = pci_domain_nr(pdev->bus);
2131 info->bus = pdev->bus->number;
2132 info->devfn = pdev->devfn;
2133 info->dev = pdev;
2134 info->domain = domain;
2135
2136 spin_lock_irqsave(&device_domain_lock, flags);
2137 list_add(&info->link, &domain->devices);
2138 list_add(&info->global, &device_domain_list);
2139 pdev->dev.archdata.iommu = info;
2140 spin_unlock_irqrestore(&device_domain_lock, flags);
2141
2142 return 0;
2143}
2144
David Woodhouse6941af22009-07-04 18:24:27 +01002145static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2146{
David Woodhousee0fc7e02009-09-30 09:12:17 -07002147 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2148 return 1;
2149
2150 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2151 return 1;
2152
2153 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2154 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002155
David Woodhouse3dfc8132009-07-04 19:11:08 +01002156 /*
2157 * We want to start off with all devices in the 1:1 domain, and
2158 * take them out later if we find they can't access all of memory.
2159 *
2160 * However, we can't do this for PCI devices behind bridges,
2161 * because all PCI devices behind the same bridge will end up
2162 * with the same source-id on their transactions.
2163 *
2164 * Practically speaking, we can't change things around for these
2165 * devices at run-time, because we can't be sure there'll be no
2166 * DMA transactions in flight for any of their siblings.
2167 *
2168 * So PCI devices (unless they're on the root bus) as well as
2169 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2170 * the 1:1 domain, just in _case_ one of their siblings turns out
2171 * not to be able to map all of memory.
2172 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002173 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002174 if (!pci_is_root_bus(pdev->bus))
2175 return 0;
2176 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2177 return 0;
2178 } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
2179 return 0;
2180
2181 /*
2182 * At boot time, we don't yet know if devices will be 64-bit capable.
2183 * Assume that they will -- if they turn out not to be, then we can
2184 * take them out of the 1:1 domain later.
2185 */
David Woodhouse6941af22009-07-04 18:24:27 +01002186 if (!startup)
2187 return pdev->dma_mask > DMA_BIT_MASK(32);
2188
2189 return 1;
2190}
2191
Matt Kraai071e1372009-08-23 22:30:22 -07002192static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002193{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002194 struct pci_dev *pdev = NULL;
2195 int ret;
2196
David Woodhouse19943b02009-08-04 16:19:20 +01002197 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002198 if (ret)
2199 return -EFAULT;
2200
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002201 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002202 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse19943b02009-08-04 16:19:20 +01002203 printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
2204 hw ? "hardware" : "software", pci_name(pdev));
David Woodhousec7ab48d2009-06-26 19:10:36 +01002205
David Woodhouse5fe60f42009-08-09 10:53:41 +01002206 ret = domain_add_dev_info(si_domain, pdev,
David Woodhouse19943b02009-08-04 16:19:20 +01002207 hw ? CONTEXT_TT_PASS_THROUGH :
David Woodhouse62edf5d2009-07-04 10:59:46 +01002208 CONTEXT_TT_MULTI_LEVEL);
2209 if (ret)
2210 return ret;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002211 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002212 }
2213
2214 return 0;
2215}
2216
2217int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002218{
2219 struct dmar_drhd_unit *drhd;
2220 struct dmar_rmrr_unit *rmrr;
2221 struct pci_dev *pdev;
2222 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002223 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002224
2225 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002226 * for each drhd
2227 * allocate root
2228 * initialize and program root entry to not present
2229 * endfor
2230 */
2231 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002232 g_num_of_iommus++;
2233 /*
2234 * lock not needed as this is only incremented in the single
2235 * threaded kernel __init code path all other access are read
2236 * only
2237 */
2238 }
2239
Weidong Hand9630fe2008-12-08 11:06:32 +08002240 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2241 GFP_KERNEL);
2242 if (!g_iommus) {
2243 printk(KERN_ERR "Allocating global iommu array failed\n");
2244 ret = -ENOMEM;
2245 goto error;
2246 }
2247
mark gross80b20dd2008-04-18 13:53:58 -07002248 deferred_flush = kzalloc(g_num_of_iommus *
2249 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2250 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002251 ret = -ENOMEM;
2252 goto error;
2253 }
2254
mark gross5e0d2a62008-03-04 15:22:08 -08002255 for_each_drhd_unit(drhd) {
2256 if (drhd->ignored)
2257 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002258
2259 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002260 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002261
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002262 ret = iommu_init_domains(iommu);
2263 if (ret)
2264 goto error;
2265
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002266 /*
2267 * TBD:
2268 * we could share the same root & context tables
2269 * amoung all IOMMU's. Need to Split it later.
2270 */
2271 ret = iommu_alloc_root_entry(iommu);
2272 if (ret) {
2273 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2274 goto error;
2275 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002276 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002277 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002278 }
2279
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002280 /*
2281 * Start from the sane iommu hardware state.
2282 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002283 for_each_drhd_unit(drhd) {
2284 if (drhd->ignored)
2285 continue;
2286
2287 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002288
2289 /*
2290 * If the queued invalidation is already initialized by us
2291 * (for example, while enabling interrupt-remapping) then
2292 * we got the things already rolling from a sane state.
2293 */
2294 if (iommu->qi)
2295 continue;
2296
2297 /*
2298 * Clear any previous faults.
2299 */
2300 dmar_fault(-1, iommu);
2301 /*
2302 * Disable queued invalidation if supported and already enabled
2303 * before OS handover.
2304 */
2305 dmar_disable_qi(iommu);
2306 }
2307
2308 for_each_drhd_unit(drhd) {
2309 if (drhd->ignored)
2310 continue;
2311
2312 iommu = drhd->iommu;
2313
Youquan Songa77b67d2008-10-16 16:31:56 -07002314 if (dmar_enable_qi(iommu)) {
2315 /*
2316 * Queued Invalidate not enabled, use Register Based
2317 * Invalidate
2318 */
2319 iommu->flush.flush_context = __iommu_flush_context;
2320 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002321 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002322 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002323 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002324 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002325 } else {
2326 iommu->flush.flush_context = qi_flush_context;
2327 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002328 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002329 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002330 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002331 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002332 }
2333 }
2334
David Woodhouse19943b02009-08-04 16:19:20 +01002335 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002336 iommu_identity_mapping |= IDENTMAP_ALL;
2337
David Woodhouse19943b02009-08-04 16:19:20 +01002338#ifdef CONFIG_DMAR_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002339 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002340#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002341
2342 check_tylersburg_isoch();
2343
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002344 /*
2345 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002346 * identity mappings for rmrr, gfx, and isa and may fall back to static
2347 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002348 */
David Woodhouse19943b02009-08-04 16:19:20 +01002349 if (iommu_identity_mapping) {
2350 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2351 if (ret) {
2352 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2353 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002354 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002355 }
David Woodhouse19943b02009-08-04 16:19:20 +01002356 /*
2357 * For each rmrr
2358 * for each dev attached to rmrr
2359 * do
2360 * locate drhd for dev, alloc domain for dev
2361 * allocate free domain
2362 * allocate page table entries for rmrr
2363 * if context not allocated for bus
2364 * allocate and init context
2365 * set present in root table for this bus
2366 * init context with domain, translation etc
2367 * endfor
2368 * endfor
2369 */
2370 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2371 for_each_rmrr_units(rmrr) {
2372 for (i = 0; i < rmrr->devices_cnt; i++) {
2373 pdev = rmrr->devices[i];
2374 /*
2375 * some BIOS lists non-exist devices in DMAR
2376 * table.
2377 */
2378 if (!pdev)
2379 continue;
2380 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2381 if (ret)
2382 printk(KERN_ERR
2383 "IOMMU: mapping reserved region failed\n");
2384 }
2385 }
2386
2387 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002388
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002389 /*
2390 * for each drhd
2391 * enable fault log
2392 * global invalidate context cache
2393 * global invalidate iotlb
2394 * enable translation
2395 */
2396 for_each_drhd_unit(drhd) {
2397 if (drhd->ignored)
2398 continue;
2399 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002400
2401 iommu_flush_write_buffer(iommu);
2402
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002403 ret = dmar_set_interrupt(iommu);
2404 if (ret)
2405 goto error;
2406
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002407 iommu_set_root_entry(iommu);
2408
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002409 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002410 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002411
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002412 ret = iommu_enable_translation(iommu);
2413 if (ret)
2414 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002415
2416 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002417 }
2418
2419 return 0;
2420error:
2421 for_each_drhd_unit(drhd) {
2422 if (drhd->ignored)
2423 continue;
2424 iommu = drhd->iommu;
2425 free_iommu(iommu);
2426 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002427 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002428 return ret;
2429}
2430
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002431/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002432static struct iova *intel_alloc_iova(struct device *dev,
2433 struct dmar_domain *domain,
2434 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002435{
2436 struct pci_dev *pdev = to_pci_dev(dev);
2437 struct iova *iova = NULL;
2438
David Woodhouse875764d2009-06-28 21:20:51 +01002439 /* Restrict dma_mask to the width that the iommu can handle */
2440 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2441
2442 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002443 /*
2444 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002445 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002446 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002447 */
David Woodhouse875764d2009-06-28 21:20:51 +01002448 iova = alloc_iova(&domain->iovad, nrpages,
2449 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2450 if (iova)
2451 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002452 }
David Woodhouse875764d2009-06-28 21:20:51 +01002453 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2454 if (unlikely(!iova)) {
2455 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2456 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002457 return NULL;
2458 }
2459
2460 return iova;
2461}
2462
David Woodhouse147202a2009-07-07 19:43:20 +01002463static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002464{
2465 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002466 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002467
2468 domain = get_domain_for_dev(pdev,
2469 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2470 if (!domain) {
2471 printk(KERN_ERR
2472 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002473 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002474 }
2475
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002476 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002477 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002478 ret = domain_context_mapping(domain, pdev,
2479 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002480 if (ret) {
2481 printk(KERN_ERR
2482 "Domain context map for %s failed",
2483 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002484 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002485 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002486 }
2487
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002488 return domain;
2489}
2490
David Woodhouse147202a2009-07-07 19:43:20 +01002491static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2492{
2493 struct device_domain_info *info;
2494
2495 /* No lock here, assumes no domain exit in normal case */
2496 info = dev->dev.archdata.iommu;
2497 if (likely(info))
2498 return info->domain;
2499
2500 return __get_valid_domain_for_dev(dev);
2501}
2502
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002503static int iommu_dummy(struct pci_dev *pdev)
2504{
2505 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2506}
2507
2508/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002509static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002510{
David Woodhouse73676832009-07-04 14:08:36 +01002511 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002512 int found;
2513
David Woodhouse73676832009-07-04 14:08:36 +01002514 if (unlikely(dev->bus != &pci_bus_type))
2515 return 1;
2516
2517 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002518 if (iommu_dummy(pdev))
2519 return 1;
2520
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002521 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002522 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002523
2524 found = identity_mapping(pdev);
2525 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002526 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002527 return 1;
2528 else {
2529 /*
2530 * 32 bit DMA is removed from si_domain and fall back
2531 * to non-identity mapping.
2532 */
2533 domain_remove_one_dev_info(si_domain, pdev);
2534 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2535 pci_name(pdev));
2536 return 0;
2537 }
2538 } else {
2539 /*
2540 * In case of a detached 64 bit DMA device from vm, the device
2541 * is put into si_domain for identity mapping.
2542 */
David Woodhouse6941af22009-07-04 18:24:27 +01002543 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002544 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002545 ret = domain_add_dev_info(si_domain, pdev,
2546 hw_pass_through ?
2547 CONTEXT_TT_PASS_THROUGH :
2548 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002549 if (!ret) {
2550 printk(KERN_INFO "64bit %s uses identity mapping\n",
2551 pci_name(pdev));
2552 return 1;
2553 }
2554 }
2555 }
2556
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002557 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002558}
2559
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002560static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2561 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002562{
2563 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002564 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002565 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002566 struct iova *iova;
2567 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002568 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002569 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002570 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002571
2572 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002573
David Woodhouse73676832009-07-04 14:08:36 +01002574 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002575 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002576
2577 domain = get_valid_domain_for_dev(pdev);
2578 if (!domain)
2579 return 0;
2580
Weidong Han8c11e792008-12-08 15:29:22 +08002581 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002582 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002583
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002584 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
2585 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002586 if (!iova)
2587 goto error;
2588
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002589 /*
2590 * Check if DMAR supports zero-length reads on write only
2591 * mappings..
2592 */
2593 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002594 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002595 prot |= DMA_PTE_READ;
2596 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2597 prot |= DMA_PTE_WRITE;
2598 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002599 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002600 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002601 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002602 * is not a big problem
2603 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002604 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002605 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002606 if (ret)
2607 goto error;
2608
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002609 /* it's a non-present to present mapping. Only flush if caching mode */
2610 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002611 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002612 else
Weidong Han8c11e792008-12-08 15:29:22 +08002613 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002614
David Woodhouse03d6a242009-06-28 15:33:46 +01002615 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2616 start_paddr += paddr & ~PAGE_MASK;
2617 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002618
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002619error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002620 if (iova)
2621 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002622 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002623 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002624 return 0;
2625}
2626
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002627static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2628 unsigned long offset, size_t size,
2629 enum dma_data_direction dir,
2630 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002631{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002632 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2633 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002634}
2635
mark gross5e0d2a62008-03-04 15:22:08 -08002636static void flush_unmaps(void)
2637{
mark gross80b20dd2008-04-18 13:53:58 -07002638 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002639
mark gross5e0d2a62008-03-04 15:22:08 -08002640 timer_on = 0;
2641
2642 /* just flush them all */
2643 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002644 struct intel_iommu *iommu = g_iommus[i];
2645 if (!iommu)
2646 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002647
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002648 if (!deferred_flush[i].next)
2649 continue;
2650
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002651 /* In caching mode, global flushes turn emulation expensive */
2652 if (!cap_caching_mode(iommu->cap))
2653 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002654 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002655 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002656 unsigned long mask;
2657 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002658 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002659
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002660 /* On real hardware multiple invalidations are expensive */
2661 if (cap_caching_mode(iommu->cap))
2662 iommu_flush_iotlb_psi(iommu, domain->id,
2663 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2664 else {
2665 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2666 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2667 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2668 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002669 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002670 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002671 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002672 }
2673
mark gross5e0d2a62008-03-04 15:22:08 -08002674 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002675}
2676
2677static void flush_unmaps_timeout(unsigned long data)
2678{
mark gross80b20dd2008-04-18 13:53:58 -07002679 unsigned long flags;
2680
2681 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002682 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002683 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002684}
2685
2686static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2687{
2688 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002689 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002690 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002691
2692 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002693 if (list_size == HIGH_WATER_MARK)
2694 flush_unmaps();
2695
Weidong Han8c11e792008-12-08 15:29:22 +08002696 iommu = domain_get_iommu(dom);
2697 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002698
mark gross80b20dd2008-04-18 13:53:58 -07002699 next = deferred_flush[iommu_id].next;
2700 deferred_flush[iommu_id].domain[next] = dom;
2701 deferred_flush[iommu_id].iova[next] = iova;
2702 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002703
2704 if (!timer_on) {
2705 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2706 timer_on = 1;
2707 }
2708 list_size++;
2709 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2710}
2711
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002712static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2713 size_t size, enum dma_data_direction dir,
2714 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002715{
2716 struct pci_dev *pdev = to_pci_dev(dev);
2717 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002718 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002719 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002720 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002721
David Woodhouse73676832009-07-04 14:08:36 +01002722 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002723 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002724
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002725 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002726 BUG_ON(!domain);
2727
Weidong Han8c11e792008-12-08 15:29:22 +08002728 iommu = domain_get_iommu(domain);
2729
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002730 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002731 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2732 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002733 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002734
David Woodhoused794dc92009-06-28 00:27:49 +01002735 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2736 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002737
David Woodhoused794dc92009-06-28 00:27:49 +01002738 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2739 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002740
2741 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002742 dma_pte_clear_range(domain, start_pfn, last_pfn);
2743
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002744 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002745 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2746
mark gross5e0d2a62008-03-04 15:22:08 -08002747 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002748 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002749 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002750 /* free iova */
2751 __free_iova(&domain->iovad, iova);
2752 } else {
2753 add_unmap(domain, iova);
2754 /*
2755 * queue up the release of the unmap to save the 1/6th of the
2756 * cpu used up by the iotlb flush operation...
2757 */
mark gross5e0d2a62008-03-04 15:22:08 -08002758 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002759}
2760
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002761static void *intel_alloc_coherent(struct device *hwdev, size_t size,
2762 dma_addr_t *dma_handle, gfp_t flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002763{
2764 void *vaddr;
2765 int order;
2766
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002767 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002768 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002769
2770 if (!iommu_no_mapping(hwdev))
2771 flags &= ~(GFP_DMA | GFP_DMA32);
2772 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
2773 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
2774 flags |= GFP_DMA;
2775 else
2776 flags |= GFP_DMA32;
2777 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002778
2779 vaddr = (void *)__get_free_pages(flags, order);
2780 if (!vaddr)
2781 return NULL;
2782 memset(vaddr, 0, size);
2783
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002784 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2785 DMA_BIDIRECTIONAL,
2786 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002787 if (*dma_handle)
2788 return vaddr;
2789 free_pages((unsigned long)vaddr, order);
2790 return NULL;
2791}
2792
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002793static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
2794 dma_addr_t dma_handle)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002795{
2796 int order;
2797
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002798 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002799 order = get_order(size);
2800
David Woodhouse0db9b7a2009-07-14 02:01:57 +01002801 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002802 free_pages((unsigned long)vaddr, order);
2803}
2804
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002805static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
2806 int nelems, enum dma_data_direction dir,
2807 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002808{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002809 struct pci_dev *pdev = to_pci_dev(hwdev);
2810 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002811 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002812 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002813 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002814
David Woodhouse73676832009-07-04 14:08:36 +01002815 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002816 return;
2817
2818 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08002819 BUG_ON(!domain);
2820
2821 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002822
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002823 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01002824 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
2825 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002826 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002827
David Woodhoused794dc92009-06-28 00:27:49 +01002828 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2829 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002830
2831 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002832 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002833
David Woodhoused794dc92009-06-28 00:27:49 +01002834 /* free page tables */
2835 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2836
David Woodhouseacea0012009-07-14 01:55:11 +01002837 if (intel_iommu_strict) {
2838 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002839 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01002840 /* free iova */
2841 __free_iova(&domain->iovad, iova);
2842 } else {
2843 add_unmap(domain, iova);
2844 /*
2845 * queue up the release of the unmap to save the 1/6th of the
2846 * cpu used up by the iotlb flush operation...
2847 */
2848 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002849}
2850
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002851static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002852 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002853{
2854 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002855 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002856
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002857 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002858 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00002859 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002860 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002861 }
2862 return nelems;
2863}
2864
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002865static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
2866 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002867{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002868 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002869 struct pci_dev *pdev = to_pci_dev(hwdev);
2870 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002871 size_t size = 0;
2872 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002873 struct iova *iova = NULL;
2874 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002875 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01002876 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08002877 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002878
2879 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01002880 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002881 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002882
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002883 domain = get_valid_domain_for_dev(pdev);
2884 if (!domain)
2885 return 0;
2886
Weidong Han8c11e792008-12-08 15:29:22 +08002887 iommu = domain_get_iommu(domain);
2888
David Woodhouseb536d242009-06-28 14:49:31 +01002889 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01002890 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002891
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002892 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
2893 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002894 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002895 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002896 return 0;
2897 }
2898
2899 /*
2900 * Check if DMAR supports zero-length reads on write only
2901 * mappings..
2902 */
2903 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002904 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002905 prot |= DMA_PTE_READ;
2906 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2907 prot |= DMA_PTE_WRITE;
2908
David Woodhouseb536d242009-06-28 14:49:31 +01002909 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01002910
Fenghua Yuf5329592009-08-04 15:09:37 -07002911 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01002912 if (unlikely(ret)) {
2913 /* clear the page */
2914 dma_pte_clear_range(domain, start_vpfn,
2915 start_vpfn + size - 1);
2916 /* free page tables */
2917 dma_pte_free_pagetable(domain, start_vpfn,
2918 start_vpfn + size - 1);
2919 /* free iova */
2920 __free_iova(&domain->iovad, iova);
2921 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002922 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002923
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002924 /* it's a non-present to present mapping. Only flush if caching mode */
2925 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002926 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002927 else
Weidong Han8c11e792008-12-08 15:29:22 +08002928 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002929
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002930 return nelems;
2931}
2932
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09002933static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
2934{
2935 return !dma_addr;
2936}
2937
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09002938struct dma_map_ops intel_dma_ops = {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002939 .alloc_coherent = intel_alloc_coherent,
2940 .free_coherent = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002941 .map_sg = intel_map_sg,
2942 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002943 .map_page = intel_map_page,
2944 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09002945 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002946};
2947
2948static inline int iommu_domain_cache_init(void)
2949{
2950 int ret = 0;
2951
2952 iommu_domain_cache = kmem_cache_create("iommu_domain",
2953 sizeof(struct dmar_domain),
2954 0,
2955 SLAB_HWCACHE_ALIGN,
2956
2957 NULL);
2958 if (!iommu_domain_cache) {
2959 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
2960 ret = -ENOMEM;
2961 }
2962
2963 return ret;
2964}
2965
2966static inline int iommu_devinfo_cache_init(void)
2967{
2968 int ret = 0;
2969
2970 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
2971 sizeof(struct device_domain_info),
2972 0,
2973 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002974 NULL);
2975 if (!iommu_devinfo_cache) {
2976 printk(KERN_ERR "Couldn't create devinfo cache\n");
2977 ret = -ENOMEM;
2978 }
2979
2980 return ret;
2981}
2982
2983static inline int iommu_iova_cache_init(void)
2984{
2985 int ret = 0;
2986
2987 iommu_iova_cache = kmem_cache_create("iommu_iova",
2988 sizeof(struct iova),
2989 0,
2990 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002991 NULL);
2992 if (!iommu_iova_cache) {
2993 printk(KERN_ERR "Couldn't create iova cache\n");
2994 ret = -ENOMEM;
2995 }
2996
2997 return ret;
2998}
2999
3000static int __init iommu_init_mempool(void)
3001{
3002 int ret;
3003 ret = iommu_iova_cache_init();
3004 if (ret)
3005 return ret;
3006
3007 ret = iommu_domain_cache_init();
3008 if (ret)
3009 goto domain_error;
3010
3011 ret = iommu_devinfo_cache_init();
3012 if (!ret)
3013 return ret;
3014
3015 kmem_cache_destroy(iommu_domain_cache);
3016domain_error:
3017 kmem_cache_destroy(iommu_iova_cache);
3018
3019 return -ENOMEM;
3020}
3021
3022static void __init iommu_exit_mempool(void)
3023{
3024 kmem_cache_destroy(iommu_devinfo_cache);
3025 kmem_cache_destroy(iommu_domain_cache);
3026 kmem_cache_destroy(iommu_iova_cache);
3027
3028}
3029
Dan Williams556ab452010-07-23 15:47:56 -07003030static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3031{
3032 struct dmar_drhd_unit *drhd;
3033 u32 vtbar;
3034 int rc;
3035
3036 /* We know that this device on this chipset has its own IOMMU.
3037 * If we find it under a different IOMMU, then the BIOS is lying
3038 * to us. Hope that the IOMMU for this device is actually
3039 * disabled, and it needs no translation...
3040 */
3041 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3042 if (rc) {
3043 /* "can't" happen */
3044 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3045 return;
3046 }
3047 vtbar &= 0xffff0000;
3048
3049 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3050 drhd = dmar_find_matched_drhd_unit(pdev);
3051 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3052 TAINT_FIRMWARE_WORKAROUND,
3053 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3054 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3055}
3056DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3057
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003058static void __init init_no_remapping_devices(void)
3059{
3060 struct dmar_drhd_unit *drhd;
3061
3062 for_each_drhd_unit(drhd) {
3063 if (!drhd->include_all) {
3064 int i;
3065 for (i = 0; i < drhd->devices_cnt; i++)
3066 if (drhd->devices[i] != NULL)
3067 break;
3068 /* ignore DMAR unit if no pci devices exist */
3069 if (i == drhd->devices_cnt)
3070 drhd->ignored = 1;
3071 }
3072 }
3073
3074 if (dmar_map_gfx)
3075 return;
3076
3077 for_each_drhd_unit(drhd) {
3078 int i;
3079 if (drhd->ignored || drhd->include_all)
3080 continue;
3081
3082 for (i = 0; i < drhd->devices_cnt; i++)
3083 if (drhd->devices[i] &&
3084 !IS_GFX_DEVICE(drhd->devices[i]))
3085 break;
3086
3087 if (i < drhd->devices_cnt)
3088 continue;
3089
3090 /* bypass IOMMU if it is just for gfx devices */
3091 drhd->ignored = 1;
3092 for (i = 0; i < drhd->devices_cnt; i++) {
3093 if (!drhd->devices[i])
3094 continue;
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07003095 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003096 }
3097 }
3098}
3099
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003100#ifdef CONFIG_SUSPEND
3101static int init_iommu_hw(void)
3102{
3103 struct dmar_drhd_unit *drhd;
3104 struct intel_iommu *iommu = NULL;
3105
3106 for_each_active_iommu(iommu, drhd)
3107 if (iommu->qi)
3108 dmar_reenable_qi(iommu);
3109
3110 for_each_active_iommu(iommu, drhd) {
3111 iommu_flush_write_buffer(iommu);
3112
3113 iommu_set_root_entry(iommu);
3114
3115 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003116 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003117 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003118 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003119 iommu_enable_translation(iommu);
David Woodhouseb94996c2009-09-19 15:28:12 -07003120 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003121 }
3122
3123 return 0;
3124}
3125
3126static void iommu_flush_all(void)
3127{
3128 struct dmar_drhd_unit *drhd;
3129 struct intel_iommu *iommu;
3130
3131 for_each_active_iommu(iommu, drhd) {
3132 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003133 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003134 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003135 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003136 }
3137}
3138
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003139static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003140{
3141 struct dmar_drhd_unit *drhd;
3142 struct intel_iommu *iommu = NULL;
3143 unsigned long flag;
3144
3145 for_each_active_iommu(iommu, drhd) {
3146 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3147 GFP_ATOMIC);
3148 if (!iommu->iommu_state)
3149 goto nomem;
3150 }
3151
3152 iommu_flush_all();
3153
3154 for_each_active_iommu(iommu, drhd) {
3155 iommu_disable_translation(iommu);
3156
3157 spin_lock_irqsave(&iommu->register_lock, flag);
3158
3159 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3160 readl(iommu->reg + DMAR_FECTL_REG);
3161 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3162 readl(iommu->reg + DMAR_FEDATA_REG);
3163 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3164 readl(iommu->reg + DMAR_FEADDR_REG);
3165 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3166 readl(iommu->reg + DMAR_FEUADDR_REG);
3167
3168 spin_unlock_irqrestore(&iommu->register_lock, flag);
3169 }
3170 return 0;
3171
3172nomem:
3173 for_each_active_iommu(iommu, drhd)
3174 kfree(iommu->iommu_state);
3175
3176 return -ENOMEM;
3177}
3178
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003179static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003180{
3181 struct dmar_drhd_unit *drhd;
3182 struct intel_iommu *iommu = NULL;
3183 unsigned long flag;
3184
3185 if (init_iommu_hw()) {
3186 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003187 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003188 }
3189
3190 for_each_active_iommu(iommu, drhd) {
3191
3192 spin_lock_irqsave(&iommu->register_lock, flag);
3193
3194 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3195 iommu->reg + DMAR_FECTL_REG);
3196 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3197 iommu->reg + DMAR_FEDATA_REG);
3198 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3199 iommu->reg + DMAR_FEADDR_REG);
3200 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3201 iommu->reg + DMAR_FEUADDR_REG);
3202
3203 spin_unlock_irqrestore(&iommu->register_lock, flag);
3204 }
3205
3206 for_each_active_iommu(iommu, drhd)
3207 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003208}
3209
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003210static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003211 .resume = iommu_resume,
3212 .suspend = iommu_suspend,
3213};
3214
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003215static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003216{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003217 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003218}
3219
3220#else
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003221static inline int init_iommu_pm_ops(void) { }
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003222#endif /* CONFIG_PM */
3223
Fenghua Yu99dcade2009-11-11 07:23:06 -08003224/*
3225 * Here we only respond to action of unbound device from driver.
3226 *
3227 * Added device is not attached to its DMAR domain here yet. That will happen
3228 * when mapping the device to iova.
3229 */
3230static int device_notifier(struct notifier_block *nb,
3231 unsigned long action, void *data)
3232{
3233 struct device *dev = data;
3234 struct pci_dev *pdev = to_pci_dev(dev);
3235 struct dmar_domain *domain;
3236
David Woodhouse44cd6132009-12-02 10:18:30 +00003237 if (iommu_no_mapping(dev))
3238 return 0;
3239
Fenghua Yu99dcade2009-11-11 07:23:06 -08003240 domain = find_domain(pdev);
3241 if (!domain)
3242 return 0;
3243
3244 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through)
3245 domain_remove_one_dev_info(domain, pdev);
3246
3247 return 0;
3248}
3249
3250static struct notifier_block device_nb = {
3251 .notifier_call = device_notifier,
3252};
3253
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003254int __init intel_iommu_init(void)
3255{
3256 int ret = 0;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003257 int force_on = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003258
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003259 /* VT-d is required for a TXT/tboot launch, so enforce that */
3260 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003261
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003262 if (dmar_table_init()) {
3263 if (force_on)
3264 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003265 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003266 }
3267
3268 if (dmar_dev_scope_init()) {
3269 if (force_on)
3270 panic("tboot: Failed to initialize DMAR device scope\n");
3271 return -ENODEV;
3272 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003273
Suresh Siddha2ae21012008-07-10 11:16:43 -07003274 /*
3275 * Check the need for DMA-remapping initialization now.
3276 * Above initialization will also be used by Interrupt-remapping.
3277 */
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003278 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003279 return -ENODEV;
3280
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003281 iommu_init_mempool();
3282 dmar_init_reserved_ranges();
3283
3284 init_no_remapping_devices();
3285
3286 ret = init_dmars();
3287 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003288 if (force_on)
3289 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003290 printk(KERN_ERR "IOMMU: dmar init failed\n");
3291 put_iova_domain(&reserved_iova_list);
3292 iommu_exit_mempool();
3293 return ret;
3294 }
3295 printk(KERN_INFO
3296 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3297
mark gross5e0d2a62008-03-04 15:22:08 -08003298 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003299#ifdef CONFIG_SWIOTLB
3300 swiotlb = 0;
3301#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003302 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003303
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003304 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003305
3306 register_iommu(&intel_iommu_ops);
3307
Fenghua Yu99dcade2009-11-11 07:23:06 -08003308 bus_register_notifier(&pci_bus_type, &device_nb);
3309
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003310 return 0;
3311}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003312
Han, Weidong3199aa62009-02-26 17:31:12 +08003313static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3314 struct pci_dev *pdev)
3315{
3316 struct pci_dev *tmp, *parent;
3317
3318 if (!iommu || !pdev)
3319 return;
3320
3321 /* dependent device detach */
3322 tmp = pci_find_upstream_pcie_bridge(pdev);
3323 /* Secondary interface's bus number and devfn 0 */
3324 if (tmp) {
3325 parent = pdev->bus->self;
3326 while (parent != tmp) {
3327 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01003328 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003329 parent = parent->bus->self;
3330 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003331 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003332 iommu_detach_dev(iommu,
3333 tmp->subordinate->number, 0);
3334 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01003335 iommu_detach_dev(iommu, tmp->bus->number,
3336 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003337 }
3338}
3339
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003340static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003341 struct pci_dev *pdev)
3342{
3343 struct device_domain_info *info;
3344 struct intel_iommu *iommu;
3345 unsigned long flags;
3346 int found = 0;
3347 struct list_head *entry, *tmp;
3348
David Woodhouse276dbf992009-04-04 01:45:37 +01003349 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3350 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003351 if (!iommu)
3352 return;
3353
3354 spin_lock_irqsave(&device_domain_lock, flags);
3355 list_for_each_safe(entry, tmp, &domain->devices) {
3356 info = list_entry(entry, struct device_domain_info, link);
David Woodhouse276dbf992009-04-04 01:45:37 +01003357 /* No need to compare PCI domain; it has to be the same */
Weidong Hanc7151a82008-12-08 22:51:37 +08003358 if (info->bus == pdev->bus->number &&
3359 info->devfn == pdev->devfn) {
3360 list_del(&info->link);
3361 list_del(&info->global);
3362 if (info->dev)
3363 info->dev->dev.archdata.iommu = NULL;
3364 spin_unlock_irqrestore(&device_domain_lock, flags);
3365
Yu Zhao93a23a72009-05-18 13:51:37 +08003366 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003367 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003368 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003369 free_devinfo_mem(info);
3370
3371 spin_lock_irqsave(&device_domain_lock, flags);
3372
3373 if (found)
3374 break;
3375 else
3376 continue;
3377 }
3378
3379 /* if there is no other devices under the same iommu
3380 * owned by this domain, clear this iommu in iommu_bmp
3381 * update iommu count and coherency
3382 */
David Woodhouse276dbf992009-04-04 01:45:37 +01003383 if (iommu == device_to_iommu(info->segment, info->bus,
3384 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003385 found = 1;
3386 }
3387
3388 if (found == 0) {
3389 unsigned long tmp_flags;
3390 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
3391 clear_bit(iommu->seq_id, &domain->iommu_bmp);
3392 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003393 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003394 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
3395 }
3396
3397 spin_unlock_irqrestore(&device_domain_lock, flags);
3398}
3399
3400static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3401{
3402 struct device_domain_info *info;
3403 struct intel_iommu *iommu;
3404 unsigned long flags1, flags2;
3405
3406 spin_lock_irqsave(&device_domain_lock, flags1);
3407 while (!list_empty(&domain->devices)) {
3408 info = list_entry(domain->devices.next,
3409 struct device_domain_info, link);
3410 list_del(&info->link);
3411 list_del(&info->global);
3412 if (info->dev)
3413 info->dev->dev.archdata.iommu = NULL;
3414
3415 spin_unlock_irqrestore(&device_domain_lock, flags1);
3416
Yu Zhao93a23a72009-05-18 13:51:37 +08003417 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01003418 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003419 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003420 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003421
3422 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003423 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003424 */
3425 spin_lock_irqsave(&domain->iommu_lock, flags2);
3426 if (test_and_clear_bit(iommu->seq_id,
3427 &domain->iommu_bmp)) {
3428 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003429 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003430 }
3431 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3432
3433 free_devinfo_mem(info);
3434 spin_lock_irqsave(&device_domain_lock, flags1);
3435 }
3436 spin_unlock_irqrestore(&device_domain_lock, flags1);
3437}
3438
Weidong Han5e98c4b2008-12-08 23:03:27 +08003439/* domain id for virtual machine, it won't be set in context */
3440static unsigned long vm_domid;
3441
3442static struct dmar_domain *iommu_alloc_vm_domain(void)
3443{
3444 struct dmar_domain *domain;
3445
3446 domain = alloc_domain_mem();
3447 if (!domain)
3448 return NULL;
3449
3450 domain->id = vm_domid++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003451 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003452 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
3453 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3454
3455 return domain;
3456}
3457
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003458static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003459{
3460 int adjust_width;
3461
3462 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003463 spin_lock_init(&domain->iommu_lock);
3464
3465 domain_reserve_special_ranges(domain);
3466
3467 /* calculate AGAW */
3468 domain->gaw = guest_width;
3469 adjust_width = guestwidth_to_adjustwidth(guest_width);
3470 domain->agaw = width_to_agaw(adjust_width);
3471
3472 INIT_LIST_HEAD(&domain->devices);
3473
3474 domain->iommu_count = 0;
3475 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003476 domain->iommu_snooping = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003477 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003478 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003479
3480 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003481 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003482 if (!domain->pgd)
3483 return -ENOMEM;
3484 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3485 return 0;
3486}
3487
3488static void iommu_free_vm_domain(struct dmar_domain *domain)
3489{
3490 unsigned long flags;
3491 struct dmar_drhd_unit *drhd;
3492 struct intel_iommu *iommu;
3493 unsigned long i;
3494 unsigned long ndomains;
3495
3496 for_each_drhd_unit(drhd) {
3497 if (drhd->ignored)
3498 continue;
3499 iommu = drhd->iommu;
3500
3501 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08003502 for_each_set_bit(i, iommu->domain_ids, ndomains) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003503 if (iommu->domains[i] == domain) {
3504 spin_lock_irqsave(&iommu->lock, flags);
3505 clear_bit(i, iommu->domain_ids);
3506 iommu->domains[i] = NULL;
3507 spin_unlock_irqrestore(&iommu->lock, flags);
3508 break;
3509 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08003510 }
3511 }
3512}
3513
3514static void vm_domain_exit(struct dmar_domain *domain)
3515{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003516 /* Domain 0 is reserved, so dont process it */
3517 if (!domain)
3518 return;
3519
3520 vm_domain_remove_all_dev_info(domain);
3521 /* destroy iovas */
3522 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003523
3524 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003525 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003526
3527 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003528 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003529
3530 iommu_free_vm_domain(domain);
3531 free_domain_mem(domain);
3532}
3533
Joerg Roedel5d450802008-12-03 14:52:32 +01003534static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003535{
Joerg Roedel5d450802008-12-03 14:52:32 +01003536 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003537
Joerg Roedel5d450802008-12-03 14:52:32 +01003538 dmar_domain = iommu_alloc_vm_domain();
3539 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003540 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003541 "intel_iommu_domain_init: dmar_domain == NULL\n");
3542 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003543 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003544 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003545 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003546 "intel_iommu_domain_init() failed\n");
3547 vm_domain_exit(dmar_domain);
3548 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003549 }
Joerg Roedel5d450802008-12-03 14:52:32 +01003550 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003551
Joerg Roedel5d450802008-12-03 14:52:32 +01003552 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003553}
Kay, Allen M38717942008-09-09 18:37:29 +03003554
Joerg Roedel5d450802008-12-03 14:52:32 +01003555static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003556{
Joerg Roedel5d450802008-12-03 14:52:32 +01003557 struct dmar_domain *dmar_domain = domain->priv;
3558
3559 domain->priv = NULL;
3560 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003561}
Kay, Allen M38717942008-09-09 18:37:29 +03003562
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003563static int intel_iommu_attach_device(struct iommu_domain *domain,
3564 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003565{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003566 struct dmar_domain *dmar_domain = domain->priv;
3567 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003568 struct intel_iommu *iommu;
3569 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03003570
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003571 /* normally pdev is not mapped */
3572 if (unlikely(domain_context_mapped(pdev))) {
3573 struct dmar_domain *old_domain;
3574
3575 old_domain = find_domain(pdev);
3576 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003577 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3578 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3579 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003580 else
3581 domain_remove_dev_info(old_domain);
3582 }
3583 }
3584
David Woodhouse276dbf992009-04-04 01:45:37 +01003585 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3586 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003587 if (!iommu)
3588 return -ENODEV;
3589
3590 /* check if this iommu agaw is sufficient for max mapped address */
3591 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01003592 if (addr_width > cap_mgaw(iommu->cap))
3593 addr_width = cap_mgaw(iommu->cap);
3594
3595 if (dmar_domain->max_addr > (1LL << addr_width)) {
3596 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003597 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01003598 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003599 return -EFAULT;
3600 }
Tom Lyona99c47a2010-05-17 08:20:45 +01003601 dmar_domain->gaw = addr_width;
3602
3603 /*
3604 * Knock out extra levels of page tables if necessary
3605 */
3606 while (iommu->agaw < dmar_domain->agaw) {
3607 struct dma_pte *pte;
3608
3609 pte = dmar_domain->pgd;
3610 if (dma_pte_present(pte)) {
3611 free_pgtable_page(dmar_domain->pgd);
Sheng Yang25cbff12010-06-12 19:21:42 +08003612 dmar_domain->pgd = (struct dma_pte *)
3613 phys_to_virt(dma_pte_addr(pte));
Tom Lyona99c47a2010-05-17 08:20:45 +01003614 }
3615 dmar_domain->agaw--;
3616 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003617
David Woodhouse5fe60f42009-08-09 10:53:41 +01003618 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003619}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003620
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003621static void intel_iommu_detach_device(struct iommu_domain *domain,
3622 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003623{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003624 struct dmar_domain *dmar_domain = domain->priv;
3625 struct pci_dev *pdev = to_pci_dev(dev);
3626
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003627 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003628}
Kay, Allen M38717942008-09-09 18:37:29 +03003629
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003630static int intel_iommu_map(struct iommu_domain *domain,
3631 unsigned long iova, phys_addr_t hpa,
3632 int gfp_order, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003633{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003634 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003635 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003636 int prot = 0;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003637 size_t size;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003638 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003639
Joerg Roedeldde57a22008-12-03 15:04:09 +01003640 if (iommu_prot & IOMMU_READ)
3641 prot |= DMA_PTE_READ;
3642 if (iommu_prot & IOMMU_WRITE)
3643 prot |= DMA_PTE_WRITE;
Sheng Yang9cf066972009-03-18 15:33:07 +08003644 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
3645 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003646
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003647 size = PAGE_SIZE << gfp_order;
David Woodhouse163cc522009-06-28 00:51:17 +01003648 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003649 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003650 u64 end;
3651
3652 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01003653 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003654 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01003655 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003656 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01003657 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003658 return -EFAULT;
3659 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003660 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003661 }
David Woodhousead051222009-06-28 14:22:28 +01003662 /* Round up size to next multiple of PAGE_SIZE, if it and
3663 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01003664 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01003665 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
3666 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003667 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003668}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003669
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003670static int intel_iommu_unmap(struct iommu_domain *domain,
3671 unsigned long iova, int gfp_order)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003672{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003673 struct dmar_domain *dmar_domain = domain->priv;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003674 size_t size = PAGE_SIZE << gfp_order;
Sheng Yang4b99d352009-07-08 11:52:52 +01003675
David Woodhouse163cc522009-06-28 00:51:17 +01003676 dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
3677 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003678
David Woodhouse163cc522009-06-28 00:51:17 +01003679 if (dmar_domain->max_addr == iova + size)
3680 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003681
3682 return gfp_order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003683}
Kay, Allen M38717942008-09-09 18:37:29 +03003684
Joerg Roedeld14d6572008-12-03 15:06:57 +01003685static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
3686 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03003687{
Joerg Roedeld14d6572008-12-03 15:06:57 +01003688 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03003689 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003690 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003691
David Woodhouseb026fd22009-06-28 10:37:25 +01003692 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
Kay, Allen M38717942008-09-09 18:37:29 +03003693 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003694 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03003695
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003696 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03003697}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003698
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003699static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
3700 unsigned long cap)
3701{
3702 struct dmar_domain *dmar_domain = domain->priv;
3703
3704 if (cap == IOMMU_CAP_CACHE_COHERENCY)
3705 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04003706 if (cap == IOMMU_CAP_INTR_REMAP)
3707 return intr_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003708
3709 return 0;
3710}
3711
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003712static struct iommu_ops intel_iommu_ops = {
3713 .domain_init = intel_iommu_domain_init,
3714 .domain_destroy = intel_iommu_domain_destroy,
3715 .attach_dev = intel_iommu_attach_device,
3716 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003717 .map = intel_iommu_map,
3718 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003719 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003720 .domain_has_cap = intel_iommu_domain_has_cap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003721};
David Woodhouse9af88142009-02-13 23:18:03 +00003722
3723static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
3724{
3725 /*
3726 * Mobile 4 Series Chipset neglects to set RWBF capability,
3727 * but needs it:
3728 */
3729 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
3730 rwbf_quirk = 1;
David Woodhouse2d9e6672010-06-15 10:57:57 +01003731
3732 /* https://bugzilla.redhat.com/show_bug.cgi?id=538163 */
3733 if (dev->revision == 0x07) {
3734 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
3735 dmar_map_gfx = 0;
3736 }
David Woodhouse9af88142009-02-13 23:18:03 +00003737}
3738
3739DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07003740
Adam Jacksoneecfd572010-08-25 21:17:34 +01003741#define GGC 0x52
3742#define GGC_MEMORY_SIZE_MASK (0xf << 8)
3743#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
3744#define GGC_MEMORY_SIZE_1M (0x1 << 8)
3745#define GGC_MEMORY_SIZE_2M (0x3 << 8)
3746#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
3747#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
3748#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
3749#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
3750
David Woodhouse9eecabc2010-09-21 22:28:23 +01003751static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
3752{
3753 unsigned short ggc;
3754
Adam Jacksoneecfd572010-08-25 21:17:34 +01003755 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01003756 return;
3757
Adam Jacksoneecfd572010-08-25 21:17:34 +01003758 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01003759 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
3760 dmar_map_gfx = 0;
3761 }
3762}
3763DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
3764DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
3765DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
3766DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
3767
David Woodhousee0fc7e02009-09-30 09:12:17 -07003768/* On Tylersburg chipsets, some BIOSes have been known to enable the
3769 ISOCH DMAR unit for the Azalia sound device, but not give it any
3770 TLB entries, which causes it to deadlock. Check for that. We do
3771 this in a function called from init_dmars(), instead of in a PCI
3772 quirk, because we don't want to print the obnoxious "BIOS broken"
3773 message if VT-d is actually disabled.
3774*/
3775static void __init check_tylersburg_isoch(void)
3776{
3777 struct pci_dev *pdev;
3778 uint32_t vtisochctrl;
3779
3780 /* If there's no Azalia in the system anyway, forget it. */
3781 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
3782 if (!pdev)
3783 return;
3784 pci_dev_put(pdev);
3785
3786 /* System Management Registers. Might be hidden, in which case
3787 we can't do the sanity check. But that's OK, because the
3788 known-broken BIOSes _don't_ actually hide it, so far. */
3789 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
3790 if (!pdev)
3791 return;
3792
3793 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
3794 pci_dev_put(pdev);
3795 return;
3796 }
3797
3798 pci_dev_put(pdev);
3799
3800 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
3801 if (vtisochctrl & 1)
3802 return;
3803
3804 /* Drop all bits other than the number of TLB entries */
3805 vtisochctrl &= 0x1c;
3806
3807 /* If we have the recommended number of TLB entries (16), fine. */
3808 if (vtisochctrl == 0x10)
3809 return;
3810
3811 /* Zero TLB entries? You get to ride the short bus to school. */
3812 if (!vtisochctrl) {
3813 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
3814 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
3815 dmi_get_system_info(DMI_BIOS_VENDOR),
3816 dmi_get_system_info(DMI_BIOS_VERSION),
3817 dmi_get_system_info(DMI_PRODUCT_VERSION));
3818 iommu_identity_mapping |= IDENTMAP_AZALIA;
3819 return;
3820 }
3821
3822 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
3823 vtisochctrl);
3824}