blob: 395f253c0494b641652b0e126adb798ebee0e6df [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>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070042#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090043#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070044#include "pci.h"
45
Fenghua Yu5b6985c2008-10-16 18:02:32 -070046#define ROOT_SIZE VTD_PAGE_SIZE
47#define CONTEXT_SIZE VTD_PAGE_SIZE
48
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070049#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
50#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070051#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070052
53#define IOAPIC_RANGE_START (0xfee00000)
54#define IOAPIC_RANGE_END (0xfeefffff)
55#define IOVA_START_ADDR (0x1000)
56
57#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
58
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070059#define MAX_AGAW_WIDTH 64
60
David Woodhouse2ebe3152009-09-19 07:34:04 -070061#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
62#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
63
64/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
65 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
66#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
67 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
68#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070069
Mark McLoughlinf27be032008-11-20 15:49:43 +000070#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070071#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070072#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080073
Andrew Mortondf08cdc2010-09-22 13:05:11 -070074/* page table handling */
75#define LEVEL_STRIDE (9)
76#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
77
78static inline int agaw_to_level(int agaw)
79{
80 return agaw + 2;
81}
82
83static inline int agaw_to_width(int agaw)
84{
85 return 30 + agaw * LEVEL_STRIDE;
86}
87
88static inline int width_to_agaw(int width)
89{
90 return (width - 30) / LEVEL_STRIDE;
91}
92
93static inline unsigned int level_to_offset_bits(int level)
94{
95 return (level - 1) * LEVEL_STRIDE;
96}
97
98static inline int pfn_level_offset(unsigned long pfn, int level)
99{
100 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
101}
102
103static inline unsigned long level_mask(int level)
104{
105 return -1UL << level_to_offset_bits(level);
106}
107
108static inline unsigned long level_size(int level)
109{
110 return 1UL << level_to_offset_bits(level);
111}
112
113static inline unsigned long align_to_level(unsigned long pfn, int level)
114{
115 return (pfn + level_size(level) - 1) & level_mask(level);
116}
David Woodhousefd18de52009-05-10 23:57:41 +0100117
David Woodhousedd4e8312009-06-27 16:21:20 +0100118/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
119 are never going to work. */
120static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
121{
122 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
123}
124
125static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
126{
127 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
128}
129static inline unsigned long page_to_dma_pfn(struct page *pg)
130{
131 return mm_to_dma_pfn(page_to_pfn(pg));
132}
133static inline unsigned long virt_to_dma_pfn(void *p)
134{
135 return page_to_dma_pfn(virt_to_page(p));
136}
137
Weidong Hand9630fe2008-12-08 11:06:32 +0800138/* global iommu list, set NULL for ignored DMAR units */
139static struct intel_iommu **g_iommus;
140
David Woodhousee0fc7e02009-09-30 09:12:17 -0700141static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000142static int rwbf_quirk;
143
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000144/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700145 * set to 1 to panic kernel if can't successfully enable VT-d
146 * (used when kernel is launched w/ TXT)
147 */
148static int force_on = 0;
149
150/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000151 * 0: Present
152 * 1-11: Reserved
153 * 12-63: Context Ptr (12 - (haw-1))
154 * 64-127: Reserved
155 */
156struct root_entry {
157 u64 val;
158 u64 rsvd1;
159};
160#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
161static inline bool root_present(struct root_entry *root)
162{
163 return (root->val & 1);
164}
165static inline void set_root_present(struct root_entry *root)
166{
167 root->val |= 1;
168}
169static inline void set_root_value(struct root_entry *root, unsigned long value)
170{
171 root->val |= value & VTD_PAGE_MASK;
172}
173
174static inline struct context_entry *
175get_context_addr_from_root(struct root_entry *root)
176{
177 return (struct context_entry *)
178 (root_present(root)?phys_to_virt(
179 root->val & VTD_PAGE_MASK) :
180 NULL);
181}
182
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000183/*
184 * low 64 bits:
185 * 0: present
186 * 1: fault processing disable
187 * 2-3: translation type
188 * 12-63: address space root
189 * high 64 bits:
190 * 0-2: address width
191 * 3-6: aval
192 * 8-23: domain id
193 */
194struct context_entry {
195 u64 lo;
196 u64 hi;
197};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000198
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000199static inline bool context_present(struct context_entry *context)
200{
201 return (context->lo & 1);
202}
203static inline void context_set_present(struct context_entry *context)
204{
205 context->lo |= 1;
206}
207
208static inline void context_set_fault_enable(struct context_entry *context)
209{
210 context->lo &= (((u64)-1) << 2) | 1;
211}
212
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000213static inline void context_set_translation_type(struct context_entry *context,
214 unsigned long value)
215{
216 context->lo &= (((u64)-1) << 4) | 3;
217 context->lo |= (value & 3) << 2;
218}
219
220static inline void context_set_address_root(struct context_entry *context,
221 unsigned long value)
222{
223 context->lo |= value & VTD_PAGE_MASK;
224}
225
226static inline void context_set_address_width(struct context_entry *context,
227 unsigned long value)
228{
229 context->hi |= value & 7;
230}
231
232static inline void context_set_domain_id(struct context_entry *context,
233 unsigned long value)
234{
235 context->hi |= (value & ((1 << 16) - 1)) << 8;
236}
237
238static inline void context_clear_entry(struct context_entry *context)
239{
240 context->lo = 0;
241 context->hi = 0;
242}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000243
Mark McLoughlin622ba122008-11-20 15:49:46 +0000244/*
245 * 0: readable
246 * 1: writable
247 * 2-6: reserved
248 * 7: super page
Sheng Yang9cf06692009-03-18 15:33:07 +0800249 * 8-10: available
250 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000251 * 12-63: Host physcial address
252 */
253struct dma_pte {
254 u64 val;
255};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000256
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000257static inline void dma_clear_pte(struct dma_pte *pte)
258{
259 pte->val = 0;
260}
261
262static inline void dma_set_pte_readable(struct dma_pte *pte)
263{
264 pte->val |= DMA_PTE_READ;
265}
266
267static inline void dma_set_pte_writable(struct dma_pte *pte)
268{
269 pte->val |= DMA_PTE_WRITE;
270}
271
Sheng Yang9cf06692009-03-18 15:33:07 +0800272static inline void dma_set_pte_snp(struct dma_pte *pte)
273{
274 pte->val |= DMA_PTE_SNP;
275}
276
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000277static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
278{
279 pte->val = (pte->val & ~3) | (prot & 3);
280}
281
282static inline u64 dma_pte_addr(struct dma_pte *pte)
283{
David Woodhousec85994e2009-07-01 19:21:24 +0100284#ifdef CONFIG_64BIT
285 return pte->val & VTD_PAGE_MASK;
286#else
287 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100288 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100289#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000290}
291
David Woodhousedd4e8312009-06-27 16:21:20 +0100292static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000293{
David Woodhousedd4e8312009-06-27 16:21:20 +0100294 pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000295}
296
297static inline bool dma_pte_present(struct dma_pte *pte)
298{
299 return (pte->val & 3) != 0;
300}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000301
David Woodhouse75e6bf92009-07-02 11:21:16 +0100302static inline int first_pte_in_page(struct dma_pte *pte)
303{
304 return !((unsigned long)pte & ~VTD_PAGE_MASK);
305}
306
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700307/*
308 * This domain is a statically identity mapping domain.
309 * 1. This domain creats a static 1:1 mapping to all usable memory.
310 * 2. It maps to each iommu if successful.
311 * 3. Each iommu mapps to this domain if successful.
312 */
David Woodhouse19943b02009-08-04 16:19:20 +0100313static struct dmar_domain *si_domain;
314static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700315
Weidong Han3b5410e2008-12-08 09:17:15 +0800316/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100317#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800318
Weidong Han1ce28fe2008-12-08 16:35:39 +0800319/* domain represents a virtual machine, more than one devices
320 * across iommus may be owned in one domain, e.g. kvm guest.
321 */
322#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
323
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700324/* si_domain contains mulitple devices */
325#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
326
Mark McLoughlin99126f72008-11-20 15:49:47 +0000327struct dmar_domain {
328 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700329 int nid; /* node id */
Weidong Han8c11e792008-12-08 15:29:22 +0800330 unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000331
332 struct list_head devices; /* all devices' list */
333 struct iova_domain iovad; /* iova's that belong to this domain */
334
335 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000336 int gaw; /* max guest address width */
337
338 /* adjusted guest address width, 0 is level 2 30-bit */
339 int agaw;
340
Weidong Han3b5410e2008-12-08 09:17:15 +0800341 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800342
343 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800344 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800345 int iommu_count; /* reference count of iommu */
346 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800347 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000348};
349
Mark McLoughlina647dacb2008-11-20 15:49:48 +0000350/* PCI domain-device relationship */
351struct device_domain_info {
352 struct list_head link; /* link to domain siblings */
353 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100354 int segment; /* PCI domain */
355 u8 bus; /* PCI bus number */
Mark McLoughlina647dacb2008-11-20 15:49:48 +0000356 u8 devfn; /* PCI devfn number */
Stefan Assmann45e829e2009-12-03 06:49:24 -0500357 struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800358 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dacb2008-11-20 15:49:48 +0000359 struct dmar_domain *domain; /* pointer to domain */
360};
361
mark gross5e0d2a62008-03-04 15:22:08 -0800362static void flush_unmaps_timeout(unsigned long data);
363
364DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
365
mark gross80b20dd2008-04-18 13:53:58 -0700366#define HIGH_WATER_MARK 250
367struct deferred_flush_tables {
368 int next;
369 struct iova *iova[HIGH_WATER_MARK];
370 struct dmar_domain *domain[HIGH_WATER_MARK];
371};
372
373static struct deferred_flush_tables *deferred_flush;
374
mark gross5e0d2a62008-03-04 15:22:08 -0800375/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800376static int g_num_of_iommus;
377
378static DEFINE_SPINLOCK(async_umap_flush_lock);
379static LIST_HEAD(unmaps_to_do);
380
381static int timer_on;
382static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800383
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700384static void domain_remove_dev_info(struct dmar_domain *domain);
385
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800386#ifdef CONFIG_DMAR_DEFAULT_ON
387int dmar_disabled = 0;
388#else
389int dmar_disabled = 1;
390#endif /*CONFIG_DMAR_DEFAULT_ON*/
391
David Woodhouse2d9e6672010-06-15 10:57:57 +0100392static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700393static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800394static int intel_iommu_strict;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700395
396#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
397static DEFINE_SPINLOCK(device_domain_lock);
398static LIST_HEAD(device_domain_list);
399
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100400static struct iommu_ops intel_iommu_ops;
401
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700402static int __init intel_iommu_setup(char *str)
403{
404 if (!str)
405 return -EINVAL;
406 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800407 if (!strncmp(str, "on", 2)) {
408 dmar_disabled = 0;
409 printk(KERN_INFO "Intel-IOMMU: enabled\n");
410 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700411 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800412 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700413 } else if (!strncmp(str, "igfx_off", 8)) {
414 dmar_map_gfx = 0;
415 printk(KERN_INFO
416 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700417 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800418 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700419 "Intel-IOMMU: Forcing DAC for PCI devices\n");
420 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800421 } else if (!strncmp(str, "strict", 6)) {
422 printk(KERN_INFO
423 "Intel-IOMMU: disable batched IOTLB flush\n");
424 intel_iommu_strict = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700425 }
426
427 str += strcspn(str, ",");
428 while (*str == ',')
429 str++;
430 }
431 return 0;
432}
433__setup("intel_iommu=", intel_iommu_setup);
434
435static struct kmem_cache *iommu_domain_cache;
436static struct kmem_cache *iommu_devinfo_cache;
437static struct kmem_cache *iommu_iova_cache;
438
Suresh Siddha4c923d42009-10-02 11:01:24 -0700439static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700440{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700441 struct page *page;
442 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700443
Suresh Siddha4c923d42009-10-02 11:01:24 -0700444 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
445 if (page)
446 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700447 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700448}
449
450static inline void free_pgtable_page(void *vaddr)
451{
452 free_page((unsigned long)vaddr);
453}
454
455static inline void *alloc_domain_mem(void)
456{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900457 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700458}
459
Kay, Allen M38717942008-09-09 18:37:29 +0300460static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700461{
462 kmem_cache_free(iommu_domain_cache, vaddr);
463}
464
465static inline void * alloc_devinfo_mem(void)
466{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900467 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700468}
469
470static inline void free_devinfo_mem(void *vaddr)
471{
472 kmem_cache_free(iommu_devinfo_cache, vaddr);
473}
474
475struct iova *alloc_iova_mem(void)
476{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900477 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700478}
479
480void free_iova_mem(struct iova *iova)
481{
482 kmem_cache_free(iommu_iova_cache, iova);
483}
484
Weidong Han1b573682008-12-08 15:34:06 +0800485
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700486static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800487{
488 unsigned long sagaw;
489 int agaw = -1;
490
491 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700492 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800493 agaw >= 0; agaw--) {
494 if (test_bit(agaw, &sagaw))
495 break;
496 }
497
498 return agaw;
499}
500
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700501/*
502 * Calculate max SAGAW for each iommu.
503 */
504int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
505{
506 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
507}
508
509/*
510 * calculate agaw for each iommu.
511 * "SAGAW" may be different across iommus, use a default agaw, and
512 * get a supported less agaw for iommus that don't support the default agaw.
513 */
514int iommu_calculate_agaw(struct intel_iommu *iommu)
515{
516 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
517}
518
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700519/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800520static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
521{
522 int iommu_id;
523
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700524 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800525 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700526 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800527
Weidong Han8c11e792008-12-08 15:29:22 +0800528 iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
529 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
530 return NULL;
531
532 return g_iommus[iommu_id];
533}
534
Weidong Han8e6040972008-12-08 15:49:06 +0800535static void domain_update_iommu_coherency(struct dmar_domain *domain)
536{
537 int i;
538
539 domain->iommu_coherency = 1;
540
Akinobu Mitaa45946a2010-03-11 14:04:08 -0800541 for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e6040972008-12-08 15:49:06 +0800542 if (!ecap_coherent(g_iommus[i]->ecap)) {
543 domain->iommu_coherency = 0;
544 break;
545 }
Weidong Han8e6040972008-12-08 15:49:06 +0800546 }
547}
548
Sheng Yang58c610b2009-03-18 15:33:05 +0800549static void domain_update_iommu_snooping(struct dmar_domain *domain)
550{
551 int i;
552
553 domain->iommu_snooping = 1;
554
Akinobu Mitaa45946a2010-03-11 14:04:08 -0800555 for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800556 if (!ecap_sc_support(g_iommus[i]->ecap)) {
557 domain->iommu_snooping = 0;
558 break;
559 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800560 }
561}
562
563/* Some capabilities may be different across iommus */
564static void domain_update_iommu_cap(struct dmar_domain *domain)
565{
566 domain_update_iommu_coherency(domain);
567 domain_update_iommu_snooping(domain);
568}
569
David Woodhouse276dbf992009-04-04 01:45:37 +0100570static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800571{
572 struct dmar_drhd_unit *drhd = NULL;
573 int i;
574
575 for_each_drhd_unit(drhd) {
576 if (drhd->ignored)
577 continue;
David Woodhouse276dbf992009-04-04 01:45:37 +0100578 if (segment != drhd->segment)
579 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800580
David Woodhouse924b6232009-04-04 00:39:25 +0100581 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000582 if (drhd->devices[i] &&
583 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800584 drhd->devices[i]->devfn == devfn)
585 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700586 if (drhd->devices[i] &&
587 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100588 drhd->devices[i]->subordinate->number <= bus &&
589 drhd->devices[i]->subordinate->subordinate >= bus)
590 return drhd->iommu;
591 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800592
593 if (drhd->include_all)
594 return drhd->iommu;
595 }
596
597 return NULL;
598}
599
Weidong Han5331fe62008-12-08 23:00:00 +0800600static void domain_flush_cache(struct dmar_domain *domain,
601 void *addr, int size)
602{
603 if (!domain->iommu_coherency)
604 clflush_cache_range(addr, size);
605}
606
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700607/* Gets context entry for a given bus and devfn */
608static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
609 u8 bus, u8 devfn)
610{
611 struct root_entry *root;
612 struct context_entry *context;
613 unsigned long phy_addr;
614 unsigned long flags;
615
616 spin_lock_irqsave(&iommu->lock, flags);
617 root = &iommu->root_entry[bus];
618 context = get_context_addr_from_root(root);
619 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700620 context = (struct context_entry *)
621 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700622 if (!context) {
623 spin_unlock_irqrestore(&iommu->lock, flags);
624 return NULL;
625 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700626 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700627 phy_addr = virt_to_phys((void *)context);
628 set_root_value(root, phy_addr);
629 set_root_present(root);
630 __iommu_flush_cache(iommu, root, sizeof(*root));
631 }
632 spin_unlock_irqrestore(&iommu->lock, flags);
633 return &context[devfn];
634}
635
636static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
637{
638 struct root_entry *root;
639 struct context_entry *context;
640 int ret;
641 unsigned long flags;
642
643 spin_lock_irqsave(&iommu->lock, flags);
644 root = &iommu->root_entry[bus];
645 context = get_context_addr_from_root(root);
646 if (!context) {
647 ret = 0;
648 goto out;
649 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000650 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700651out:
652 spin_unlock_irqrestore(&iommu->lock, flags);
653 return ret;
654}
655
656static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
657{
658 struct root_entry *root;
659 struct context_entry *context;
660 unsigned long flags;
661
662 spin_lock_irqsave(&iommu->lock, flags);
663 root = &iommu->root_entry[bus];
664 context = get_context_addr_from_root(root);
665 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000666 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700667 __iommu_flush_cache(iommu, &context[devfn], \
668 sizeof(*context));
669 }
670 spin_unlock_irqrestore(&iommu->lock, flags);
671}
672
673static void free_context_table(struct intel_iommu *iommu)
674{
675 struct root_entry *root;
676 int i;
677 unsigned long flags;
678 struct context_entry *context;
679
680 spin_lock_irqsave(&iommu->lock, flags);
681 if (!iommu->root_entry) {
682 goto out;
683 }
684 for (i = 0; i < ROOT_ENTRY_NR; i++) {
685 root = &iommu->root_entry[i];
686 context = get_context_addr_from_root(root);
687 if (context)
688 free_pgtable_page(context);
689 }
690 free_pgtable_page(iommu->root_entry);
691 iommu->root_entry = NULL;
692out:
693 spin_unlock_irqrestore(&iommu->lock, flags);
694}
695
David Woodhouseb026fd22009-06-28 10:37:25 +0100696static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
697 unsigned long pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700698{
David Woodhouseb026fd22009-06-28 10:37:25 +0100699 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700700 struct dma_pte *parent, *pte = NULL;
701 int level = agaw_to_level(domain->agaw);
702 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700703
704 BUG_ON(!domain->pgd);
David Woodhouseb026fd22009-06-28 10:37:25 +0100705 BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700706 parent = domain->pgd;
707
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700708 while (level > 0) {
709 void *tmp_page;
710
David Woodhouseb026fd22009-06-28 10:37:25 +0100711 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700712 pte = &parent[offset];
713 if (level == 1)
714 break;
715
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000716 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100717 uint64_t pteval;
718
Suresh Siddha4c923d42009-10-02 11:01:24 -0700719 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700720
David Woodhouse206a73c2009-07-01 19:30:28 +0100721 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700722 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100723
David Woodhousec85994e2009-07-01 19:21:24 +0100724 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400725 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 +0100726 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
727 /* Someone else set it while we were thinking; use theirs. */
728 free_pgtable_page(tmp_page);
729 } else {
730 dma_pte_addr(pte);
731 domain_flush_cache(domain, pte, sizeof(*pte));
732 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700733 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000734 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700735 level--;
736 }
737
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700738 return pte;
739}
740
741/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100742static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
743 unsigned long pfn,
744 int level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700745{
746 struct dma_pte *parent, *pte = NULL;
747 int total = agaw_to_level(domain->agaw);
748 int offset;
749
750 parent = domain->pgd;
751 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100752 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700753 pte = &parent[offset];
754 if (level == total)
755 return pte;
756
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000757 if (!dma_pte_present(pte))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700758 break;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000759 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700760 total--;
761 }
762 return NULL;
763}
764
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700765/* clear last level pte, a tlb flush should be followed */
David Woodhouse595badf52009-06-27 22:09:11 +0100766static void dma_pte_clear_range(struct dmar_domain *domain,
767 unsigned long start_pfn,
768 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700769{
David Woodhouse04b18e62009-06-27 19:15:01 +0100770 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100771 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700772
David Woodhouse04b18e62009-06-27 19:15:01 +0100773 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf52009-06-27 22:09:11 +0100774 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700775 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100776
David Woodhouse04b18e62009-06-27 19:15:01 +0100777 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700778 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100779 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
780 if (!pte) {
781 start_pfn = align_to_level(start_pfn + 1, 2);
782 continue;
783 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100784 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100785 dma_clear_pte(pte);
786 start_pfn++;
787 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100788 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
789
David Woodhouse310a5ab2009-06-28 18:52:20 +0100790 domain_flush_cache(domain, first_pte,
791 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700792
793 } while (start_pfn && start_pfn <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700794}
795
796/* free page table pages. last level pte should already be cleared */
797static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100798 unsigned long start_pfn,
799 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700800{
David Woodhouse6660c632009-06-27 22:41:00 +0100801 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhousef3a0a522009-06-30 03:40:07 +0100802 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700803 int total = agaw_to_level(domain->agaw);
804 int level;
David Woodhouse6660c632009-06-27 22:41:00 +0100805 unsigned long tmp;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700806
David Woodhouse6660c632009-06-27 22:41:00 +0100807 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
808 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700809 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700810
David Woodhousef3a0a522009-06-30 03:40:07 +0100811 /* We don't need lock here; nobody else touches the iova range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700812 level = 2;
813 while (level <= total) {
David Woodhouse6660c632009-06-27 22:41:00 +0100814 tmp = align_to_level(start_pfn, level);
815
David Woodhousef3a0a522009-06-30 03:40:07 +0100816 /* If we can't even clear one PTE at this level, we're done */
David Woodhouse6660c632009-06-27 22:41:00 +0100817 if (tmp + level_size(level) - 1 > last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700818 return;
819
David Woodhouse59c36282009-09-19 07:36:28 -0700820 do {
David Woodhousef3a0a522009-06-30 03:40:07 +0100821 first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
822 if (!pte) {
823 tmp = align_to_level(tmp + 1, level + 1);
824 continue;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700825 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100826 do {
David Woodhouse6a43e572009-07-02 12:02:34 +0100827 if (dma_pte_present(pte)) {
828 free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
829 dma_clear_pte(pte);
830 }
David Woodhousef3a0a522009-06-30 03:40:07 +0100831 pte++;
832 tmp += level_size(level);
David Woodhouse75e6bf92009-07-02 11:21:16 +0100833 } while (!first_pte_in_page(pte) &&
834 tmp + level_size(level) - 1 <= last_pfn);
835
David Woodhousef3a0a522009-06-30 03:40:07 +0100836 domain_flush_cache(domain, first_pte,
837 (void *)pte - (void *)first_pte);
838
David Woodhouse59c36282009-09-19 07:36:28 -0700839 } while (tmp && tmp + level_size(level) - 1 <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700840 level++;
841 }
842 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100843 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700844 free_pgtable_page(domain->pgd);
845 domain->pgd = NULL;
846 }
847}
848
849/* iommu handling */
850static int iommu_alloc_root_entry(struct intel_iommu *iommu)
851{
852 struct root_entry *root;
853 unsigned long flags;
854
Suresh Siddha4c923d42009-10-02 11:01:24 -0700855 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700856 if (!root)
857 return -ENOMEM;
858
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700859 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700860
861 spin_lock_irqsave(&iommu->lock, flags);
862 iommu->root_entry = root;
863 spin_unlock_irqrestore(&iommu->lock, flags);
864
865 return 0;
866}
867
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700868static void iommu_set_root_entry(struct intel_iommu *iommu)
869{
870 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100871 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700872 unsigned long flag;
873
874 addr = iommu->root_entry;
875
876 spin_lock_irqsave(&iommu->register_lock, flag);
877 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
878
David Woodhousec416daa2009-05-10 20:30:58 +0100879 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700880
881 /* Make sure hardware complete it */
882 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100883 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700884
885 spin_unlock_irqrestore(&iommu->register_lock, flag);
886}
887
888static void iommu_flush_write_buffer(struct intel_iommu *iommu)
889{
890 u32 val;
891 unsigned long flag;
892
David Woodhouse9af88142009-02-13 23:18:03 +0000893 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700894 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700895
896 spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100897 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700898
899 /* Make sure hardware complete it */
900 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100901 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700902
903 spin_unlock_irqrestore(&iommu->register_lock, flag);
904}
905
906/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +0100907static void __iommu_flush_context(struct intel_iommu *iommu,
908 u16 did, u16 source_id, u8 function_mask,
909 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700910{
911 u64 val = 0;
912 unsigned long flag;
913
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700914 switch (type) {
915 case DMA_CCMD_GLOBAL_INVL:
916 val = DMA_CCMD_GLOBAL_INVL;
917 break;
918 case DMA_CCMD_DOMAIN_INVL:
919 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
920 break;
921 case DMA_CCMD_DEVICE_INVL:
922 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
923 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
924 break;
925 default:
926 BUG();
927 }
928 val |= DMA_CCMD_ICC;
929
930 spin_lock_irqsave(&iommu->register_lock, flag);
931 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
932
933 /* Make sure hardware complete it */
934 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
935 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
936
937 spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700938}
939
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700940/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +0100941static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
942 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700943{
944 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
945 u64 val = 0, val_iva = 0;
946 unsigned long flag;
947
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700948 switch (type) {
949 case DMA_TLB_GLOBAL_FLUSH:
950 /* global flush doesn't need set IVA_REG */
951 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
952 break;
953 case DMA_TLB_DSI_FLUSH:
954 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
955 break;
956 case DMA_TLB_PSI_FLUSH:
957 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
958 /* Note: always flush non-leaf currently */
959 val_iva = size_order | addr;
960 break;
961 default:
962 BUG();
963 }
964 /* Note: set drain read/write */
965#if 0
966 /*
967 * This is probably to be super secure.. Looks like we can
968 * ignore it without any impact.
969 */
970 if (cap_read_drain(iommu->cap))
971 val |= DMA_TLB_READ_DRAIN;
972#endif
973 if (cap_write_drain(iommu->cap))
974 val |= DMA_TLB_WRITE_DRAIN;
975
976 spin_lock_irqsave(&iommu->register_lock, flag);
977 /* Note: Only uses first TLB reg currently */
978 if (val_iva)
979 dmar_writeq(iommu->reg + tlb_offset, val_iva);
980 dmar_writeq(iommu->reg + tlb_offset + 8, val);
981
982 /* Make sure hardware complete it */
983 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
984 dmar_readq, (!(val & DMA_TLB_IVT)), val);
985
986 spin_unlock_irqrestore(&iommu->register_lock, flag);
987
988 /* check IOTLB invalidation granularity */
989 if (DMA_TLB_IAIG(val) == 0)
990 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
991 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
992 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700993 (unsigned long long)DMA_TLB_IIRG(type),
994 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700995}
996
Yu Zhao93a23a72009-05-18 13:51:37 +0800997static struct device_domain_info *iommu_support_dev_iotlb(
998 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700999{
Yu Zhao93a23a72009-05-18 13:51:37 +08001000 int found = 0;
1001 unsigned long flags;
1002 struct device_domain_info *info;
1003 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1004
1005 if (!ecap_dev_iotlb_support(iommu->ecap))
1006 return NULL;
1007
1008 if (!iommu->qi)
1009 return NULL;
1010
1011 spin_lock_irqsave(&device_domain_lock, flags);
1012 list_for_each_entry(info, &domain->devices, link)
1013 if (info->bus == bus && info->devfn == devfn) {
1014 found = 1;
1015 break;
1016 }
1017 spin_unlock_irqrestore(&device_domain_lock, flags);
1018
1019 if (!found || !info->dev)
1020 return NULL;
1021
1022 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1023 return NULL;
1024
1025 if (!dmar_find_matched_atsr_unit(info->dev))
1026 return NULL;
1027
1028 info->iommu = iommu;
1029
1030 return info;
1031}
1032
1033static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1034{
1035 if (!info)
1036 return;
1037
1038 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1039}
1040
1041static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1042{
1043 if (!info->dev || !pci_ats_enabled(info->dev))
1044 return;
1045
1046 pci_disable_ats(info->dev);
1047}
1048
1049static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1050 u64 addr, unsigned mask)
1051{
1052 u16 sid, qdep;
1053 unsigned long flags;
1054 struct device_domain_info *info;
1055
1056 spin_lock_irqsave(&device_domain_lock, flags);
1057 list_for_each_entry(info, &domain->devices, link) {
1058 if (!info->dev || !pci_ats_enabled(info->dev))
1059 continue;
1060
1061 sid = info->bus << 8 | info->devfn;
1062 qdep = pci_ats_queue_depth(info->dev);
1063 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1064 }
1065 spin_unlock_irqrestore(&device_domain_lock, flags);
1066}
1067
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001068static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001069 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001070{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001071 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001072 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001073
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001074 BUG_ON(pages == 0);
1075
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001076 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001077 * Fallback to domain selective flush if no PSI support or the size is
1078 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001079 * PSI requires page size to be 2 ^ x, and the base address is naturally
1080 * aligned to the size
1081 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001082 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1083 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001084 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001085 else
1086 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1087 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001088
1089 /*
Nadav Amit82653632010-04-01 13:24:40 +03001090 * In caching mode, changes of pages from non-present to present require
1091 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001092 */
Nadav Amit82653632010-04-01 13:24:40 +03001093 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001094 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001095}
1096
mark grossf8bab732008-02-08 04:18:38 -08001097static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1098{
1099 u32 pmen;
1100 unsigned long flags;
1101
1102 spin_lock_irqsave(&iommu->register_lock, flags);
1103 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1104 pmen &= ~DMA_PMEN_EPM;
1105 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1106
1107 /* wait for the protected region status bit to clear */
1108 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1109 readl, !(pmen & DMA_PMEN_PRS), pmen);
1110
1111 spin_unlock_irqrestore(&iommu->register_lock, flags);
1112}
1113
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001114static int iommu_enable_translation(struct intel_iommu *iommu)
1115{
1116 u32 sts;
1117 unsigned long flags;
1118
1119 spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001120 iommu->gcmd |= DMA_GCMD_TE;
1121 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001122
1123 /* Make sure hardware complete it */
1124 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001125 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001126
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001127 spin_unlock_irqrestore(&iommu->register_lock, flags);
1128 return 0;
1129}
1130
1131static int iommu_disable_translation(struct intel_iommu *iommu)
1132{
1133 u32 sts;
1134 unsigned long flag;
1135
1136 spin_lock_irqsave(&iommu->register_lock, flag);
1137 iommu->gcmd &= ~DMA_GCMD_TE;
1138 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1139
1140 /* Make sure hardware complete it */
1141 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001142 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001143
1144 spin_unlock_irqrestore(&iommu->register_lock, flag);
1145 return 0;
1146}
1147
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001148
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001149static int iommu_init_domains(struct intel_iommu *iommu)
1150{
1151 unsigned long ndomains;
1152 unsigned long nlongs;
1153
1154 ndomains = cap_ndoms(iommu->cap);
Yinghai Lu680a7522010-04-08 19:58:23 +01001155 pr_debug("IOMMU %d: Number of Domains supportd <%ld>\n", iommu->seq_id,
1156 ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001157 nlongs = BITS_TO_LONGS(ndomains);
1158
Donald Dutile94a91b502009-08-20 16:51:34 -04001159 spin_lock_init(&iommu->lock);
1160
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001161 /* TBD: there might be 64K domains,
1162 * consider other allocation for future chip
1163 */
1164 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1165 if (!iommu->domain_ids) {
1166 printk(KERN_ERR "Allocating domain id array failed\n");
1167 return -ENOMEM;
1168 }
1169 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1170 GFP_KERNEL);
1171 if (!iommu->domains) {
1172 printk(KERN_ERR "Allocating domain array failed\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001173 return -ENOMEM;
1174 }
1175
1176 /*
1177 * if Caching mode is set, then invalid translations are tagged
1178 * with domainid 0. Hence we need to pre-allocate it.
1179 */
1180 if (cap_caching_mode(iommu->cap))
1181 set_bit(0, iommu->domain_ids);
1182 return 0;
1183}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001184
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001185
1186static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001187static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001188
1189void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001190{
1191 struct dmar_domain *domain;
1192 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001193 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001194
Donald Dutile94a91b502009-08-20 16:51:34 -04001195 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001196 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b502009-08-20 16:51:34 -04001197 domain = iommu->domains[i];
1198 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001199
Donald Dutile94a91b502009-08-20 16:51:34 -04001200 spin_lock_irqsave(&domain->iommu_lock, flags);
1201 if (--domain->iommu_count == 0) {
1202 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1203 vm_domain_exit(domain);
1204 else
1205 domain_exit(domain);
1206 }
1207 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001208 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001209 }
1210
1211 if (iommu->gcmd & DMA_GCMD_TE)
1212 iommu_disable_translation(iommu);
1213
1214 if (iommu->irq) {
Thomas Gleixnerdced35a2011-03-28 17:49:12 +02001215 irq_set_handler_data(iommu->irq, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001216 /* This will mask the irq */
1217 free_irq(iommu->irq, iommu);
1218 destroy_irq(iommu->irq);
1219 }
1220
1221 kfree(iommu->domains);
1222 kfree(iommu->domain_ids);
1223
Weidong Hand9630fe2008-12-08 11:06:32 +08001224 g_iommus[iommu->seq_id] = NULL;
1225
1226 /* if all iommus are freed, free g_iommus */
1227 for (i = 0; i < g_num_of_iommus; i++) {
1228 if (g_iommus[i])
1229 break;
1230 }
1231
1232 if (i == g_num_of_iommus)
1233 kfree(g_iommus);
1234
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001235 /* free context mapping */
1236 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001237}
1238
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001239static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001240{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001241 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001242
1243 domain = alloc_domain_mem();
1244 if (!domain)
1245 return NULL;
1246
Suresh Siddha4c923d42009-10-02 11:01:24 -07001247 domain->nid = -1;
Weidong Han8c11e792008-12-08 15:29:22 +08001248 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
Weidong Hand71a2f32008-12-07 21:13:41 +08001249 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001250
1251 return domain;
1252}
1253
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001254static int iommu_attach_domain(struct dmar_domain *domain,
1255 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001256{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001257 int num;
1258 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001259 unsigned long flags;
1260
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001261 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001262
1263 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001264
1265 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1266 if (num >= ndomains) {
1267 spin_unlock_irqrestore(&iommu->lock, flags);
1268 printk(KERN_ERR "IOMMU: no free domain ids\n");
1269 return -ENOMEM;
1270 }
1271
1272 domain->id = num;
1273 set_bit(num, iommu->domain_ids);
1274 set_bit(iommu->seq_id, &domain->iommu_bmp);
1275 iommu->domains[num] = domain;
1276 spin_unlock_irqrestore(&iommu->lock, flags);
1277
1278 return 0;
1279}
1280
1281static void iommu_detach_domain(struct dmar_domain *domain,
1282 struct intel_iommu *iommu)
1283{
1284 unsigned long flags;
1285 int num, ndomains;
1286 int found = 0;
1287
1288 spin_lock_irqsave(&iommu->lock, flags);
1289 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001290 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001291 if (iommu->domains[num] == domain) {
1292 found = 1;
1293 break;
1294 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001295 }
1296
1297 if (found) {
1298 clear_bit(num, iommu->domain_ids);
1299 clear_bit(iommu->seq_id, &domain->iommu_bmp);
1300 iommu->domains[num] = NULL;
1301 }
Weidong Han8c11e792008-12-08 15:29:22 +08001302 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001303}
1304
1305static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001306static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001307
Joseph Cihula51a63e62011-03-21 11:04:24 -07001308static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001309{
1310 struct pci_dev *pdev = NULL;
1311 struct iova *iova;
1312 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001313
David Millerf6611972008-02-06 01:36:23 -08001314 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001315
Mark Gross8a443df2008-03-04 14:59:31 -08001316 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1317 &reserved_rbtree_key);
1318
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001319 /* IOAPIC ranges shouldn't be accessed by DMA */
1320 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1321 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001322 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001323 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001324 return -ENODEV;
1325 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001326
1327 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1328 for_each_pci_dev(pdev) {
1329 struct resource *r;
1330
1331 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1332 r = &pdev->resource[i];
1333 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1334 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001335 iova = reserve_iova(&reserved_iova_list,
1336 IOVA_PFN(r->start),
1337 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001338 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001339 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001340 return -ENODEV;
1341 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001342 }
1343 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001344 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001345}
1346
1347static void domain_reserve_special_ranges(struct dmar_domain *domain)
1348{
1349 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1350}
1351
1352static inline int guestwidth_to_adjustwidth(int gaw)
1353{
1354 int agaw;
1355 int r = (gaw - 12) % 9;
1356
1357 if (r == 0)
1358 agaw = gaw;
1359 else
1360 agaw = gaw + 9 - r;
1361 if (agaw > 64)
1362 agaw = 64;
1363 return agaw;
1364}
1365
1366static int domain_init(struct dmar_domain *domain, int guest_width)
1367{
1368 struct intel_iommu *iommu;
1369 int adjust_width, agaw;
1370 unsigned long sagaw;
1371
David Millerf6611972008-02-06 01:36:23 -08001372 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001373 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001374
1375 domain_reserve_special_ranges(domain);
1376
1377 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001378 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001379 if (guest_width > cap_mgaw(iommu->cap))
1380 guest_width = cap_mgaw(iommu->cap);
1381 domain->gaw = guest_width;
1382 adjust_width = guestwidth_to_adjustwidth(guest_width);
1383 agaw = width_to_agaw(adjust_width);
1384 sagaw = cap_sagaw(iommu->cap);
1385 if (!test_bit(agaw, &sagaw)) {
1386 /* hardware doesn't support it, choose a bigger one */
1387 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1388 agaw = find_next_bit(&sagaw, 5, agaw);
1389 if (agaw >= 5)
1390 return -ENODEV;
1391 }
1392 domain->agaw = agaw;
1393 INIT_LIST_HEAD(&domain->devices);
1394
Weidong Han8e6040972008-12-08 15:49:06 +08001395 if (ecap_coherent(iommu->ecap))
1396 domain->iommu_coherency = 1;
1397 else
1398 domain->iommu_coherency = 0;
1399
Sheng Yang58c610b2009-03-18 15:33:05 +08001400 if (ecap_sc_support(iommu->ecap))
1401 domain->iommu_snooping = 1;
1402 else
1403 domain->iommu_snooping = 0;
1404
Weidong Hanc7151a82008-12-08 22:51:37 +08001405 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001406 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001407
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001408 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001409 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001410 if (!domain->pgd)
1411 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001412 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001413 return 0;
1414}
1415
1416static void domain_exit(struct dmar_domain *domain)
1417{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001418 struct dmar_drhd_unit *drhd;
1419 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001420
1421 /* Domain 0 is reserved, so dont process it */
1422 if (!domain)
1423 return;
1424
Alex Williamson7b668352011-05-24 12:02:41 +01001425 /* Flush any lazy unmaps that may reference this domain */
1426 if (!intel_iommu_strict)
1427 flush_unmaps_timeout(0);
1428
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001429 domain_remove_dev_info(domain);
1430 /* destroy iovas */
1431 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001432
1433 /* clear ptes */
David Woodhouse595badf52009-06-27 22:09:11 +01001434 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001435
1436 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001437 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001438
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001439 for_each_active_iommu(iommu, drhd)
1440 if (test_bit(iommu->seq_id, &domain->iommu_bmp))
1441 iommu_detach_domain(domain, iommu);
1442
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001443 free_domain_mem(domain);
1444}
1445
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001446static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1447 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001448{
1449 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001450 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001451 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001452 struct dma_pte *pgd;
1453 unsigned long num;
1454 unsigned long ndomains;
1455 int id;
1456 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001457 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001458
1459 pr_debug("Set context mapping for %02x:%02x.%d\n",
1460 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001461
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001462 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001463 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1464 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001465
David Woodhouse276dbf992009-04-04 01:45:37 +01001466 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001467 if (!iommu)
1468 return -ENODEV;
1469
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001470 context = device_to_context_entry(iommu, bus, devfn);
1471 if (!context)
1472 return -ENOMEM;
1473 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001474 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001475 spin_unlock_irqrestore(&iommu->lock, flags);
1476 return 0;
1477 }
1478
Weidong Hanea6606b2008-12-08 23:08:15 +08001479 id = domain->id;
1480 pgd = domain->pgd;
1481
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001482 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1483 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001484 int found = 0;
1485
1486 /* find an available domain id for this device in iommu */
1487 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001488 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001489 if (iommu->domains[num] == domain) {
1490 id = num;
1491 found = 1;
1492 break;
1493 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001494 }
1495
1496 if (found == 0) {
1497 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1498 if (num >= ndomains) {
1499 spin_unlock_irqrestore(&iommu->lock, flags);
1500 printk(KERN_ERR "IOMMU: no free domain ids\n");
1501 return -EFAULT;
1502 }
1503
1504 set_bit(num, iommu->domain_ids);
1505 iommu->domains[num] = domain;
1506 id = num;
1507 }
1508
1509 /* Skip top levels of page tables for
1510 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001511 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001512 */
Chris Wright1672af12009-12-02 12:06:34 -08001513 if (translation != CONTEXT_TT_PASS_THROUGH) {
1514 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1515 pgd = phys_to_virt(dma_pte_addr(pgd));
1516 if (!dma_pte_present(pgd)) {
1517 spin_unlock_irqrestore(&iommu->lock, flags);
1518 return -ENOMEM;
1519 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001520 }
1521 }
1522 }
1523
1524 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001525
Yu Zhao93a23a72009-05-18 13:51:37 +08001526 if (translation != CONTEXT_TT_PASS_THROUGH) {
1527 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1528 translation = info ? CONTEXT_TT_DEV_IOTLB :
1529 CONTEXT_TT_MULTI_LEVEL;
1530 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001531 /*
1532 * In pass through mode, AW must be programmed to indicate the largest
1533 * AGAW value supported by hardware. And ASR is ignored by hardware.
1534 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001535 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001536 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001537 else {
1538 context_set_address_root(context, virt_to_phys(pgd));
1539 context_set_address_width(context, iommu->agaw);
1540 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001541
1542 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001543 context_set_fault_enable(context);
1544 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001545 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001546
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001547 /*
1548 * It's a non-present to present mapping. If hardware doesn't cache
1549 * non-present entry we only need to flush the write-buffer. If the
1550 * _does_ cache non-present entries, then it does so in the special
1551 * domain #0, which we have to flush:
1552 */
1553 if (cap_caching_mode(iommu->cap)) {
1554 iommu->flush.flush_context(iommu, 0,
1555 (((u16)bus) << 8) | devfn,
1556 DMA_CCMD_MASK_NOBIT,
1557 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001558 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001559 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001560 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001561 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001562 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001563 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001564
1565 spin_lock_irqsave(&domain->iommu_lock, flags);
1566 if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
1567 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001568 if (domain->iommu_count == 1)
1569 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001570 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001571 }
1572 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001573 return 0;
1574}
1575
1576static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001577domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1578 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001579{
1580 int ret;
1581 struct pci_dev *tmp, *parent;
1582
David Woodhouse276dbf992009-04-04 01:45:37 +01001583 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001584 pdev->bus->number, pdev->devfn,
1585 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001586 if (ret)
1587 return ret;
1588
1589 /* dependent device mapping */
1590 tmp = pci_find_upstream_pcie_bridge(pdev);
1591 if (!tmp)
1592 return 0;
1593 /* Secondary interface's bus number and devfn 0 */
1594 parent = pdev->bus->self;
1595 while (parent != tmp) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001596 ret = domain_context_mapping_one(domain,
1597 pci_domain_nr(parent->bus),
1598 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001599 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001600 if (ret)
1601 return ret;
1602 parent = parent->bus->self;
1603 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001604 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001605 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001606 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001607 tmp->subordinate->number, 0,
1608 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001609 else /* this is a legacy PCI bridge */
1610 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001611 pci_domain_nr(tmp->bus),
1612 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001613 tmp->devfn,
1614 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001615}
1616
Weidong Han5331fe62008-12-08 23:00:00 +08001617static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001618{
1619 int ret;
1620 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001621 struct intel_iommu *iommu;
1622
David Woodhouse276dbf992009-04-04 01:45:37 +01001623 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1624 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001625 if (!iommu)
1626 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001627
David Woodhouse276dbf992009-04-04 01:45:37 +01001628 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001629 if (!ret)
1630 return ret;
1631 /* dependent device mapping */
1632 tmp = pci_find_upstream_pcie_bridge(pdev);
1633 if (!tmp)
1634 return ret;
1635 /* Secondary interface's bus number and devfn 0 */
1636 parent = pdev->bus->self;
1637 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001638 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001639 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001640 if (!ret)
1641 return ret;
1642 parent = parent->bus->self;
1643 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001644 if (pci_is_pcie(tmp))
David Woodhouse276dbf992009-04-04 01:45:37 +01001645 return device_context_mapped(iommu, tmp->subordinate->number,
1646 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001647 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001648 return device_context_mapped(iommu, tmp->bus->number,
1649 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001650}
1651
Fenghua Yuf5329592009-08-04 15:09:37 -07001652/* Returns a number of VTD pages, but aligned to MM page size */
1653static inline unsigned long aligned_nrpages(unsigned long host_addr,
1654 size_t size)
1655{
1656 host_addr &= ~PAGE_MASK;
1657 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1658}
1659
David Woodhouse9051aa02009-06-29 12:30:54 +01001660static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1661 struct scatterlist *sg, unsigned long phys_pfn,
1662 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001663{
1664 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001665 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001666 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001667 unsigned long sg_res;
David Woodhousee1605492009-06-29 11:17:38 +01001668
1669 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1670
1671 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1672 return -EINVAL;
1673
1674 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1675
David Woodhouse9051aa02009-06-29 12:30:54 +01001676 if (sg)
1677 sg_res = 0;
1678 else {
1679 sg_res = nr_pages + 1;
1680 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1681 }
1682
David Woodhousee1605492009-06-29 11:17:38 +01001683 while (nr_pages--) {
David Woodhousec85994e2009-07-01 19:21:24 +01001684 uint64_t tmp;
1685
David Woodhousee1605492009-06-29 11:17:38 +01001686 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001687 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001688 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1689 sg->dma_length = sg->length;
1690 pteval = page_to_phys(sg_page(sg)) | prot;
1691 }
1692 if (!pte) {
1693 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
1694 if (!pte)
1695 return -ENOMEM;
1696 }
1697 /* We don't need lock here, nobody else
1698 * touches the iova range
1699 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001700 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001701 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001702 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001703 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1704 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001705 if (dumps) {
1706 dumps--;
1707 debug_dma_dump_mappings(NULL);
1708 }
1709 WARN_ON(1);
1710 }
David Woodhousee1605492009-06-29 11:17:38 +01001711 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +01001712 if (!nr_pages || first_pte_in_page(pte)) {
David Woodhousee1605492009-06-29 11:17:38 +01001713 domain_flush_cache(domain, first_pte,
1714 (void *)pte - (void *)first_pte);
1715 pte = NULL;
1716 }
1717 iov_pfn++;
1718 pteval += VTD_PAGE_SIZE;
1719 sg_res--;
1720 if (!sg_res)
1721 sg = sg_next(sg);
1722 }
1723 return 0;
1724}
1725
David Woodhouse9051aa02009-06-29 12:30:54 +01001726static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1727 struct scatterlist *sg, unsigned long nr_pages,
1728 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001729{
David Woodhouse9051aa02009-06-29 12:30:54 +01001730 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1731}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001732
David Woodhouse9051aa02009-06-29 12:30:54 +01001733static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1734 unsigned long phys_pfn, unsigned long nr_pages,
1735 int prot)
1736{
1737 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001738}
1739
Weidong Hanc7151a82008-12-08 22:51:37 +08001740static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001741{
Weidong Hanc7151a82008-12-08 22:51:37 +08001742 if (!iommu)
1743 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001744
1745 clear_context_table(iommu, bus, devfn);
1746 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001747 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001748 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001749}
1750
1751static void domain_remove_dev_info(struct dmar_domain *domain)
1752{
1753 struct device_domain_info *info;
1754 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001755 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001756
1757 spin_lock_irqsave(&device_domain_lock, flags);
1758 while (!list_empty(&domain->devices)) {
1759 info = list_entry(domain->devices.next,
1760 struct device_domain_info, link);
1761 list_del(&info->link);
1762 list_del(&info->global);
1763 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001764 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001765 spin_unlock_irqrestore(&device_domain_lock, flags);
1766
Yu Zhao93a23a72009-05-18 13:51:37 +08001767 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01001768 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001769 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001770 free_devinfo_mem(info);
1771
1772 spin_lock_irqsave(&device_domain_lock, flags);
1773 }
1774 spin_unlock_irqrestore(&device_domain_lock, flags);
1775}
1776
1777/*
1778 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001779 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001780 */
Kay, Allen M38717942008-09-09 18:37:29 +03001781static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001782find_domain(struct pci_dev *pdev)
1783{
1784 struct device_domain_info *info;
1785
1786 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001787 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001788 if (info)
1789 return info->domain;
1790 return NULL;
1791}
1792
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001793/* domain is initialized */
1794static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1795{
1796 struct dmar_domain *domain, *found = NULL;
1797 struct intel_iommu *iommu;
1798 struct dmar_drhd_unit *drhd;
1799 struct device_domain_info *info, *tmp;
1800 struct pci_dev *dev_tmp;
1801 unsigned long flags;
1802 int bus = 0, devfn = 0;
David Woodhouse276dbf992009-04-04 01:45:37 +01001803 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001804 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001805
1806 domain = find_domain(pdev);
1807 if (domain)
1808 return domain;
1809
David Woodhouse276dbf992009-04-04 01:45:37 +01001810 segment = pci_domain_nr(pdev->bus);
1811
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001812 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1813 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001814 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001815 bus = dev_tmp->subordinate->number;
1816 devfn = 0;
1817 } else {
1818 bus = dev_tmp->bus->number;
1819 devfn = dev_tmp->devfn;
1820 }
1821 spin_lock_irqsave(&device_domain_lock, flags);
1822 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001823 if (info->segment == segment &&
1824 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001825 found = info->domain;
1826 break;
1827 }
1828 }
1829 spin_unlock_irqrestore(&device_domain_lock, flags);
1830 /* pcie-pci bridge already has a domain, uses it */
1831 if (found) {
1832 domain = found;
1833 goto found_domain;
1834 }
1835 }
1836
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001837 domain = alloc_domain();
1838 if (!domain)
1839 goto error;
1840
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001841 /* Allocate new domain for the device */
1842 drhd = dmar_find_matched_drhd_unit(pdev);
1843 if (!drhd) {
1844 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
1845 pci_name(pdev));
1846 return NULL;
1847 }
1848 iommu = drhd->iommu;
1849
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001850 ret = iommu_attach_domain(domain, iommu);
1851 if (ret) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07001852 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001853 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001854 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001855
1856 if (domain_init(domain, gaw)) {
1857 domain_exit(domain);
1858 goto error;
1859 }
1860
1861 /* register pcie-to-pci device */
1862 if (dev_tmp) {
1863 info = alloc_devinfo_mem();
1864 if (!info) {
1865 domain_exit(domain);
1866 goto error;
1867 }
David Woodhouse276dbf992009-04-04 01:45:37 +01001868 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001869 info->bus = bus;
1870 info->devfn = devfn;
1871 info->dev = NULL;
1872 info->domain = domain;
1873 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08001874 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001875
1876 /* pcie-to-pci bridge already has a domain, uses it */
1877 found = NULL;
1878 spin_lock_irqsave(&device_domain_lock, flags);
1879 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001880 if (tmp->segment == segment &&
1881 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001882 found = tmp->domain;
1883 break;
1884 }
1885 }
1886 if (found) {
Jiri Slaby00dfff72010-06-14 17:17:32 +02001887 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001888 free_devinfo_mem(info);
1889 domain_exit(domain);
1890 domain = found;
1891 } else {
1892 list_add(&info->link, &domain->devices);
1893 list_add(&info->global, &device_domain_list);
Jiri Slaby00dfff72010-06-14 17:17:32 +02001894 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001895 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001896 }
1897
1898found_domain:
1899 info = alloc_devinfo_mem();
1900 if (!info)
1901 goto error;
David Woodhouse276dbf992009-04-04 01:45:37 +01001902 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001903 info->bus = pdev->bus->number;
1904 info->devfn = pdev->devfn;
1905 info->dev = pdev;
1906 info->domain = domain;
1907 spin_lock_irqsave(&device_domain_lock, flags);
1908 /* somebody is fast */
1909 found = find_domain(pdev);
1910 if (found != NULL) {
1911 spin_unlock_irqrestore(&device_domain_lock, flags);
1912 if (found != domain) {
1913 domain_exit(domain);
1914 domain = found;
1915 }
1916 free_devinfo_mem(info);
1917 return domain;
1918 }
1919 list_add(&info->link, &domain->devices);
1920 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001921 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001922 spin_unlock_irqrestore(&device_domain_lock, flags);
1923 return domain;
1924error:
1925 /* recheck it here, maybe others set it */
1926 return find_domain(pdev);
1927}
1928
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001929static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07001930#define IDENTMAP_ALL 1
1931#define IDENTMAP_GFX 2
1932#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001933
David Woodhouseb2132032009-06-26 18:50:28 +01001934static int iommu_domain_identity_map(struct dmar_domain *domain,
1935 unsigned long long start,
1936 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001937{
David Woodhousec5395d52009-06-28 16:35:56 +01001938 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
1939 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001940
David Woodhousec5395d52009-06-28 16:35:56 +01001941 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
1942 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001943 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01001944 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001945 }
1946
David Woodhousec5395d52009-06-28 16:35:56 +01001947 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
1948 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001949 /*
1950 * RMRR range might have overlap with physical memory range,
1951 * clear it first
1952 */
David Woodhousec5395d52009-06-28 16:35:56 +01001953 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001954
David Woodhousec5395d52009-06-28 16:35:56 +01001955 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
1956 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01001957 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01001958}
1959
1960static int iommu_prepare_identity_map(struct pci_dev *pdev,
1961 unsigned long long start,
1962 unsigned long long end)
1963{
1964 struct dmar_domain *domain;
1965 int ret;
1966
David Woodhousec7ab48d2009-06-26 19:10:36 +01001967 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01001968 if (!domain)
1969 return -ENOMEM;
1970
David Woodhouse19943b02009-08-04 16:19:20 +01001971 /* For _hardware_ passthrough, don't bother. But for software
1972 passthrough, we do it anyway -- it may indicate a memory
1973 range which is reserved in E820, so which didn't get set
1974 up to start with in si_domain */
1975 if (domain == si_domain && hw_pass_through) {
1976 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
1977 pci_name(pdev), start, end);
1978 return 0;
1979 }
1980
1981 printk(KERN_INFO
1982 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
1983 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01001984
David Woodhouse5595b522009-12-02 09:21:55 +00001985 if (end < start) {
1986 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
1987 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
1988 dmi_get_system_info(DMI_BIOS_VENDOR),
1989 dmi_get_system_info(DMI_BIOS_VERSION),
1990 dmi_get_system_info(DMI_PRODUCT_VERSION));
1991 ret = -EIO;
1992 goto error;
1993 }
1994
David Woodhouse2ff729f2009-08-26 14:25:41 +01001995 if (end >> agaw_to_width(domain->agaw)) {
1996 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
1997 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
1998 agaw_to_width(domain->agaw),
1999 dmi_get_system_info(DMI_BIOS_VENDOR),
2000 dmi_get_system_info(DMI_BIOS_VERSION),
2001 dmi_get_system_info(DMI_PRODUCT_VERSION));
2002 ret = -EIO;
2003 goto error;
2004 }
David Woodhouse19943b02009-08-04 16:19:20 +01002005
David Woodhouseb2132032009-06-26 18:50:28 +01002006 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002007 if (ret)
2008 goto error;
2009
2010 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002011 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002012 if (ret)
2013 goto error;
2014
2015 return 0;
2016
2017 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002018 domain_exit(domain);
2019 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002020}
2021
2022static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2023 struct pci_dev *pdev)
2024{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002025 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002026 return 0;
2027 return iommu_prepare_identity_map(pdev, rmrr->base_address,
2028 rmrr->end_address + 1);
2029}
2030
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002031#ifdef CONFIG_DMAR_FLOPPY_WA
2032static inline void iommu_prepare_isa(void)
2033{
2034 struct pci_dev *pdev;
2035 int ret;
2036
2037 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2038 if (!pdev)
2039 return;
2040
David Woodhousec7ab48d2009-06-26 19:10:36 +01002041 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002042 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
2043
2044 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002045 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2046 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002047
2048}
2049#else
2050static inline void iommu_prepare_isa(void)
2051{
2052 return;
2053}
2054#endif /* !CONFIG_DMAR_FLPY_WA */
2055
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002056static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002057
2058static int __init si_domain_work_fn(unsigned long start_pfn,
2059 unsigned long end_pfn, void *datax)
2060{
2061 int *ret = datax;
2062
2063 *ret = iommu_domain_identity_map(si_domain,
2064 (uint64_t)start_pfn << PAGE_SHIFT,
2065 (uint64_t)end_pfn << PAGE_SHIFT);
2066 return *ret;
2067
2068}
2069
Matt Kraai071e1372009-08-23 22:30:22 -07002070static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002071{
2072 struct dmar_drhd_unit *drhd;
2073 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002074 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002075
2076 si_domain = alloc_domain();
2077 if (!si_domain)
2078 return -EFAULT;
2079
David Woodhousec7ab48d2009-06-26 19:10:36 +01002080 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002081
2082 for_each_active_iommu(iommu, drhd) {
2083 ret = iommu_attach_domain(si_domain, iommu);
2084 if (ret) {
2085 domain_exit(si_domain);
2086 return -EFAULT;
2087 }
2088 }
2089
2090 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2091 domain_exit(si_domain);
2092 return -EFAULT;
2093 }
2094
2095 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2096
David Woodhouse19943b02009-08-04 16:19:20 +01002097 if (hw)
2098 return 0;
2099
David Woodhousec7ab48d2009-06-26 19:10:36 +01002100 for_each_online_node(nid) {
2101 work_with_active_regions(nid, si_domain_work_fn, &ret);
2102 if (ret)
2103 return ret;
2104 }
2105
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002106 return 0;
2107}
2108
2109static void domain_remove_one_dev_info(struct dmar_domain *domain,
2110 struct pci_dev *pdev);
2111static int identity_mapping(struct pci_dev *pdev)
2112{
2113 struct device_domain_info *info;
2114
2115 if (likely(!iommu_identity_mapping))
2116 return 0;
2117
2118
2119 list_for_each_entry(info, &si_domain->devices, link)
2120 if (info->dev == pdev)
2121 return 1;
2122 return 0;
2123}
2124
2125static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002126 struct pci_dev *pdev,
2127 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002128{
2129 struct device_domain_info *info;
2130 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002131 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002132
2133 info = alloc_devinfo_mem();
2134 if (!info)
2135 return -ENOMEM;
2136
David Woodhouse5fe60f42009-08-09 10:53:41 +01002137 ret = domain_context_mapping(domain, pdev, translation);
2138 if (ret) {
2139 free_devinfo_mem(info);
2140 return ret;
2141 }
2142
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002143 info->segment = pci_domain_nr(pdev->bus);
2144 info->bus = pdev->bus->number;
2145 info->devfn = pdev->devfn;
2146 info->dev = pdev;
2147 info->domain = domain;
2148
2149 spin_lock_irqsave(&device_domain_lock, flags);
2150 list_add(&info->link, &domain->devices);
2151 list_add(&info->global, &device_domain_list);
2152 pdev->dev.archdata.iommu = info;
2153 spin_unlock_irqrestore(&device_domain_lock, flags);
2154
2155 return 0;
2156}
2157
David Woodhouse6941af22009-07-04 18:24:27 +01002158static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2159{
David Woodhousee0fc7e02009-09-30 09:12:17 -07002160 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2161 return 1;
2162
2163 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2164 return 1;
2165
2166 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2167 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002168
David Woodhouse3dfc8132009-07-04 19:11:08 +01002169 /*
2170 * We want to start off with all devices in the 1:1 domain, and
2171 * take them out later if we find they can't access all of memory.
2172 *
2173 * However, we can't do this for PCI devices behind bridges,
2174 * because all PCI devices behind the same bridge will end up
2175 * with the same source-id on their transactions.
2176 *
2177 * Practically speaking, we can't change things around for these
2178 * devices at run-time, because we can't be sure there'll be no
2179 * DMA transactions in flight for any of their siblings.
2180 *
2181 * So PCI devices (unless they're on the root bus) as well as
2182 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2183 * the 1:1 domain, just in _case_ one of their siblings turns out
2184 * not to be able to map all of memory.
2185 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002186 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002187 if (!pci_is_root_bus(pdev->bus))
2188 return 0;
2189 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2190 return 0;
2191 } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
2192 return 0;
2193
2194 /*
2195 * At boot time, we don't yet know if devices will be 64-bit capable.
2196 * Assume that they will -- if they turn out not to be, then we can
2197 * take them out of the 1:1 domain later.
2198 */
David Woodhouse6941af22009-07-04 18:24:27 +01002199 if (!startup)
2200 return pdev->dma_mask > DMA_BIT_MASK(32);
2201
2202 return 1;
2203}
2204
Matt Kraai071e1372009-08-23 22:30:22 -07002205static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002206{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002207 struct pci_dev *pdev = NULL;
2208 int ret;
2209
David Woodhouse19943b02009-08-04 16:19:20 +01002210 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002211 if (ret)
2212 return -EFAULT;
2213
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002214 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002215 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse19943b02009-08-04 16:19:20 +01002216 printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
2217 hw ? "hardware" : "software", pci_name(pdev));
David Woodhousec7ab48d2009-06-26 19:10:36 +01002218
David Woodhouse5fe60f42009-08-09 10:53:41 +01002219 ret = domain_add_dev_info(si_domain, pdev,
David Woodhouse19943b02009-08-04 16:19:20 +01002220 hw ? CONTEXT_TT_PASS_THROUGH :
David Woodhouse62edf5d2009-07-04 10:59:46 +01002221 CONTEXT_TT_MULTI_LEVEL);
2222 if (ret)
2223 return ret;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002224 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002225 }
2226
2227 return 0;
2228}
2229
Joseph Cihulab7792602011-05-03 00:08:37 -07002230static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002231{
2232 struct dmar_drhd_unit *drhd;
2233 struct dmar_rmrr_unit *rmrr;
2234 struct pci_dev *pdev;
2235 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002236 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002237
2238 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002239 * for each drhd
2240 * allocate root
2241 * initialize and program root entry to not present
2242 * endfor
2243 */
2244 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002245 g_num_of_iommus++;
2246 /*
2247 * lock not needed as this is only incremented in the single
2248 * threaded kernel __init code path all other access are read
2249 * only
2250 */
2251 }
2252
Weidong Hand9630fe2008-12-08 11:06:32 +08002253 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2254 GFP_KERNEL);
2255 if (!g_iommus) {
2256 printk(KERN_ERR "Allocating global iommu array failed\n");
2257 ret = -ENOMEM;
2258 goto error;
2259 }
2260
mark gross80b20dd2008-04-18 13:53:58 -07002261 deferred_flush = kzalloc(g_num_of_iommus *
2262 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2263 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002264 ret = -ENOMEM;
2265 goto error;
2266 }
2267
mark gross5e0d2a62008-03-04 15:22:08 -08002268 for_each_drhd_unit(drhd) {
2269 if (drhd->ignored)
2270 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002271
2272 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002273 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002274
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002275 ret = iommu_init_domains(iommu);
2276 if (ret)
2277 goto error;
2278
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002279 /*
2280 * TBD:
2281 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002282 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002283 */
2284 ret = iommu_alloc_root_entry(iommu);
2285 if (ret) {
2286 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2287 goto error;
2288 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002289 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002290 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002291 }
2292
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002293 /*
2294 * Start from the sane iommu hardware state.
2295 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002296 for_each_drhd_unit(drhd) {
2297 if (drhd->ignored)
2298 continue;
2299
2300 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002301
2302 /*
2303 * If the queued invalidation is already initialized by us
2304 * (for example, while enabling interrupt-remapping) then
2305 * we got the things already rolling from a sane state.
2306 */
2307 if (iommu->qi)
2308 continue;
2309
2310 /*
2311 * Clear any previous faults.
2312 */
2313 dmar_fault(-1, iommu);
2314 /*
2315 * Disable queued invalidation if supported and already enabled
2316 * before OS handover.
2317 */
2318 dmar_disable_qi(iommu);
2319 }
2320
2321 for_each_drhd_unit(drhd) {
2322 if (drhd->ignored)
2323 continue;
2324
2325 iommu = drhd->iommu;
2326
Youquan Songa77b67d2008-10-16 16:31:56 -07002327 if (dmar_enable_qi(iommu)) {
2328 /*
2329 * Queued Invalidate not enabled, use Register Based
2330 * Invalidate
2331 */
2332 iommu->flush.flush_context = __iommu_flush_context;
2333 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002334 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002335 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002336 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002337 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002338 } else {
2339 iommu->flush.flush_context = qi_flush_context;
2340 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002341 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002342 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002343 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002344 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002345 }
2346 }
2347
David Woodhouse19943b02009-08-04 16:19:20 +01002348 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002349 iommu_identity_mapping |= IDENTMAP_ALL;
2350
David Woodhouse19943b02009-08-04 16:19:20 +01002351#ifdef CONFIG_DMAR_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002352 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002353#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002354
2355 check_tylersburg_isoch();
2356
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002357 /*
2358 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002359 * identity mappings for rmrr, gfx, and isa and may fall back to static
2360 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002361 */
David Woodhouse19943b02009-08-04 16:19:20 +01002362 if (iommu_identity_mapping) {
2363 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2364 if (ret) {
2365 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2366 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002367 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002368 }
David Woodhouse19943b02009-08-04 16:19:20 +01002369 /*
2370 * For each rmrr
2371 * for each dev attached to rmrr
2372 * do
2373 * locate drhd for dev, alloc domain for dev
2374 * allocate free domain
2375 * allocate page table entries for rmrr
2376 * if context not allocated for bus
2377 * allocate and init context
2378 * set present in root table for this bus
2379 * init context with domain, translation etc
2380 * endfor
2381 * endfor
2382 */
2383 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2384 for_each_rmrr_units(rmrr) {
2385 for (i = 0; i < rmrr->devices_cnt; i++) {
2386 pdev = rmrr->devices[i];
2387 /*
2388 * some BIOS lists non-exist devices in DMAR
2389 * table.
2390 */
2391 if (!pdev)
2392 continue;
2393 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2394 if (ret)
2395 printk(KERN_ERR
2396 "IOMMU: mapping reserved region failed\n");
2397 }
2398 }
2399
2400 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002401
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002402 /*
2403 * for each drhd
2404 * enable fault log
2405 * global invalidate context cache
2406 * global invalidate iotlb
2407 * enable translation
2408 */
2409 for_each_drhd_unit(drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002410 if (drhd->ignored) {
2411 /*
2412 * we always have to disable PMRs or DMA may fail on
2413 * this device
2414 */
2415 if (force_on)
2416 iommu_disable_protect_mem_regions(drhd->iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002417 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002418 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002419 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002420
2421 iommu_flush_write_buffer(iommu);
2422
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002423 ret = dmar_set_interrupt(iommu);
2424 if (ret)
2425 goto error;
2426
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002427 iommu_set_root_entry(iommu);
2428
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002429 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002430 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002431
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002432 ret = iommu_enable_translation(iommu);
2433 if (ret)
2434 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002435
2436 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002437 }
2438
2439 return 0;
2440error:
2441 for_each_drhd_unit(drhd) {
2442 if (drhd->ignored)
2443 continue;
2444 iommu = drhd->iommu;
2445 free_iommu(iommu);
2446 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002447 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002448 return ret;
2449}
2450
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002451/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002452static struct iova *intel_alloc_iova(struct device *dev,
2453 struct dmar_domain *domain,
2454 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002455{
2456 struct pci_dev *pdev = to_pci_dev(dev);
2457 struct iova *iova = NULL;
2458
David Woodhouse875764d2009-06-28 21:20:51 +01002459 /* Restrict dma_mask to the width that the iommu can handle */
2460 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2461
2462 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002463 /*
2464 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002465 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002466 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002467 */
David Woodhouse875764d2009-06-28 21:20:51 +01002468 iova = alloc_iova(&domain->iovad, nrpages,
2469 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2470 if (iova)
2471 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002472 }
David Woodhouse875764d2009-06-28 21:20:51 +01002473 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2474 if (unlikely(!iova)) {
2475 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2476 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002477 return NULL;
2478 }
2479
2480 return iova;
2481}
2482
David Woodhouse147202a2009-07-07 19:43:20 +01002483static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002484{
2485 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002486 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002487
2488 domain = get_domain_for_dev(pdev,
2489 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2490 if (!domain) {
2491 printk(KERN_ERR
2492 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002493 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002494 }
2495
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002496 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002497 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002498 ret = domain_context_mapping(domain, pdev,
2499 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002500 if (ret) {
2501 printk(KERN_ERR
2502 "Domain context map for %s failed",
2503 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002504 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002505 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002506 }
2507
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002508 return domain;
2509}
2510
David Woodhouse147202a2009-07-07 19:43:20 +01002511static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2512{
2513 struct device_domain_info *info;
2514
2515 /* No lock here, assumes no domain exit in normal case */
2516 info = dev->dev.archdata.iommu;
2517 if (likely(info))
2518 return info->domain;
2519
2520 return __get_valid_domain_for_dev(dev);
2521}
2522
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002523static int iommu_dummy(struct pci_dev *pdev)
2524{
2525 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2526}
2527
2528/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002529static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002530{
David Woodhouse73676832009-07-04 14:08:36 +01002531 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002532 int found;
2533
David Woodhouse73676832009-07-04 14:08:36 +01002534 if (unlikely(dev->bus != &pci_bus_type))
2535 return 1;
2536
2537 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002538 if (iommu_dummy(pdev))
2539 return 1;
2540
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002541 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002542 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002543
2544 found = identity_mapping(pdev);
2545 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002546 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002547 return 1;
2548 else {
2549 /*
2550 * 32 bit DMA is removed from si_domain and fall back
2551 * to non-identity mapping.
2552 */
2553 domain_remove_one_dev_info(si_domain, pdev);
2554 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2555 pci_name(pdev));
2556 return 0;
2557 }
2558 } else {
2559 /*
2560 * In case of a detached 64 bit DMA device from vm, the device
2561 * is put into si_domain for identity mapping.
2562 */
David Woodhouse6941af22009-07-04 18:24:27 +01002563 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002564 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002565 ret = domain_add_dev_info(si_domain, pdev,
2566 hw_pass_through ?
2567 CONTEXT_TT_PASS_THROUGH :
2568 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002569 if (!ret) {
2570 printk(KERN_INFO "64bit %s uses identity mapping\n",
2571 pci_name(pdev));
2572 return 1;
2573 }
2574 }
2575 }
2576
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002577 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002578}
2579
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002580static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2581 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002582{
2583 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002584 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002585 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002586 struct iova *iova;
2587 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002588 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002589 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002590 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002591
2592 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002593
David Woodhouse73676832009-07-04 14:08:36 +01002594 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002595 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002596
2597 domain = get_valid_domain_for_dev(pdev);
2598 if (!domain)
2599 return 0;
2600
Weidong Han8c11e792008-12-08 15:29:22 +08002601 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002602 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002603
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002604 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
2605 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002606 if (!iova)
2607 goto error;
2608
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002609 /*
2610 * Check if DMAR supports zero-length reads on write only
2611 * mappings..
2612 */
2613 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002614 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002615 prot |= DMA_PTE_READ;
2616 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2617 prot |= DMA_PTE_WRITE;
2618 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002619 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002620 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002621 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002622 * is not a big problem
2623 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002624 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002625 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002626 if (ret)
2627 goto error;
2628
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002629 /* it's a non-present to present mapping. Only flush if caching mode */
2630 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002631 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002632 else
Weidong Han8c11e792008-12-08 15:29:22 +08002633 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002634
David Woodhouse03d6a242009-06-28 15:33:46 +01002635 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2636 start_paddr += paddr & ~PAGE_MASK;
2637 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002638
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002639error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002640 if (iova)
2641 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002642 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002643 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002644 return 0;
2645}
2646
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002647static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2648 unsigned long offset, size_t size,
2649 enum dma_data_direction dir,
2650 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002651{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002652 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2653 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002654}
2655
mark gross5e0d2a62008-03-04 15:22:08 -08002656static void flush_unmaps(void)
2657{
mark gross80b20dd2008-04-18 13:53:58 -07002658 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002659
mark gross5e0d2a62008-03-04 15:22:08 -08002660 timer_on = 0;
2661
2662 /* just flush them all */
2663 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002664 struct intel_iommu *iommu = g_iommus[i];
2665 if (!iommu)
2666 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002667
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002668 if (!deferred_flush[i].next)
2669 continue;
2670
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002671 /* In caching mode, global flushes turn emulation expensive */
2672 if (!cap_caching_mode(iommu->cap))
2673 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002674 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002675 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002676 unsigned long mask;
2677 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002678 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002679
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002680 /* On real hardware multiple invalidations are expensive */
2681 if (cap_caching_mode(iommu->cap))
2682 iommu_flush_iotlb_psi(iommu, domain->id,
2683 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2684 else {
2685 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2686 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2687 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2688 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002689 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002690 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002691 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002692 }
2693
mark gross5e0d2a62008-03-04 15:22:08 -08002694 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002695}
2696
2697static void flush_unmaps_timeout(unsigned long data)
2698{
mark gross80b20dd2008-04-18 13:53:58 -07002699 unsigned long flags;
2700
2701 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002702 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002703 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002704}
2705
2706static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2707{
2708 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002709 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002710 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002711
2712 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002713 if (list_size == HIGH_WATER_MARK)
2714 flush_unmaps();
2715
Weidong Han8c11e792008-12-08 15:29:22 +08002716 iommu = domain_get_iommu(dom);
2717 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002718
mark gross80b20dd2008-04-18 13:53:58 -07002719 next = deferred_flush[iommu_id].next;
2720 deferred_flush[iommu_id].domain[next] = dom;
2721 deferred_flush[iommu_id].iova[next] = iova;
2722 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002723
2724 if (!timer_on) {
2725 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2726 timer_on = 1;
2727 }
2728 list_size++;
2729 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2730}
2731
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002732static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2733 size_t size, enum dma_data_direction dir,
2734 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002735{
2736 struct pci_dev *pdev = to_pci_dev(dev);
2737 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002738 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002739 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002740 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002741
David Woodhouse73676832009-07-04 14:08:36 +01002742 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002743 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002744
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002745 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002746 BUG_ON(!domain);
2747
Weidong Han8c11e792008-12-08 15:29:22 +08002748 iommu = domain_get_iommu(domain);
2749
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002750 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002751 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2752 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002753 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002754
David Woodhoused794dc92009-06-28 00:27:49 +01002755 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2756 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002757
David Woodhoused794dc92009-06-28 00:27:49 +01002758 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2759 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002760
2761 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002762 dma_pte_clear_range(domain, start_pfn, last_pfn);
2763
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002764 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002765 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2766
mark gross5e0d2a62008-03-04 15:22:08 -08002767 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002768 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002769 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002770 /* free iova */
2771 __free_iova(&domain->iovad, iova);
2772 } else {
2773 add_unmap(domain, iova);
2774 /*
2775 * queue up the release of the unmap to save the 1/6th of the
2776 * cpu used up by the iotlb flush operation...
2777 */
mark gross5e0d2a62008-03-04 15:22:08 -08002778 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002779}
2780
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002781static void *intel_alloc_coherent(struct device *hwdev, size_t size,
2782 dma_addr_t *dma_handle, gfp_t flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002783{
2784 void *vaddr;
2785 int order;
2786
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002787 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002788 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002789
2790 if (!iommu_no_mapping(hwdev))
2791 flags &= ~(GFP_DMA | GFP_DMA32);
2792 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
2793 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
2794 flags |= GFP_DMA;
2795 else
2796 flags |= GFP_DMA32;
2797 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002798
2799 vaddr = (void *)__get_free_pages(flags, order);
2800 if (!vaddr)
2801 return NULL;
2802 memset(vaddr, 0, size);
2803
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002804 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2805 DMA_BIDIRECTIONAL,
2806 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002807 if (*dma_handle)
2808 return vaddr;
2809 free_pages((unsigned long)vaddr, order);
2810 return NULL;
2811}
2812
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002813static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
2814 dma_addr_t dma_handle)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002815{
2816 int order;
2817
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002818 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002819 order = get_order(size);
2820
David Woodhouse0db9b7a2009-07-14 02:01:57 +01002821 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002822 free_pages((unsigned long)vaddr, order);
2823}
2824
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002825static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
2826 int nelems, enum dma_data_direction dir,
2827 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002828{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002829 struct pci_dev *pdev = to_pci_dev(hwdev);
2830 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002831 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002832 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002833 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002834
David Woodhouse73676832009-07-04 14:08:36 +01002835 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002836 return;
2837
2838 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08002839 BUG_ON(!domain);
2840
2841 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002842
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002843 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01002844 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
2845 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002846 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002847
David Woodhoused794dc92009-06-28 00:27:49 +01002848 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2849 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002850
2851 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002852 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002853
David Woodhoused794dc92009-06-28 00:27:49 +01002854 /* free page tables */
2855 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2856
David Woodhouseacea0012009-07-14 01:55:11 +01002857 if (intel_iommu_strict) {
2858 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002859 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01002860 /* free iova */
2861 __free_iova(&domain->iovad, iova);
2862 } else {
2863 add_unmap(domain, iova);
2864 /*
2865 * queue up the release of the unmap to save the 1/6th of the
2866 * cpu used up by the iotlb flush operation...
2867 */
2868 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002869}
2870
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002871static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002872 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002873{
2874 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002875 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002876
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002877 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02002878 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00002879 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002880 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002881 }
2882 return nelems;
2883}
2884
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002885static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
2886 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002887{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002888 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002889 struct pci_dev *pdev = to_pci_dev(hwdev);
2890 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002891 size_t size = 0;
2892 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002893 struct iova *iova = NULL;
2894 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002895 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01002896 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08002897 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002898
2899 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01002900 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002901 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002902
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002903 domain = get_valid_domain_for_dev(pdev);
2904 if (!domain)
2905 return 0;
2906
Weidong Han8c11e792008-12-08 15:29:22 +08002907 iommu = domain_get_iommu(domain);
2908
David Woodhouseb536d242009-06-28 14:49:31 +01002909 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01002910 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002911
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002912 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
2913 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002914 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002915 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002916 return 0;
2917 }
2918
2919 /*
2920 * Check if DMAR supports zero-length reads on write only
2921 * mappings..
2922 */
2923 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002924 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002925 prot |= DMA_PTE_READ;
2926 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2927 prot |= DMA_PTE_WRITE;
2928
David Woodhouseb536d242009-06-28 14:49:31 +01002929 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01002930
Fenghua Yuf5329592009-08-04 15:09:37 -07002931 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01002932 if (unlikely(ret)) {
2933 /* clear the page */
2934 dma_pte_clear_range(domain, start_vpfn,
2935 start_vpfn + size - 1);
2936 /* free page tables */
2937 dma_pte_free_pagetable(domain, start_vpfn,
2938 start_vpfn + size - 1);
2939 /* free iova */
2940 __free_iova(&domain->iovad, iova);
2941 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002942 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002943
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002944 /* it's a non-present to present mapping. Only flush if caching mode */
2945 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002946 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002947 else
Weidong Han8c11e792008-12-08 15:29:22 +08002948 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002949
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002950 return nelems;
2951}
2952
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09002953static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
2954{
2955 return !dma_addr;
2956}
2957
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09002958struct dma_map_ops intel_dma_ops = {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002959 .alloc_coherent = intel_alloc_coherent,
2960 .free_coherent = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002961 .map_sg = intel_map_sg,
2962 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002963 .map_page = intel_map_page,
2964 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09002965 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002966};
2967
2968static inline int iommu_domain_cache_init(void)
2969{
2970 int ret = 0;
2971
2972 iommu_domain_cache = kmem_cache_create("iommu_domain",
2973 sizeof(struct dmar_domain),
2974 0,
2975 SLAB_HWCACHE_ALIGN,
2976
2977 NULL);
2978 if (!iommu_domain_cache) {
2979 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
2980 ret = -ENOMEM;
2981 }
2982
2983 return ret;
2984}
2985
2986static inline int iommu_devinfo_cache_init(void)
2987{
2988 int ret = 0;
2989
2990 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
2991 sizeof(struct device_domain_info),
2992 0,
2993 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002994 NULL);
2995 if (!iommu_devinfo_cache) {
2996 printk(KERN_ERR "Couldn't create devinfo cache\n");
2997 ret = -ENOMEM;
2998 }
2999
3000 return ret;
3001}
3002
3003static inline int iommu_iova_cache_init(void)
3004{
3005 int ret = 0;
3006
3007 iommu_iova_cache = kmem_cache_create("iommu_iova",
3008 sizeof(struct iova),
3009 0,
3010 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003011 NULL);
3012 if (!iommu_iova_cache) {
3013 printk(KERN_ERR "Couldn't create iova cache\n");
3014 ret = -ENOMEM;
3015 }
3016
3017 return ret;
3018}
3019
3020static int __init iommu_init_mempool(void)
3021{
3022 int ret;
3023 ret = iommu_iova_cache_init();
3024 if (ret)
3025 return ret;
3026
3027 ret = iommu_domain_cache_init();
3028 if (ret)
3029 goto domain_error;
3030
3031 ret = iommu_devinfo_cache_init();
3032 if (!ret)
3033 return ret;
3034
3035 kmem_cache_destroy(iommu_domain_cache);
3036domain_error:
3037 kmem_cache_destroy(iommu_iova_cache);
3038
3039 return -ENOMEM;
3040}
3041
3042static void __init iommu_exit_mempool(void)
3043{
3044 kmem_cache_destroy(iommu_devinfo_cache);
3045 kmem_cache_destroy(iommu_domain_cache);
3046 kmem_cache_destroy(iommu_iova_cache);
3047
3048}
3049
Dan Williams556ab452010-07-23 15:47:56 -07003050static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3051{
3052 struct dmar_drhd_unit *drhd;
3053 u32 vtbar;
3054 int rc;
3055
3056 /* We know that this device on this chipset has its own IOMMU.
3057 * If we find it under a different IOMMU, then the BIOS is lying
3058 * to us. Hope that the IOMMU for this device is actually
3059 * disabled, and it needs no translation...
3060 */
3061 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3062 if (rc) {
3063 /* "can't" happen */
3064 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3065 return;
3066 }
3067 vtbar &= 0xffff0000;
3068
3069 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3070 drhd = dmar_find_matched_drhd_unit(pdev);
3071 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3072 TAINT_FIRMWARE_WORKAROUND,
3073 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3074 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3075}
3076DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3077
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003078static void __init init_no_remapping_devices(void)
3079{
3080 struct dmar_drhd_unit *drhd;
3081
3082 for_each_drhd_unit(drhd) {
3083 if (!drhd->include_all) {
3084 int i;
3085 for (i = 0; i < drhd->devices_cnt; i++)
3086 if (drhd->devices[i] != NULL)
3087 break;
3088 /* ignore DMAR unit if no pci devices exist */
3089 if (i == drhd->devices_cnt)
3090 drhd->ignored = 1;
3091 }
3092 }
3093
3094 if (dmar_map_gfx)
3095 return;
3096
3097 for_each_drhd_unit(drhd) {
3098 int i;
3099 if (drhd->ignored || drhd->include_all)
3100 continue;
3101
3102 for (i = 0; i < drhd->devices_cnt; i++)
3103 if (drhd->devices[i] &&
3104 !IS_GFX_DEVICE(drhd->devices[i]))
3105 break;
3106
3107 if (i < drhd->devices_cnt)
3108 continue;
3109
3110 /* bypass IOMMU if it is just for gfx devices */
3111 drhd->ignored = 1;
3112 for (i = 0; i < drhd->devices_cnt; i++) {
3113 if (!drhd->devices[i])
3114 continue;
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07003115 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003116 }
3117 }
3118}
3119
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003120#ifdef CONFIG_SUSPEND
3121static int init_iommu_hw(void)
3122{
3123 struct dmar_drhd_unit *drhd;
3124 struct intel_iommu *iommu = NULL;
3125
3126 for_each_active_iommu(iommu, drhd)
3127 if (iommu->qi)
3128 dmar_reenable_qi(iommu);
3129
Joseph Cihulab7792602011-05-03 00:08:37 -07003130 for_each_iommu(iommu, drhd) {
3131 if (drhd->ignored) {
3132 /*
3133 * we always have to disable PMRs or DMA may fail on
3134 * this device
3135 */
3136 if (force_on)
3137 iommu_disable_protect_mem_regions(iommu);
3138 continue;
3139 }
3140
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003141 iommu_flush_write_buffer(iommu);
3142
3143 iommu_set_root_entry(iommu);
3144
3145 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003146 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003147 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003148 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003149 if (iommu_enable_translation(iommu))
3150 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003151 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003152 }
3153
3154 return 0;
3155}
3156
3157static void iommu_flush_all(void)
3158{
3159 struct dmar_drhd_unit *drhd;
3160 struct intel_iommu *iommu;
3161
3162 for_each_active_iommu(iommu, drhd) {
3163 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003164 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003165 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003166 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003167 }
3168}
3169
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003170static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003171{
3172 struct dmar_drhd_unit *drhd;
3173 struct intel_iommu *iommu = NULL;
3174 unsigned long flag;
3175
3176 for_each_active_iommu(iommu, drhd) {
3177 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3178 GFP_ATOMIC);
3179 if (!iommu->iommu_state)
3180 goto nomem;
3181 }
3182
3183 iommu_flush_all();
3184
3185 for_each_active_iommu(iommu, drhd) {
3186 iommu_disable_translation(iommu);
3187
3188 spin_lock_irqsave(&iommu->register_lock, flag);
3189
3190 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3191 readl(iommu->reg + DMAR_FECTL_REG);
3192 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3193 readl(iommu->reg + DMAR_FEDATA_REG);
3194 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3195 readl(iommu->reg + DMAR_FEADDR_REG);
3196 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3197 readl(iommu->reg + DMAR_FEUADDR_REG);
3198
3199 spin_unlock_irqrestore(&iommu->register_lock, flag);
3200 }
3201 return 0;
3202
3203nomem:
3204 for_each_active_iommu(iommu, drhd)
3205 kfree(iommu->iommu_state);
3206
3207 return -ENOMEM;
3208}
3209
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003210static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003211{
3212 struct dmar_drhd_unit *drhd;
3213 struct intel_iommu *iommu = NULL;
3214 unsigned long flag;
3215
3216 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003217 if (force_on)
3218 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3219 else
3220 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003221 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003222 }
3223
3224 for_each_active_iommu(iommu, drhd) {
3225
3226 spin_lock_irqsave(&iommu->register_lock, flag);
3227
3228 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3229 iommu->reg + DMAR_FECTL_REG);
3230 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3231 iommu->reg + DMAR_FEDATA_REG);
3232 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3233 iommu->reg + DMAR_FEADDR_REG);
3234 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3235 iommu->reg + DMAR_FEUADDR_REG);
3236
3237 spin_unlock_irqrestore(&iommu->register_lock, flag);
3238 }
3239
3240 for_each_active_iommu(iommu, drhd)
3241 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003242}
3243
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003244static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003245 .resume = iommu_resume,
3246 .suspend = iommu_suspend,
3247};
3248
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003249static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003250{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003251 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003252}
3253
3254#else
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003255static inline int init_iommu_pm_ops(void) { }
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003256#endif /* CONFIG_PM */
3257
Fenghua Yu99dcade2009-11-11 07:23:06 -08003258/*
3259 * Here we only respond to action of unbound device from driver.
3260 *
3261 * Added device is not attached to its DMAR domain here yet. That will happen
3262 * when mapping the device to iova.
3263 */
3264static int device_notifier(struct notifier_block *nb,
3265 unsigned long action, void *data)
3266{
3267 struct device *dev = data;
3268 struct pci_dev *pdev = to_pci_dev(dev);
3269 struct dmar_domain *domain;
3270
David Woodhouse44cd6132009-12-02 10:18:30 +00003271 if (iommu_no_mapping(dev))
3272 return 0;
3273
Fenghua Yu99dcade2009-11-11 07:23:06 -08003274 domain = find_domain(pdev);
3275 if (!domain)
3276 return 0;
3277
Alex Williamsona97590e2011-03-04 14:52:16 -07003278 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
Fenghua Yu99dcade2009-11-11 07:23:06 -08003279 domain_remove_one_dev_info(domain, pdev);
3280
Alex Williamsona97590e2011-03-04 14:52:16 -07003281 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3282 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3283 list_empty(&domain->devices))
3284 domain_exit(domain);
3285 }
3286
Fenghua Yu99dcade2009-11-11 07:23:06 -08003287 return 0;
3288}
3289
3290static struct notifier_block device_nb = {
3291 .notifier_call = device_notifier,
3292};
3293
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003294int __init intel_iommu_init(void)
3295{
3296 int ret = 0;
3297
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003298 /* VT-d is required for a TXT/tboot launch, so enforce that */
3299 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003300
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003301 if (dmar_table_init()) {
3302 if (force_on)
3303 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003304 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003305 }
3306
3307 if (dmar_dev_scope_init()) {
3308 if (force_on)
3309 panic("tboot: Failed to initialize DMAR device scope\n");
3310 return -ENODEV;
3311 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003312
Suresh Siddha2ae21012008-07-10 11:16:43 -07003313 /*
3314 * Check the need for DMA-remapping initialization now.
3315 * Above initialization will also be used by Interrupt-remapping.
3316 */
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003317 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003318 return -ENODEV;
3319
Joseph Cihula51a63e62011-03-21 11:04:24 -07003320 if (iommu_init_mempool()) {
3321 if (force_on)
3322 panic("tboot: Failed to initialize iommu memory\n");
3323 return -ENODEV;
3324 }
3325
3326 if (dmar_init_reserved_ranges()) {
3327 if (force_on)
3328 panic("tboot: Failed to reserve iommu ranges\n");
3329 return -ENODEV;
3330 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003331
3332 init_no_remapping_devices();
3333
Joseph Cihulab7792602011-05-03 00:08:37 -07003334 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003335 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003336 if (force_on)
3337 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003338 printk(KERN_ERR "IOMMU: dmar init failed\n");
3339 put_iova_domain(&reserved_iova_list);
3340 iommu_exit_mempool();
3341 return ret;
3342 }
3343 printk(KERN_INFO
3344 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3345
mark gross5e0d2a62008-03-04 15:22:08 -08003346 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003347#ifdef CONFIG_SWIOTLB
3348 swiotlb = 0;
3349#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003350 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003351
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003352 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003353
3354 register_iommu(&intel_iommu_ops);
3355
Fenghua Yu99dcade2009-11-11 07:23:06 -08003356 bus_register_notifier(&pci_bus_type, &device_nb);
3357
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003358 return 0;
3359}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003360
Han, Weidong3199aa62009-02-26 17:31:12 +08003361static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3362 struct pci_dev *pdev)
3363{
3364 struct pci_dev *tmp, *parent;
3365
3366 if (!iommu || !pdev)
3367 return;
3368
3369 /* dependent device detach */
3370 tmp = pci_find_upstream_pcie_bridge(pdev);
3371 /* Secondary interface's bus number and devfn 0 */
3372 if (tmp) {
3373 parent = pdev->bus->self;
3374 while (parent != tmp) {
3375 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01003376 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003377 parent = parent->bus->self;
3378 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003379 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003380 iommu_detach_dev(iommu,
3381 tmp->subordinate->number, 0);
3382 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01003383 iommu_detach_dev(iommu, tmp->bus->number,
3384 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003385 }
3386}
3387
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003388static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003389 struct pci_dev *pdev)
3390{
3391 struct device_domain_info *info;
3392 struct intel_iommu *iommu;
3393 unsigned long flags;
3394 int found = 0;
3395 struct list_head *entry, *tmp;
3396
David Woodhouse276dbf992009-04-04 01:45:37 +01003397 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3398 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003399 if (!iommu)
3400 return;
3401
3402 spin_lock_irqsave(&device_domain_lock, flags);
3403 list_for_each_safe(entry, tmp, &domain->devices) {
3404 info = list_entry(entry, struct device_domain_info, link);
David Woodhouse276dbf992009-04-04 01:45:37 +01003405 /* No need to compare PCI domain; it has to be the same */
Weidong Hanc7151a82008-12-08 22:51:37 +08003406 if (info->bus == pdev->bus->number &&
3407 info->devfn == pdev->devfn) {
3408 list_del(&info->link);
3409 list_del(&info->global);
3410 if (info->dev)
3411 info->dev->dev.archdata.iommu = NULL;
3412 spin_unlock_irqrestore(&device_domain_lock, flags);
3413
Yu Zhao93a23a72009-05-18 13:51:37 +08003414 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003415 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003416 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003417 free_devinfo_mem(info);
3418
3419 spin_lock_irqsave(&device_domain_lock, flags);
3420
3421 if (found)
3422 break;
3423 else
3424 continue;
3425 }
3426
3427 /* if there is no other devices under the same iommu
3428 * owned by this domain, clear this iommu in iommu_bmp
3429 * update iommu count and coherency
3430 */
David Woodhouse276dbf992009-04-04 01:45:37 +01003431 if (iommu == device_to_iommu(info->segment, info->bus,
3432 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003433 found = 1;
3434 }
3435
3436 if (found == 0) {
3437 unsigned long tmp_flags;
3438 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
3439 clear_bit(iommu->seq_id, &domain->iommu_bmp);
3440 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003441 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003442 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003443
3444 spin_lock_irqsave(&iommu->lock, tmp_flags);
3445 clear_bit(domain->id, iommu->domain_ids);
3446 iommu->domains[domain->id] = NULL;
3447 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08003448 }
3449
3450 spin_unlock_irqrestore(&device_domain_lock, flags);
3451}
3452
3453static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3454{
3455 struct device_domain_info *info;
3456 struct intel_iommu *iommu;
3457 unsigned long flags1, flags2;
3458
3459 spin_lock_irqsave(&device_domain_lock, flags1);
3460 while (!list_empty(&domain->devices)) {
3461 info = list_entry(domain->devices.next,
3462 struct device_domain_info, link);
3463 list_del(&info->link);
3464 list_del(&info->global);
3465 if (info->dev)
3466 info->dev->dev.archdata.iommu = NULL;
3467
3468 spin_unlock_irqrestore(&device_domain_lock, flags1);
3469
Yu Zhao93a23a72009-05-18 13:51:37 +08003470 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01003471 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003472 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003473 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003474
3475 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003476 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003477 */
3478 spin_lock_irqsave(&domain->iommu_lock, flags2);
3479 if (test_and_clear_bit(iommu->seq_id,
3480 &domain->iommu_bmp)) {
3481 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003482 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003483 }
3484 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3485
3486 free_devinfo_mem(info);
3487 spin_lock_irqsave(&device_domain_lock, flags1);
3488 }
3489 spin_unlock_irqrestore(&device_domain_lock, flags1);
3490}
3491
Weidong Han5e98c4b2008-12-08 23:03:27 +08003492/* domain id for virtual machine, it won't be set in context */
3493static unsigned long vm_domid;
3494
3495static struct dmar_domain *iommu_alloc_vm_domain(void)
3496{
3497 struct dmar_domain *domain;
3498
3499 domain = alloc_domain_mem();
3500 if (!domain)
3501 return NULL;
3502
3503 domain->id = vm_domid++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003504 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003505 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
3506 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3507
3508 return domain;
3509}
3510
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003511static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003512{
3513 int adjust_width;
3514
3515 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003516 spin_lock_init(&domain->iommu_lock);
3517
3518 domain_reserve_special_ranges(domain);
3519
3520 /* calculate AGAW */
3521 domain->gaw = guest_width;
3522 adjust_width = guestwidth_to_adjustwidth(guest_width);
3523 domain->agaw = width_to_agaw(adjust_width);
3524
3525 INIT_LIST_HEAD(&domain->devices);
3526
3527 domain->iommu_count = 0;
3528 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003529 domain->iommu_snooping = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003530 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003531 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003532
3533 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003534 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003535 if (!domain->pgd)
3536 return -ENOMEM;
3537 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3538 return 0;
3539}
3540
3541static void iommu_free_vm_domain(struct dmar_domain *domain)
3542{
3543 unsigned long flags;
3544 struct dmar_drhd_unit *drhd;
3545 struct intel_iommu *iommu;
3546 unsigned long i;
3547 unsigned long ndomains;
3548
3549 for_each_drhd_unit(drhd) {
3550 if (drhd->ignored)
3551 continue;
3552 iommu = drhd->iommu;
3553
3554 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08003555 for_each_set_bit(i, iommu->domain_ids, ndomains) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003556 if (iommu->domains[i] == domain) {
3557 spin_lock_irqsave(&iommu->lock, flags);
3558 clear_bit(i, iommu->domain_ids);
3559 iommu->domains[i] = NULL;
3560 spin_unlock_irqrestore(&iommu->lock, flags);
3561 break;
3562 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08003563 }
3564 }
3565}
3566
3567static void vm_domain_exit(struct dmar_domain *domain)
3568{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003569 /* Domain 0 is reserved, so dont process it */
3570 if (!domain)
3571 return;
3572
3573 vm_domain_remove_all_dev_info(domain);
3574 /* destroy iovas */
3575 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003576
3577 /* clear ptes */
David Woodhouse595badf52009-06-27 22:09:11 +01003578 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003579
3580 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003581 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003582
3583 iommu_free_vm_domain(domain);
3584 free_domain_mem(domain);
3585}
3586
Joerg Roedel5d450802008-12-03 14:52:32 +01003587static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003588{
Joerg Roedel5d450802008-12-03 14:52:32 +01003589 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003590
Joerg Roedel5d450802008-12-03 14:52:32 +01003591 dmar_domain = iommu_alloc_vm_domain();
3592 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003593 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003594 "intel_iommu_domain_init: dmar_domain == NULL\n");
3595 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003596 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003597 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003598 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003599 "intel_iommu_domain_init() failed\n");
3600 vm_domain_exit(dmar_domain);
3601 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003602 }
Joerg Roedel5d450802008-12-03 14:52:32 +01003603 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003604
Joerg Roedel5d450802008-12-03 14:52:32 +01003605 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003606}
Kay, Allen M38717942008-09-09 18:37:29 +03003607
Joerg Roedel5d450802008-12-03 14:52:32 +01003608static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003609{
Joerg Roedel5d450802008-12-03 14:52:32 +01003610 struct dmar_domain *dmar_domain = domain->priv;
3611
3612 domain->priv = NULL;
3613 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003614}
Kay, Allen M38717942008-09-09 18:37:29 +03003615
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003616static int intel_iommu_attach_device(struct iommu_domain *domain,
3617 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003618{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003619 struct dmar_domain *dmar_domain = domain->priv;
3620 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003621 struct intel_iommu *iommu;
3622 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03003623
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003624 /* normally pdev is not mapped */
3625 if (unlikely(domain_context_mapped(pdev))) {
3626 struct dmar_domain *old_domain;
3627
3628 old_domain = find_domain(pdev);
3629 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003630 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3631 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3632 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003633 else
3634 domain_remove_dev_info(old_domain);
3635 }
3636 }
3637
David Woodhouse276dbf992009-04-04 01:45:37 +01003638 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3639 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003640 if (!iommu)
3641 return -ENODEV;
3642
3643 /* check if this iommu agaw is sufficient for max mapped address */
3644 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01003645 if (addr_width > cap_mgaw(iommu->cap))
3646 addr_width = cap_mgaw(iommu->cap);
3647
3648 if (dmar_domain->max_addr > (1LL << addr_width)) {
3649 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003650 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01003651 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003652 return -EFAULT;
3653 }
Tom Lyona99c47a2010-05-17 08:20:45 +01003654 dmar_domain->gaw = addr_width;
3655
3656 /*
3657 * Knock out extra levels of page tables if necessary
3658 */
3659 while (iommu->agaw < dmar_domain->agaw) {
3660 struct dma_pte *pte;
3661
3662 pte = dmar_domain->pgd;
3663 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08003664 dmar_domain->pgd = (struct dma_pte *)
3665 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01003666 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01003667 }
3668 dmar_domain->agaw--;
3669 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003670
David Woodhouse5fe60f42009-08-09 10:53:41 +01003671 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003672}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003673
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003674static void intel_iommu_detach_device(struct iommu_domain *domain,
3675 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003676{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003677 struct dmar_domain *dmar_domain = domain->priv;
3678 struct pci_dev *pdev = to_pci_dev(dev);
3679
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003680 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003681}
Kay, Allen M38717942008-09-09 18:37:29 +03003682
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003683static int intel_iommu_map(struct iommu_domain *domain,
3684 unsigned long iova, phys_addr_t hpa,
3685 int gfp_order, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003686{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003687 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003688 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003689 int prot = 0;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003690 size_t size;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003691 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003692
Joerg Roedeldde57a22008-12-03 15:04:09 +01003693 if (iommu_prot & IOMMU_READ)
3694 prot |= DMA_PTE_READ;
3695 if (iommu_prot & IOMMU_WRITE)
3696 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08003697 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
3698 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003699
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003700 size = PAGE_SIZE << gfp_order;
David Woodhouse163cc522009-06-28 00:51:17 +01003701 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003702 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003703 u64 end;
3704
3705 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01003706 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003707 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01003708 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003709 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01003710 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003711 return -EFAULT;
3712 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003713 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003714 }
David Woodhousead051222009-06-28 14:22:28 +01003715 /* Round up size to next multiple of PAGE_SIZE, if it and
3716 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01003717 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01003718 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
3719 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003720 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003721}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003722
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003723static int intel_iommu_unmap(struct iommu_domain *domain,
3724 unsigned long iova, int gfp_order)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003725{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003726 struct dmar_domain *dmar_domain = domain->priv;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003727 size_t size = PAGE_SIZE << gfp_order;
Sheng Yang4b99d352009-07-08 11:52:52 +01003728
David Woodhouse163cc522009-06-28 00:51:17 +01003729 dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
3730 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003731
David Woodhouse163cc522009-06-28 00:51:17 +01003732 if (dmar_domain->max_addr == iova + size)
3733 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003734
3735 return gfp_order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003736}
Kay, Allen M38717942008-09-09 18:37:29 +03003737
Joerg Roedeld14d6572008-12-03 15:06:57 +01003738static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
3739 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03003740{
Joerg Roedeld14d6572008-12-03 15:06:57 +01003741 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03003742 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003743 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003744
David Woodhouseb026fd22009-06-28 10:37:25 +01003745 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
Kay, Allen M38717942008-09-09 18:37:29 +03003746 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003747 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03003748
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003749 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03003750}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003751
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003752static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
3753 unsigned long cap)
3754{
3755 struct dmar_domain *dmar_domain = domain->priv;
3756
3757 if (cap == IOMMU_CAP_CACHE_COHERENCY)
3758 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04003759 if (cap == IOMMU_CAP_INTR_REMAP)
3760 return intr_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003761
3762 return 0;
3763}
3764
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003765static struct iommu_ops intel_iommu_ops = {
3766 .domain_init = intel_iommu_domain_init,
3767 .domain_destroy = intel_iommu_domain_destroy,
3768 .attach_dev = intel_iommu_attach_device,
3769 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003770 .map = intel_iommu_map,
3771 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003772 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08003773 .domain_has_cap = intel_iommu_domain_has_cap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003774};
David Woodhouse9af88142009-02-13 23:18:03 +00003775
3776static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
3777{
3778 /*
3779 * Mobile 4 Series Chipset neglects to set RWBF capability,
3780 * but needs it:
3781 */
3782 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
3783 rwbf_quirk = 1;
David Woodhouse2d9e6672010-06-15 10:57:57 +01003784
3785 /* https://bugzilla.redhat.com/show_bug.cgi?id=538163 */
3786 if (dev->revision == 0x07) {
3787 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
3788 dmar_map_gfx = 0;
3789 }
David Woodhouse9af88142009-02-13 23:18:03 +00003790}
3791
3792DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07003793
Adam Jacksoneecfd572010-08-25 21:17:34 +01003794#define GGC 0x52
3795#define GGC_MEMORY_SIZE_MASK (0xf << 8)
3796#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
3797#define GGC_MEMORY_SIZE_1M (0x1 << 8)
3798#define GGC_MEMORY_SIZE_2M (0x3 << 8)
3799#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
3800#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
3801#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
3802#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
3803
David Woodhouse9eecabc2010-09-21 22:28:23 +01003804static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
3805{
3806 unsigned short ggc;
3807
Adam Jacksoneecfd572010-08-25 21:17:34 +01003808 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01003809 return;
3810
Adam Jacksoneecfd572010-08-25 21:17:34 +01003811 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01003812 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
3813 dmar_map_gfx = 0;
3814 }
3815}
3816DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
3817DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
3818DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
3819DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
3820
David Woodhousee0fc7e02009-09-30 09:12:17 -07003821/* On Tylersburg chipsets, some BIOSes have been known to enable the
3822 ISOCH DMAR unit for the Azalia sound device, but not give it any
3823 TLB entries, which causes it to deadlock. Check for that. We do
3824 this in a function called from init_dmars(), instead of in a PCI
3825 quirk, because we don't want to print the obnoxious "BIOS broken"
3826 message if VT-d is actually disabled.
3827*/
3828static void __init check_tylersburg_isoch(void)
3829{
3830 struct pci_dev *pdev;
3831 uint32_t vtisochctrl;
3832
3833 /* If there's no Azalia in the system anyway, forget it. */
3834 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
3835 if (!pdev)
3836 return;
3837 pci_dev_put(pdev);
3838
3839 /* System Management Registers. Might be hidden, in which case
3840 we can't do the sanity check. But that's OK, because the
3841 known-broken BIOSes _don't_ actually hide it, so far. */
3842 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
3843 if (!pdev)
3844 return;
3845
3846 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
3847 pci_dev_put(pdev);
3848 return;
3849 }
3850
3851 pci_dev_put(pdev);
3852
3853 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
3854 if (vtisochctrl & 1)
3855 return;
3856
3857 /* Drop all bits other than the number of TLB entries */
3858 vtisochctrl &= 0x1c;
3859
3860 /* If we have the recommended number of TLB entries (16), fine. */
3861 if (vtisochctrl == 0x10)
3862 return;
3863
3864 /* Zero TLB entries? You get to ride the short bus to school. */
3865 if (!vtisochctrl) {
3866 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
3867 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
3868 dmi_get_system_info(DMI_BIOS_VENDOR),
3869 dmi_get_system_info(DMI_BIOS_VERSION),
3870 dmi_get_system_info(DMI_PRODUCT_VERSION));
3871 iommu_identity_mapping |= IDENTMAP_AZALIA;
3872 return;
3873 }
3874
3875 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
3876 vtisochctrl);
3877}