blob: d1c17934d66f1e4070a00800d87e8b78d36d5758 [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>
Paul Gortmaker54485c32011-10-29 10:26:25 -040027#include <linux/export.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070028#include <linux/slab.h>
29#include <linux/irq.h>
30#include <linux/interrupt.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070031#include <linux/spinlock.h>
32#include <linux/pci.h>
33#include <linux/dmar.h>
34#include <linux/dma-mapping.h>
35#include <linux/mempool.h>
mark gross5e0d2a62008-03-04 15:22:08 -080036#include <linux/timer.h>
Kay, Allen M38717942008-09-09 18:37:29 +030037#include <linux/iova.h>
Joerg Roedel5d450802008-12-03 14:52:32 +010038#include <linux/iommu.h>
Kay, Allen M38717942008-09-09 18:37:29 +030039#include <linux/intel-iommu.h>
Rafael J. Wysocki134fac32011-03-23 22:16:14 +010040#include <linux/syscore_ops.h>
Shane Wang69575d32009-09-01 18:25:07 -070041#include <linux/tboot.h>
Stephen Rothwelladb2fe02009-08-31 15:24:23 +100042#include <linux/dmi.h>
Joerg Roedel5cdede22011-04-04 15:55:18 +020043#include <linux/pci-ats.h>
Tejun Heo0ee332c2011-12-08 10:22:09 -080044#include <linux/memblock.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070045#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090046#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070047
Fenghua Yu5b6985c2008-10-16 18:02:32 -070048#define ROOT_SIZE VTD_PAGE_SIZE
49#define CONTEXT_SIZE VTD_PAGE_SIZE
50
Mike Travis825507d2011-05-28 13:15:06 -050051#define IS_BRIDGE_HOST_DEVICE(pdev) \
52 ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070053#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
54#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070055#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070056
57#define IOAPIC_RANGE_START (0xfee00000)
58#define IOAPIC_RANGE_END (0xfeefffff)
59#define IOVA_START_ADDR (0x1000)
60
61#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
62
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070063#define MAX_AGAW_WIDTH 64
64
David Woodhouse2ebe3152009-09-19 07:34:04 -070065#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
66#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
67
68/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
69 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
70#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
71 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
72#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070073
Mark McLoughlinf27be032008-11-20 15:49:43 +000074#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070075#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070076#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080077
Andrew Mortondf08cdc2010-09-22 13:05:11 -070078/* page table handling */
79#define LEVEL_STRIDE (9)
80#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
81
82static inline int agaw_to_level(int agaw)
83{
84 return agaw + 2;
85}
86
87static inline int agaw_to_width(int agaw)
88{
89 return 30 + agaw * LEVEL_STRIDE;
90}
91
92static inline int width_to_agaw(int width)
93{
94 return (width - 30) / LEVEL_STRIDE;
95}
96
97static inline unsigned int level_to_offset_bits(int level)
98{
99 return (level - 1) * LEVEL_STRIDE;
100}
101
102static inline int pfn_level_offset(unsigned long pfn, int level)
103{
104 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
105}
106
107static inline unsigned long level_mask(int level)
108{
109 return -1UL << level_to_offset_bits(level);
110}
111
112static inline unsigned long level_size(int level)
113{
114 return 1UL << level_to_offset_bits(level);
115}
116
117static inline unsigned long align_to_level(unsigned long pfn, int level)
118{
119 return (pfn + level_size(level) - 1) & level_mask(level);
120}
David Woodhousefd18de52009-05-10 23:57:41 +0100121
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100122static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
123{
124 return 1 << ((lvl - 1) * LEVEL_STRIDE);
125}
126
David Woodhousedd4e8312009-06-27 16:21:20 +0100127/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
128 are never going to work. */
129static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
130{
131 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
132}
133
134static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
135{
136 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
137}
138static inline unsigned long page_to_dma_pfn(struct page *pg)
139{
140 return mm_to_dma_pfn(page_to_pfn(pg));
141}
142static inline unsigned long virt_to_dma_pfn(void *p)
143{
144 return page_to_dma_pfn(virt_to_page(p));
145}
146
Weidong Hand9630fe2008-12-08 11:06:32 +0800147/* global iommu list, set NULL for ignored DMAR units */
148static struct intel_iommu **g_iommus;
149
David Woodhousee0fc7e02009-09-30 09:12:17 -0700150static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000151static int rwbf_quirk;
152
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000153/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700154 * set to 1 to panic kernel if can't successfully enable VT-d
155 * (used when kernel is launched w/ TXT)
156 */
157static int force_on = 0;
158
159/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000160 * 0: Present
161 * 1-11: Reserved
162 * 12-63: Context Ptr (12 - (haw-1))
163 * 64-127: Reserved
164 */
165struct root_entry {
166 u64 val;
167 u64 rsvd1;
168};
169#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
170static inline bool root_present(struct root_entry *root)
171{
172 return (root->val & 1);
173}
174static inline void set_root_present(struct root_entry *root)
175{
176 root->val |= 1;
177}
178static inline void set_root_value(struct root_entry *root, unsigned long value)
179{
180 root->val |= value & VTD_PAGE_MASK;
181}
182
183static inline struct context_entry *
184get_context_addr_from_root(struct root_entry *root)
185{
186 return (struct context_entry *)
187 (root_present(root)?phys_to_virt(
188 root->val & VTD_PAGE_MASK) :
189 NULL);
190}
191
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000192/*
193 * low 64 bits:
194 * 0: present
195 * 1: fault processing disable
196 * 2-3: translation type
197 * 12-63: address space root
198 * high 64 bits:
199 * 0-2: address width
200 * 3-6: aval
201 * 8-23: domain id
202 */
203struct context_entry {
204 u64 lo;
205 u64 hi;
206};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000207
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000208static inline bool context_present(struct context_entry *context)
209{
210 return (context->lo & 1);
211}
212static inline void context_set_present(struct context_entry *context)
213{
214 context->lo |= 1;
215}
216
217static inline void context_set_fault_enable(struct context_entry *context)
218{
219 context->lo &= (((u64)-1) << 2) | 1;
220}
221
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000222static inline void context_set_translation_type(struct context_entry *context,
223 unsigned long value)
224{
225 context->lo &= (((u64)-1) << 4) | 3;
226 context->lo |= (value & 3) << 2;
227}
228
229static inline void context_set_address_root(struct context_entry *context,
230 unsigned long value)
231{
232 context->lo |= value & VTD_PAGE_MASK;
233}
234
235static inline void context_set_address_width(struct context_entry *context,
236 unsigned long value)
237{
238 context->hi |= value & 7;
239}
240
241static inline void context_set_domain_id(struct context_entry *context,
242 unsigned long value)
243{
244 context->hi |= (value & ((1 << 16) - 1)) << 8;
245}
246
247static inline void context_clear_entry(struct context_entry *context)
248{
249 context->lo = 0;
250 context->hi = 0;
251}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000252
Mark McLoughlin622ba122008-11-20 15:49:46 +0000253/*
254 * 0: readable
255 * 1: writable
256 * 2-6: reserved
257 * 7: super page
Sheng Yang9cf06692009-03-18 15:33:07 +0800258 * 8-10: available
259 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000260 * 12-63: Host physcial address
261 */
262struct dma_pte {
263 u64 val;
264};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000265
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000266static inline void dma_clear_pte(struct dma_pte *pte)
267{
268 pte->val = 0;
269}
270
271static inline void dma_set_pte_readable(struct dma_pte *pte)
272{
273 pte->val |= DMA_PTE_READ;
274}
275
276static inline void dma_set_pte_writable(struct dma_pte *pte)
277{
278 pte->val |= DMA_PTE_WRITE;
279}
280
Sheng Yang9cf06692009-03-18 15:33:07 +0800281static inline void dma_set_pte_snp(struct dma_pte *pte)
282{
283 pte->val |= DMA_PTE_SNP;
284}
285
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000286static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
287{
288 pte->val = (pte->val & ~3) | (prot & 3);
289}
290
291static inline u64 dma_pte_addr(struct dma_pte *pte)
292{
David Woodhousec85994e2009-07-01 19:21:24 +0100293#ifdef CONFIG_64BIT
294 return pte->val & VTD_PAGE_MASK;
295#else
296 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100297 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100298#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000299}
300
David Woodhousedd4e8312009-06-27 16:21:20 +0100301static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000302{
David Woodhousedd4e8312009-06-27 16:21:20 +0100303 pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000304}
305
306static inline bool dma_pte_present(struct dma_pte *pte)
307{
308 return (pte->val & 3) != 0;
309}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000310
Allen Kay4399c8b2011-10-14 12:32:46 -0700311static inline bool dma_pte_superpage(struct dma_pte *pte)
312{
313 return (pte->val & (1 << 7));
314}
315
David Woodhouse75e6bf92009-07-02 11:21:16 +0100316static inline int first_pte_in_page(struct dma_pte *pte)
317{
318 return !((unsigned long)pte & ~VTD_PAGE_MASK);
319}
320
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700321/*
322 * This domain is a statically identity mapping domain.
323 * 1. This domain creats a static 1:1 mapping to all usable memory.
324 * 2. It maps to each iommu if successful.
325 * 3. Each iommu mapps to this domain if successful.
326 */
David Woodhouse19943b02009-08-04 16:19:20 +0100327static struct dmar_domain *si_domain;
328static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700329
Weidong Han3b5410e2008-12-08 09:17:15 +0800330/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100331#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800332
Weidong Han1ce28fe2008-12-08 16:35:39 +0800333/* domain represents a virtual machine, more than one devices
334 * across iommus may be owned in one domain, e.g. kvm guest.
335 */
336#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
337
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700338/* si_domain contains mulitple devices */
339#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
340
Mark McLoughlin99126f72008-11-20 15:49:47 +0000341struct dmar_domain {
342 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700343 int nid; /* node id */
Weidong Han8c11e792008-12-08 15:29:22 +0800344 unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000345
346 struct list_head devices; /* all devices' list */
347 struct iova_domain iovad; /* iova's that belong to this domain */
348
349 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000350 int gaw; /* max guest address width */
351
352 /* adjusted guest address width, 0 is level 2 30-bit */
353 int agaw;
354
Weidong Han3b5410e2008-12-08 09:17:15 +0800355 int flags; /* flags to find out type of domain */
Weidong Han8e604092008-12-08 15:49:06 +0800356
357 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800358 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800359 int iommu_count; /* reference count of iommu */
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100360 int iommu_superpage;/* Level of superpages supported:
361 0 == 4KiB (no superpages), 1 == 2MiB,
362 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
Weidong Hanc7151a82008-12-08 22:51:37 +0800363 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800364 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000365};
366
Mark McLoughlina647dac2008-11-20 15:49:48 +0000367/* PCI domain-device relationship */
368struct device_domain_info {
369 struct list_head link; /* link to domain siblings */
370 struct list_head global; /* link to global list */
David Woodhouse276dbf92009-04-04 01:45:37 +0100371 int segment; /* PCI domain */
372 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000373 u8 devfn; /* PCI devfn number */
Stefan Assmann45e829e2009-12-03 06:49:24 -0500374 struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800375 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000376 struct dmar_domain *domain; /* pointer to domain */
377};
378
mark gross5e0d2a62008-03-04 15:22:08 -0800379static void flush_unmaps_timeout(unsigned long data);
380
381DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
382
mark gross80b20dd2008-04-18 13:53:58 -0700383#define HIGH_WATER_MARK 250
384struct deferred_flush_tables {
385 int next;
386 struct iova *iova[HIGH_WATER_MARK];
387 struct dmar_domain *domain[HIGH_WATER_MARK];
388};
389
390static struct deferred_flush_tables *deferred_flush;
391
mark gross5e0d2a62008-03-04 15:22:08 -0800392/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800393static int g_num_of_iommus;
394
395static DEFINE_SPINLOCK(async_umap_flush_lock);
396static LIST_HEAD(unmaps_to_do);
397
398static int timer_on;
399static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800400
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700401static void domain_remove_dev_info(struct dmar_domain *domain);
402
Suresh Siddhad3f13812011-08-23 17:05:25 -0700403#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800404int dmar_disabled = 0;
405#else
406int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700407#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800408
David Woodhouse2d9e6672010-06-15 10:57:57 +0100409static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700410static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800411static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100412static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700413
David Woodhousec0771df2011-10-14 20:59:46 +0100414int intel_iommu_gfx_mapped;
415EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
416
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700417#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
418static DEFINE_SPINLOCK(device_domain_lock);
419static LIST_HEAD(device_domain_list);
420
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100421static struct iommu_ops intel_iommu_ops;
422
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700423static int __init intel_iommu_setup(char *str)
424{
425 if (!str)
426 return -EINVAL;
427 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800428 if (!strncmp(str, "on", 2)) {
429 dmar_disabled = 0;
430 printk(KERN_INFO "Intel-IOMMU: enabled\n");
431 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700432 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800433 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700434 } else if (!strncmp(str, "igfx_off", 8)) {
435 dmar_map_gfx = 0;
436 printk(KERN_INFO
437 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700438 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800439 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700440 "Intel-IOMMU: Forcing DAC for PCI devices\n");
441 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800442 } else if (!strncmp(str, "strict", 6)) {
443 printk(KERN_INFO
444 "Intel-IOMMU: disable batched IOTLB flush\n");
445 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100446 } else if (!strncmp(str, "sp_off", 6)) {
447 printk(KERN_INFO
448 "Intel-IOMMU: disable supported super page\n");
449 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700450 }
451
452 str += strcspn(str, ",");
453 while (*str == ',')
454 str++;
455 }
456 return 0;
457}
458__setup("intel_iommu=", intel_iommu_setup);
459
460static struct kmem_cache *iommu_domain_cache;
461static struct kmem_cache *iommu_devinfo_cache;
462static struct kmem_cache *iommu_iova_cache;
463
Suresh Siddha4c923d42009-10-02 11:01:24 -0700464static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700465{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700466 struct page *page;
467 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700468
Suresh Siddha4c923d42009-10-02 11:01:24 -0700469 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
470 if (page)
471 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700472 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700473}
474
475static inline void free_pgtable_page(void *vaddr)
476{
477 free_page((unsigned long)vaddr);
478}
479
480static inline void *alloc_domain_mem(void)
481{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900482 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700483}
484
Kay, Allen M38717942008-09-09 18:37:29 +0300485static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700486{
487 kmem_cache_free(iommu_domain_cache, vaddr);
488}
489
490static inline void * alloc_devinfo_mem(void)
491{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900492 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700493}
494
495static inline void free_devinfo_mem(void *vaddr)
496{
497 kmem_cache_free(iommu_devinfo_cache, vaddr);
498}
499
500struct iova *alloc_iova_mem(void)
501{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900502 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700503}
504
505void free_iova_mem(struct iova *iova)
506{
507 kmem_cache_free(iommu_iova_cache, iova);
508}
509
Weidong Han1b573682008-12-08 15:34:06 +0800510
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700511static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800512{
513 unsigned long sagaw;
514 int agaw = -1;
515
516 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700517 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800518 agaw >= 0; agaw--) {
519 if (test_bit(agaw, &sagaw))
520 break;
521 }
522
523 return agaw;
524}
525
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700526/*
527 * Calculate max SAGAW for each iommu.
528 */
529int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
530{
531 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
532}
533
534/*
535 * calculate agaw for each iommu.
536 * "SAGAW" may be different across iommus, use a default agaw, and
537 * get a supported less agaw for iommus that don't support the default agaw.
538 */
539int iommu_calculate_agaw(struct intel_iommu *iommu)
540{
541 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
542}
543
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700544/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800545static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
546{
547 int iommu_id;
548
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700549 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800550 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700551 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800552
Weidong Han8c11e792008-12-08 15:29:22 +0800553 iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
554 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
555 return NULL;
556
557 return g_iommus[iommu_id];
558}
559
Weidong Han8e604092008-12-08 15:49:06 +0800560static void domain_update_iommu_coherency(struct dmar_domain *domain)
561{
562 int i;
563
564 domain->iommu_coherency = 1;
565
Akinobu Mitaa45946a2010-03-11 14:04:08 -0800566 for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e604092008-12-08 15:49:06 +0800567 if (!ecap_coherent(g_iommus[i]->ecap)) {
568 domain->iommu_coherency = 0;
569 break;
570 }
Weidong Han8e604092008-12-08 15:49:06 +0800571 }
572}
573
Sheng Yang58c610b2009-03-18 15:33:05 +0800574static void domain_update_iommu_snooping(struct dmar_domain *domain)
575{
576 int i;
577
578 domain->iommu_snooping = 1;
579
Akinobu Mitaa45946a2010-03-11 14:04:08 -0800580 for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800581 if (!ecap_sc_support(g_iommus[i]->ecap)) {
582 domain->iommu_snooping = 0;
583 break;
584 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800585 }
586}
587
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100588static void domain_update_iommu_superpage(struct dmar_domain *domain)
589{
Allen Kay8140a952011-10-14 12:32:17 -0700590 struct dmar_drhd_unit *drhd;
591 struct intel_iommu *iommu = NULL;
592 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100593
594 if (!intel_iommu_superpage) {
595 domain->iommu_superpage = 0;
596 return;
597 }
598
Allen Kay8140a952011-10-14 12:32:17 -0700599 /* set iommu_superpage to the smallest common denominator */
600 for_each_active_iommu(iommu, drhd) {
601 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100602 if (!mask) {
603 break;
604 }
605 }
606 domain->iommu_superpage = fls(mask);
607}
608
Sheng Yang58c610b2009-03-18 15:33:05 +0800609/* Some capabilities may be different across iommus */
610static void domain_update_iommu_cap(struct dmar_domain *domain)
611{
612 domain_update_iommu_coherency(domain);
613 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100614 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800615}
616
David Woodhouse276dbf92009-04-04 01:45:37 +0100617static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800618{
619 struct dmar_drhd_unit *drhd = NULL;
620 int i;
621
622 for_each_drhd_unit(drhd) {
623 if (drhd->ignored)
624 continue;
David Woodhouse276dbf92009-04-04 01:45:37 +0100625 if (segment != drhd->segment)
626 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800627
David Woodhouse924b6232009-04-04 00:39:25 +0100628 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000629 if (drhd->devices[i] &&
630 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800631 drhd->devices[i]->devfn == devfn)
632 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700633 if (drhd->devices[i] &&
634 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100635 drhd->devices[i]->subordinate->number <= bus &&
636 drhd->devices[i]->subordinate->subordinate >= bus)
637 return drhd->iommu;
638 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800639
640 if (drhd->include_all)
641 return drhd->iommu;
642 }
643
644 return NULL;
645}
646
Weidong Han5331fe62008-12-08 23:00:00 +0800647static void domain_flush_cache(struct dmar_domain *domain,
648 void *addr, int size)
649{
650 if (!domain->iommu_coherency)
651 clflush_cache_range(addr, size);
652}
653
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700654/* Gets context entry for a given bus and devfn */
655static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
656 u8 bus, u8 devfn)
657{
658 struct root_entry *root;
659 struct context_entry *context;
660 unsigned long phy_addr;
661 unsigned long flags;
662
663 spin_lock_irqsave(&iommu->lock, flags);
664 root = &iommu->root_entry[bus];
665 context = get_context_addr_from_root(root);
666 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700667 context = (struct context_entry *)
668 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700669 if (!context) {
670 spin_unlock_irqrestore(&iommu->lock, flags);
671 return NULL;
672 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700673 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700674 phy_addr = virt_to_phys((void *)context);
675 set_root_value(root, phy_addr);
676 set_root_present(root);
677 __iommu_flush_cache(iommu, root, sizeof(*root));
678 }
679 spin_unlock_irqrestore(&iommu->lock, flags);
680 return &context[devfn];
681}
682
683static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
684{
685 struct root_entry *root;
686 struct context_entry *context;
687 int ret;
688 unsigned long flags;
689
690 spin_lock_irqsave(&iommu->lock, flags);
691 root = &iommu->root_entry[bus];
692 context = get_context_addr_from_root(root);
693 if (!context) {
694 ret = 0;
695 goto out;
696 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000697 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700698out:
699 spin_unlock_irqrestore(&iommu->lock, flags);
700 return ret;
701}
702
703static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
704{
705 struct root_entry *root;
706 struct context_entry *context;
707 unsigned long flags;
708
709 spin_lock_irqsave(&iommu->lock, flags);
710 root = &iommu->root_entry[bus];
711 context = get_context_addr_from_root(root);
712 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000713 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700714 __iommu_flush_cache(iommu, &context[devfn], \
715 sizeof(*context));
716 }
717 spin_unlock_irqrestore(&iommu->lock, flags);
718}
719
720static void free_context_table(struct intel_iommu *iommu)
721{
722 struct root_entry *root;
723 int i;
724 unsigned long flags;
725 struct context_entry *context;
726
727 spin_lock_irqsave(&iommu->lock, flags);
728 if (!iommu->root_entry) {
729 goto out;
730 }
731 for (i = 0; i < ROOT_ENTRY_NR; i++) {
732 root = &iommu->root_entry[i];
733 context = get_context_addr_from_root(root);
734 if (context)
735 free_pgtable_page(context);
736 }
737 free_pgtable_page(iommu->root_entry);
738 iommu->root_entry = NULL;
739out:
740 spin_unlock_irqrestore(&iommu->lock, flags);
741}
742
David Woodhouseb026fd22009-06-28 10:37:25 +0100743static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
Allen Kay4399c8b2011-10-14 12:32:46 -0700744 unsigned long pfn, int target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700745{
David Woodhouseb026fd22009-06-28 10:37:25 +0100746 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700747 struct dma_pte *parent, *pte = NULL;
748 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700749 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700750
751 BUG_ON(!domain->pgd);
David Woodhouseb026fd22009-06-28 10:37:25 +0100752 BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700753 parent = domain->pgd;
754
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700755 while (level > 0) {
756 void *tmp_page;
757
David Woodhouseb026fd22009-06-28 10:37:25 +0100758 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700759 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700760 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100761 break;
762 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700763 break;
764
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000765 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100766 uint64_t pteval;
767
Suresh Siddha4c923d42009-10-02 11:01:24 -0700768 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700769
David Woodhouse206a73c2009-07-01 19:30:28 +0100770 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700771 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100772
David Woodhousec85994e2009-07-01 19:21:24 +0100773 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400774 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 +0100775 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
776 /* Someone else set it while we were thinking; use theirs. */
777 free_pgtable_page(tmp_page);
778 } else {
779 dma_pte_addr(pte);
780 domain_flush_cache(domain, pte, sizeof(*pte));
781 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700782 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000783 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700784 level--;
785 }
786
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700787 return pte;
788}
789
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100790
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700791/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100792static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
793 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100794 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700795{
796 struct dma_pte *parent, *pte = NULL;
797 int total = agaw_to_level(domain->agaw);
798 int offset;
799
800 parent = domain->pgd;
801 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100802 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700803 pte = &parent[offset];
804 if (level == total)
805 return pte;
806
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100807 if (!dma_pte_present(pte)) {
808 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700809 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100810 }
811
812 if (pte->val & DMA_PTE_LARGE_PAGE) {
813 *large_page = total;
814 return pte;
815 }
816
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000817 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700818 total--;
819 }
820 return NULL;
821}
822
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700823/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700824static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100825 unsigned long start_pfn,
826 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700827{
David Woodhouse04b18e62009-06-27 19:15:01 +0100828 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100829 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100830 struct dma_pte *first_pte, *pte;
Allen Kay292827c2011-10-14 12:31:54 -0700831 int order;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700832
David Woodhouse04b18e62009-06-27 19:15:01 +0100833 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100834 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700835 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100836
David Woodhouse04b18e62009-06-27 19:15:01 +0100837 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700838 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100839 large_page = 1;
840 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100841 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100842 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100843 continue;
844 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100845 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100846 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100847 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100848 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100849 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
850
David Woodhouse310a5ab2009-06-28 18:52:20 +0100851 domain_flush_cache(domain, first_pte,
852 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700853
854 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700855
856 order = (large_page - 1) * 9;
857 return order;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700858}
859
860/* free page table pages. last level pte should already be cleared */
861static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100862 unsigned long start_pfn,
863 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700864{
David Woodhouse6660c632009-06-27 22:41:00 +0100865 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhousef3a0a522009-06-30 03:40:07 +0100866 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700867 int total = agaw_to_level(domain->agaw);
868 int level;
David Woodhouse6660c632009-06-27 22:41:00 +0100869 unsigned long tmp;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100870 int large_page = 2;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700871
David Woodhouse6660c632009-06-27 22:41:00 +0100872 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
873 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700874 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700875
David Woodhousef3a0a522009-06-30 03:40:07 +0100876 /* We don't need lock here; nobody else touches the iova range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700877 level = 2;
878 while (level <= total) {
David Woodhouse6660c632009-06-27 22:41:00 +0100879 tmp = align_to_level(start_pfn, level);
880
David Woodhousef3a0a522009-06-30 03:40:07 +0100881 /* If we can't even clear one PTE at this level, we're done */
David Woodhouse6660c632009-06-27 22:41:00 +0100882 if (tmp + level_size(level) - 1 > last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700883 return;
884
David Woodhouse59c36282009-09-19 07:36:28 -0700885 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100886 large_page = level;
887 first_pte = pte = dma_pfn_level_pte(domain, tmp, level, &large_page);
888 if (large_page > level)
889 level = large_page + 1;
David Woodhousef3a0a522009-06-30 03:40:07 +0100890 if (!pte) {
891 tmp = align_to_level(tmp + 1, level + 1);
892 continue;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700893 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100894 do {
David Woodhouse6a43e572009-07-02 12:02:34 +0100895 if (dma_pte_present(pte)) {
896 free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
897 dma_clear_pte(pte);
898 }
David Woodhousef3a0a522009-06-30 03:40:07 +0100899 pte++;
900 tmp += level_size(level);
David Woodhouse75e6bf92009-07-02 11:21:16 +0100901 } while (!first_pte_in_page(pte) &&
902 tmp + level_size(level) - 1 <= last_pfn);
903
David Woodhousef3a0a522009-06-30 03:40:07 +0100904 domain_flush_cache(domain, first_pte,
905 (void *)pte - (void *)first_pte);
906
David Woodhouse59c36282009-09-19 07:36:28 -0700907 } while (tmp && tmp + level_size(level) - 1 <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700908 level++;
909 }
910 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100911 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700912 free_pgtable_page(domain->pgd);
913 domain->pgd = NULL;
914 }
915}
916
917/* iommu handling */
918static int iommu_alloc_root_entry(struct intel_iommu *iommu)
919{
920 struct root_entry *root;
921 unsigned long flags;
922
Suresh Siddha4c923d42009-10-02 11:01:24 -0700923 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700924 if (!root)
925 return -ENOMEM;
926
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700927 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700928
929 spin_lock_irqsave(&iommu->lock, flags);
930 iommu->root_entry = root;
931 spin_unlock_irqrestore(&iommu->lock, flags);
932
933 return 0;
934}
935
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700936static void iommu_set_root_entry(struct intel_iommu *iommu)
937{
938 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100939 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700940 unsigned long flag;
941
942 addr = iommu->root_entry;
943
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200944 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700945 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
946
David Woodhousec416daa2009-05-10 20:30:58 +0100947 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700948
949 /* Make sure hardware complete it */
950 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100951 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700952
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200953 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700954}
955
956static void iommu_flush_write_buffer(struct intel_iommu *iommu)
957{
958 u32 val;
959 unsigned long flag;
960
David Woodhouse9af88142009-02-13 23:18:03 +0000961 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700962 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700963
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200964 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100965 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700966
967 /* Make sure hardware complete it */
968 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100969 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700970
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200971 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700972}
973
974/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +0100975static void __iommu_flush_context(struct intel_iommu *iommu,
976 u16 did, u16 source_id, u8 function_mask,
977 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700978{
979 u64 val = 0;
980 unsigned long flag;
981
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700982 switch (type) {
983 case DMA_CCMD_GLOBAL_INVL:
984 val = DMA_CCMD_GLOBAL_INVL;
985 break;
986 case DMA_CCMD_DOMAIN_INVL:
987 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
988 break;
989 case DMA_CCMD_DEVICE_INVL:
990 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
991 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
992 break;
993 default:
994 BUG();
995 }
996 val |= DMA_CCMD_ICC;
997
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200998 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700999 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1000
1001 /* Make sure hardware complete it */
1002 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1003 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1004
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001005 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001006}
1007
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001008/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001009static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1010 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001011{
1012 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1013 u64 val = 0, val_iva = 0;
1014 unsigned long flag;
1015
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001016 switch (type) {
1017 case DMA_TLB_GLOBAL_FLUSH:
1018 /* global flush doesn't need set IVA_REG */
1019 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1020 break;
1021 case DMA_TLB_DSI_FLUSH:
1022 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1023 break;
1024 case DMA_TLB_PSI_FLUSH:
1025 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1026 /* Note: always flush non-leaf currently */
1027 val_iva = size_order | addr;
1028 break;
1029 default:
1030 BUG();
1031 }
1032 /* Note: set drain read/write */
1033#if 0
1034 /*
1035 * This is probably to be super secure.. Looks like we can
1036 * ignore it without any impact.
1037 */
1038 if (cap_read_drain(iommu->cap))
1039 val |= DMA_TLB_READ_DRAIN;
1040#endif
1041 if (cap_write_drain(iommu->cap))
1042 val |= DMA_TLB_WRITE_DRAIN;
1043
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001044 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001045 /* Note: Only uses first TLB reg currently */
1046 if (val_iva)
1047 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1048 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1049
1050 /* Make sure hardware complete it */
1051 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1052 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1053
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001054 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001055
1056 /* check IOTLB invalidation granularity */
1057 if (DMA_TLB_IAIG(val) == 0)
1058 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1059 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1060 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001061 (unsigned long long)DMA_TLB_IIRG(type),
1062 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001063}
1064
Yu Zhao93a23a72009-05-18 13:51:37 +08001065static struct device_domain_info *iommu_support_dev_iotlb(
1066 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001067{
Yu Zhao93a23a72009-05-18 13:51:37 +08001068 int found = 0;
1069 unsigned long flags;
1070 struct device_domain_info *info;
1071 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1072
1073 if (!ecap_dev_iotlb_support(iommu->ecap))
1074 return NULL;
1075
1076 if (!iommu->qi)
1077 return NULL;
1078
1079 spin_lock_irqsave(&device_domain_lock, flags);
1080 list_for_each_entry(info, &domain->devices, link)
1081 if (info->bus == bus && info->devfn == devfn) {
1082 found = 1;
1083 break;
1084 }
1085 spin_unlock_irqrestore(&device_domain_lock, flags);
1086
1087 if (!found || !info->dev)
1088 return NULL;
1089
1090 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1091 return NULL;
1092
1093 if (!dmar_find_matched_atsr_unit(info->dev))
1094 return NULL;
1095
1096 info->iommu = iommu;
1097
1098 return info;
1099}
1100
1101static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1102{
1103 if (!info)
1104 return;
1105
1106 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1107}
1108
1109static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1110{
1111 if (!info->dev || !pci_ats_enabled(info->dev))
1112 return;
1113
1114 pci_disable_ats(info->dev);
1115}
1116
1117static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1118 u64 addr, unsigned mask)
1119{
1120 u16 sid, qdep;
1121 unsigned long flags;
1122 struct device_domain_info *info;
1123
1124 spin_lock_irqsave(&device_domain_lock, flags);
1125 list_for_each_entry(info, &domain->devices, link) {
1126 if (!info->dev || !pci_ats_enabled(info->dev))
1127 continue;
1128
1129 sid = info->bus << 8 | info->devfn;
1130 qdep = pci_ats_queue_depth(info->dev);
1131 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1132 }
1133 spin_unlock_irqrestore(&device_domain_lock, flags);
1134}
1135
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001136static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001137 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001138{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001139 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001140 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001141
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001142 BUG_ON(pages == 0);
1143
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001144 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001145 * Fallback to domain selective flush if no PSI support or the size is
1146 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001147 * PSI requires page size to be 2 ^ x, and the base address is naturally
1148 * aligned to the size
1149 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001150 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1151 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001152 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001153 else
1154 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1155 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001156
1157 /*
Nadav Amit82653632010-04-01 13:24:40 +03001158 * In caching mode, changes of pages from non-present to present require
1159 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001160 */
Nadav Amit82653632010-04-01 13:24:40 +03001161 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001162 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001163}
1164
mark grossf8bab732008-02-08 04:18:38 -08001165static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1166{
1167 u32 pmen;
1168 unsigned long flags;
1169
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001170 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001171 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1172 pmen &= ~DMA_PMEN_EPM;
1173 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1174
1175 /* wait for the protected region status bit to clear */
1176 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1177 readl, !(pmen & DMA_PMEN_PRS), pmen);
1178
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001179 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001180}
1181
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001182static int iommu_enable_translation(struct intel_iommu *iommu)
1183{
1184 u32 sts;
1185 unsigned long flags;
1186
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001187 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001188 iommu->gcmd |= DMA_GCMD_TE;
1189 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001190
1191 /* Make sure hardware complete it */
1192 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001193 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001194
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001195 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001196 return 0;
1197}
1198
1199static int iommu_disable_translation(struct intel_iommu *iommu)
1200{
1201 u32 sts;
1202 unsigned long flag;
1203
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001204 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001205 iommu->gcmd &= ~DMA_GCMD_TE;
1206 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1207
1208 /* Make sure hardware complete it */
1209 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001210 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001211
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001212 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001213 return 0;
1214}
1215
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001216
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001217static int iommu_init_domains(struct intel_iommu *iommu)
1218{
1219 unsigned long ndomains;
1220 unsigned long nlongs;
1221
1222 ndomains = cap_ndoms(iommu->cap);
Yinghai Lu680a7522010-04-08 19:58:23 +01001223 pr_debug("IOMMU %d: Number of Domains supportd <%ld>\n", iommu->seq_id,
1224 ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001225 nlongs = BITS_TO_LONGS(ndomains);
1226
Donald Dutile94a91b52009-08-20 16:51:34 -04001227 spin_lock_init(&iommu->lock);
1228
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001229 /* TBD: there might be 64K domains,
1230 * consider other allocation for future chip
1231 */
1232 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1233 if (!iommu->domain_ids) {
1234 printk(KERN_ERR "Allocating domain id array failed\n");
1235 return -ENOMEM;
1236 }
1237 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1238 GFP_KERNEL);
1239 if (!iommu->domains) {
1240 printk(KERN_ERR "Allocating domain array failed\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001241 return -ENOMEM;
1242 }
1243
1244 /*
1245 * if Caching mode is set, then invalid translations are tagged
1246 * with domainid 0. Hence we need to pre-allocate it.
1247 */
1248 if (cap_caching_mode(iommu->cap))
1249 set_bit(0, iommu->domain_ids);
1250 return 0;
1251}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001252
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001253
1254static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001255static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001256
1257void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001258{
1259 struct dmar_domain *domain;
1260 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001261 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001262
Donald Dutile94a91b52009-08-20 16:51:34 -04001263 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001264 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001265 domain = iommu->domains[i];
1266 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001267
Donald Dutile94a91b52009-08-20 16:51:34 -04001268 spin_lock_irqsave(&domain->iommu_lock, flags);
1269 if (--domain->iommu_count == 0) {
1270 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1271 vm_domain_exit(domain);
1272 else
1273 domain_exit(domain);
1274 }
1275 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001276 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001277 }
1278
1279 if (iommu->gcmd & DMA_GCMD_TE)
1280 iommu_disable_translation(iommu);
1281
1282 if (iommu->irq) {
Thomas Gleixnerdced35a2011-03-28 17:49:12 +02001283 irq_set_handler_data(iommu->irq, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001284 /* This will mask the irq */
1285 free_irq(iommu->irq, iommu);
1286 destroy_irq(iommu->irq);
1287 }
1288
1289 kfree(iommu->domains);
1290 kfree(iommu->domain_ids);
1291
Weidong Hand9630fe2008-12-08 11:06:32 +08001292 g_iommus[iommu->seq_id] = NULL;
1293
1294 /* if all iommus are freed, free g_iommus */
1295 for (i = 0; i < g_num_of_iommus; i++) {
1296 if (g_iommus[i])
1297 break;
1298 }
1299
1300 if (i == g_num_of_iommus)
1301 kfree(g_iommus);
1302
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001303 /* free context mapping */
1304 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001305}
1306
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001307static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001308{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001309 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001310
1311 domain = alloc_domain_mem();
1312 if (!domain)
1313 return NULL;
1314
Suresh Siddha4c923d42009-10-02 11:01:24 -07001315 domain->nid = -1;
Weidong Han8c11e792008-12-08 15:29:22 +08001316 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
Weidong Hand71a2f32008-12-07 21:13:41 +08001317 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001318
1319 return domain;
1320}
1321
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001322static int iommu_attach_domain(struct dmar_domain *domain,
1323 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001324{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001325 int num;
1326 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001327 unsigned long flags;
1328
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001329 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001330
1331 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001332
1333 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1334 if (num >= ndomains) {
1335 spin_unlock_irqrestore(&iommu->lock, flags);
1336 printk(KERN_ERR "IOMMU: no free domain ids\n");
1337 return -ENOMEM;
1338 }
1339
1340 domain->id = num;
1341 set_bit(num, iommu->domain_ids);
1342 set_bit(iommu->seq_id, &domain->iommu_bmp);
1343 iommu->domains[num] = domain;
1344 spin_unlock_irqrestore(&iommu->lock, flags);
1345
1346 return 0;
1347}
1348
1349static void iommu_detach_domain(struct dmar_domain *domain,
1350 struct intel_iommu *iommu)
1351{
1352 unsigned long flags;
1353 int num, ndomains;
1354 int found = 0;
1355
1356 spin_lock_irqsave(&iommu->lock, flags);
1357 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001358 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001359 if (iommu->domains[num] == domain) {
1360 found = 1;
1361 break;
1362 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001363 }
1364
1365 if (found) {
1366 clear_bit(num, iommu->domain_ids);
1367 clear_bit(iommu->seq_id, &domain->iommu_bmp);
1368 iommu->domains[num] = NULL;
1369 }
Weidong Han8c11e792008-12-08 15:29:22 +08001370 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001371}
1372
1373static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001374static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001375
Joseph Cihula51a63e62011-03-21 11:04:24 -07001376static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001377{
1378 struct pci_dev *pdev = NULL;
1379 struct iova *iova;
1380 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001381
David Millerf6611972008-02-06 01:36:23 -08001382 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001383
Mark Gross8a443df2008-03-04 14:59:31 -08001384 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1385 &reserved_rbtree_key);
1386
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001387 /* IOAPIC ranges shouldn't be accessed by DMA */
1388 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1389 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001390 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001391 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001392 return -ENODEV;
1393 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001394
1395 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1396 for_each_pci_dev(pdev) {
1397 struct resource *r;
1398
1399 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1400 r = &pdev->resource[i];
1401 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1402 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001403 iova = reserve_iova(&reserved_iova_list,
1404 IOVA_PFN(r->start),
1405 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001406 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001407 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001408 return -ENODEV;
1409 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001410 }
1411 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001412 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001413}
1414
1415static void domain_reserve_special_ranges(struct dmar_domain *domain)
1416{
1417 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1418}
1419
1420static inline int guestwidth_to_adjustwidth(int gaw)
1421{
1422 int agaw;
1423 int r = (gaw - 12) % 9;
1424
1425 if (r == 0)
1426 agaw = gaw;
1427 else
1428 agaw = gaw + 9 - r;
1429 if (agaw > 64)
1430 agaw = 64;
1431 return agaw;
1432}
1433
1434static int domain_init(struct dmar_domain *domain, int guest_width)
1435{
1436 struct intel_iommu *iommu;
1437 int adjust_width, agaw;
1438 unsigned long sagaw;
1439
David Millerf6611972008-02-06 01:36:23 -08001440 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001441 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001442
1443 domain_reserve_special_ranges(domain);
1444
1445 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001446 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001447 if (guest_width > cap_mgaw(iommu->cap))
1448 guest_width = cap_mgaw(iommu->cap);
1449 domain->gaw = guest_width;
1450 adjust_width = guestwidth_to_adjustwidth(guest_width);
1451 agaw = width_to_agaw(adjust_width);
1452 sagaw = cap_sagaw(iommu->cap);
1453 if (!test_bit(agaw, &sagaw)) {
1454 /* hardware doesn't support it, choose a bigger one */
1455 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1456 agaw = find_next_bit(&sagaw, 5, agaw);
1457 if (agaw >= 5)
1458 return -ENODEV;
1459 }
1460 domain->agaw = agaw;
1461 INIT_LIST_HEAD(&domain->devices);
1462
Weidong Han8e604092008-12-08 15:49:06 +08001463 if (ecap_coherent(iommu->ecap))
1464 domain->iommu_coherency = 1;
1465 else
1466 domain->iommu_coherency = 0;
1467
Sheng Yang58c610b2009-03-18 15:33:05 +08001468 if (ecap_sc_support(iommu->ecap))
1469 domain->iommu_snooping = 1;
1470 else
1471 domain->iommu_snooping = 0;
1472
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001473 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Weidong Hanc7151a82008-12-08 22:51:37 +08001474 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001475 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001476
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001477 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001478 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001479 if (!domain->pgd)
1480 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001481 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001482 return 0;
1483}
1484
1485static void domain_exit(struct dmar_domain *domain)
1486{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001487 struct dmar_drhd_unit *drhd;
1488 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001489
1490 /* Domain 0 is reserved, so dont process it */
1491 if (!domain)
1492 return;
1493
Alex Williamson7b668352011-05-24 12:02:41 +01001494 /* Flush any lazy unmaps that may reference this domain */
1495 if (!intel_iommu_strict)
1496 flush_unmaps_timeout(0);
1497
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001498 domain_remove_dev_info(domain);
1499 /* destroy iovas */
1500 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001501
1502 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001503 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001504
1505 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001506 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001507
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001508 for_each_active_iommu(iommu, drhd)
1509 if (test_bit(iommu->seq_id, &domain->iommu_bmp))
1510 iommu_detach_domain(domain, iommu);
1511
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001512 free_domain_mem(domain);
1513}
1514
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001515static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1516 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001517{
1518 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001519 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001520 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001521 struct dma_pte *pgd;
1522 unsigned long num;
1523 unsigned long ndomains;
1524 int id;
1525 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001526 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001527
1528 pr_debug("Set context mapping for %02x:%02x.%d\n",
1529 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001530
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001531 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001532 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1533 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001534
David Woodhouse276dbf92009-04-04 01:45:37 +01001535 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001536 if (!iommu)
1537 return -ENODEV;
1538
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001539 context = device_to_context_entry(iommu, bus, devfn);
1540 if (!context)
1541 return -ENOMEM;
1542 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001543 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001544 spin_unlock_irqrestore(&iommu->lock, flags);
1545 return 0;
1546 }
1547
Weidong Hanea6606b2008-12-08 23:08:15 +08001548 id = domain->id;
1549 pgd = domain->pgd;
1550
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001551 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1552 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001553 int found = 0;
1554
1555 /* find an available domain id for this device in iommu */
1556 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001557 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001558 if (iommu->domains[num] == domain) {
1559 id = num;
1560 found = 1;
1561 break;
1562 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001563 }
1564
1565 if (found == 0) {
1566 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1567 if (num >= ndomains) {
1568 spin_unlock_irqrestore(&iommu->lock, flags);
1569 printk(KERN_ERR "IOMMU: no free domain ids\n");
1570 return -EFAULT;
1571 }
1572
1573 set_bit(num, iommu->domain_ids);
1574 iommu->domains[num] = domain;
1575 id = num;
1576 }
1577
1578 /* Skip top levels of page tables for
1579 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001580 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001581 */
Chris Wright1672af12009-12-02 12:06:34 -08001582 if (translation != CONTEXT_TT_PASS_THROUGH) {
1583 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1584 pgd = phys_to_virt(dma_pte_addr(pgd));
1585 if (!dma_pte_present(pgd)) {
1586 spin_unlock_irqrestore(&iommu->lock, flags);
1587 return -ENOMEM;
1588 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001589 }
1590 }
1591 }
1592
1593 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001594
Yu Zhao93a23a72009-05-18 13:51:37 +08001595 if (translation != CONTEXT_TT_PASS_THROUGH) {
1596 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1597 translation = info ? CONTEXT_TT_DEV_IOTLB :
1598 CONTEXT_TT_MULTI_LEVEL;
1599 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001600 /*
1601 * In pass through mode, AW must be programmed to indicate the largest
1602 * AGAW value supported by hardware. And ASR is ignored by hardware.
1603 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001604 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001605 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001606 else {
1607 context_set_address_root(context, virt_to_phys(pgd));
1608 context_set_address_width(context, iommu->agaw);
1609 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001610
1611 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001612 context_set_fault_enable(context);
1613 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001614 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001615
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001616 /*
1617 * It's a non-present to present mapping. If hardware doesn't cache
1618 * non-present entry we only need to flush the write-buffer. If the
1619 * _does_ cache non-present entries, then it does so in the special
1620 * domain #0, which we have to flush:
1621 */
1622 if (cap_caching_mode(iommu->cap)) {
1623 iommu->flush.flush_context(iommu, 0,
1624 (((u16)bus) << 8) | devfn,
1625 DMA_CCMD_MASK_NOBIT,
1626 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001627 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001628 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001629 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001630 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001631 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001632 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001633
1634 spin_lock_irqsave(&domain->iommu_lock, flags);
1635 if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
1636 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001637 if (domain->iommu_count == 1)
1638 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001639 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001640 }
1641 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001642 return 0;
1643}
1644
1645static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001646domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1647 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001648{
1649 int ret;
1650 struct pci_dev *tmp, *parent;
1651
David Woodhouse276dbf92009-04-04 01:45:37 +01001652 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001653 pdev->bus->number, pdev->devfn,
1654 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001655 if (ret)
1656 return ret;
1657
1658 /* dependent device mapping */
1659 tmp = pci_find_upstream_pcie_bridge(pdev);
1660 if (!tmp)
1661 return 0;
1662 /* Secondary interface's bus number and devfn 0 */
1663 parent = pdev->bus->self;
1664 while (parent != tmp) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001665 ret = domain_context_mapping_one(domain,
1666 pci_domain_nr(parent->bus),
1667 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001668 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001669 if (ret)
1670 return ret;
1671 parent = parent->bus->self;
1672 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001673 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001674 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001675 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001676 tmp->subordinate->number, 0,
1677 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001678 else /* this is a legacy PCI bridge */
1679 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001680 pci_domain_nr(tmp->bus),
1681 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001682 tmp->devfn,
1683 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001684}
1685
Weidong Han5331fe62008-12-08 23:00:00 +08001686static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001687{
1688 int ret;
1689 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001690 struct intel_iommu *iommu;
1691
David Woodhouse276dbf92009-04-04 01:45:37 +01001692 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1693 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001694 if (!iommu)
1695 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001696
David Woodhouse276dbf92009-04-04 01:45:37 +01001697 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001698 if (!ret)
1699 return ret;
1700 /* dependent device mapping */
1701 tmp = pci_find_upstream_pcie_bridge(pdev);
1702 if (!tmp)
1703 return ret;
1704 /* Secondary interface's bus number and devfn 0 */
1705 parent = pdev->bus->self;
1706 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001707 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01001708 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001709 if (!ret)
1710 return ret;
1711 parent = parent->bus->self;
1712 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001713 if (pci_is_pcie(tmp))
David Woodhouse276dbf92009-04-04 01:45:37 +01001714 return device_context_mapped(iommu, tmp->subordinate->number,
1715 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001716 else
David Woodhouse276dbf92009-04-04 01:45:37 +01001717 return device_context_mapped(iommu, tmp->bus->number,
1718 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001719}
1720
Fenghua Yuf5329592009-08-04 15:09:37 -07001721/* Returns a number of VTD pages, but aligned to MM page size */
1722static inline unsigned long aligned_nrpages(unsigned long host_addr,
1723 size_t size)
1724{
1725 host_addr &= ~PAGE_MASK;
1726 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1727}
1728
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001729/* Return largest possible superpage level for a given mapping */
1730static inline int hardware_largepage_caps(struct dmar_domain *domain,
1731 unsigned long iov_pfn,
1732 unsigned long phy_pfn,
1733 unsigned long pages)
1734{
1735 int support, level = 1;
1736 unsigned long pfnmerge;
1737
1738 support = domain->iommu_superpage;
1739
1740 /* To use a large page, the virtual *and* physical addresses
1741 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1742 of them will mean we have to use smaller pages. So just
1743 merge them and check both at once. */
1744 pfnmerge = iov_pfn | phy_pfn;
1745
1746 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1747 pages >>= VTD_STRIDE_SHIFT;
1748 if (!pages)
1749 break;
1750 pfnmerge >>= VTD_STRIDE_SHIFT;
1751 level++;
1752 support--;
1753 }
1754 return level;
1755}
1756
David Woodhouse9051aa02009-06-29 12:30:54 +01001757static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1758 struct scatterlist *sg, unsigned long phys_pfn,
1759 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001760{
1761 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001762 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001763 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001764 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001765 unsigned int largepage_lvl = 0;
1766 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001767
1768 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1769
1770 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1771 return -EINVAL;
1772
1773 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1774
David Woodhouse9051aa02009-06-29 12:30:54 +01001775 if (sg)
1776 sg_res = 0;
1777 else {
1778 sg_res = nr_pages + 1;
1779 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1780 }
1781
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001782 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001783 uint64_t tmp;
1784
David Woodhousee1605492009-06-29 11:17:38 +01001785 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001786 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001787 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1788 sg->dma_length = sg->length;
1789 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001790 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001791 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001792
David Woodhousee1605492009-06-29 11:17:38 +01001793 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001794 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1795
1796 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001797 if (!pte)
1798 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001799 /* It is large page*/
1800 if (largepage_lvl > 1)
1801 pteval |= DMA_PTE_LARGE_PAGE;
1802 else
1803 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
1804
David Woodhousee1605492009-06-29 11:17:38 +01001805 }
1806 /* We don't need lock here, nobody else
1807 * touches the iova range
1808 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001809 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001810 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001811 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001812 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1813 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001814 if (dumps) {
1815 dumps--;
1816 debug_dma_dump_mappings(NULL);
1817 }
1818 WARN_ON(1);
1819 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001820
1821 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1822
1823 BUG_ON(nr_pages < lvl_pages);
1824 BUG_ON(sg_res < lvl_pages);
1825
1826 nr_pages -= lvl_pages;
1827 iov_pfn += lvl_pages;
1828 phys_pfn += lvl_pages;
1829 pteval += lvl_pages * VTD_PAGE_SIZE;
1830 sg_res -= lvl_pages;
1831
1832 /* If the next PTE would be the first in a new page, then we
1833 need to flush the cache on the entries we've just written.
1834 And then we'll need to recalculate 'pte', so clear it and
1835 let it get set again in the if (!pte) block above.
1836
1837 If we're done (!nr_pages) we need to flush the cache too.
1838
1839 Also if we've been setting superpages, we may need to
1840 recalculate 'pte' and switch back to smaller pages for the
1841 end of the mapping, if the trailing size is not enough to
1842 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001843 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001844 if (!nr_pages || first_pte_in_page(pte) ||
1845 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001846 domain_flush_cache(domain, first_pte,
1847 (void *)pte - (void *)first_pte);
1848 pte = NULL;
1849 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001850
1851 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001852 sg = sg_next(sg);
1853 }
1854 return 0;
1855}
1856
David Woodhouse9051aa02009-06-29 12:30:54 +01001857static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1858 struct scatterlist *sg, unsigned long nr_pages,
1859 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001860{
David Woodhouse9051aa02009-06-29 12:30:54 +01001861 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1862}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001863
David Woodhouse9051aa02009-06-29 12:30:54 +01001864static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1865 unsigned long phys_pfn, unsigned long nr_pages,
1866 int prot)
1867{
1868 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001869}
1870
Weidong Hanc7151a82008-12-08 22:51:37 +08001871static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001872{
Weidong Hanc7151a82008-12-08 22:51:37 +08001873 if (!iommu)
1874 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001875
1876 clear_context_table(iommu, bus, devfn);
1877 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001878 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001879 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001880}
1881
1882static void domain_remove_dev_info(struct dmar_domain *domain)
1883{
1884 struct device_domain_info *info;
1885 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001886 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001887
1888 spin_lock_irqsave(&device_domain_lock, flags);
1889 while (!list_empty(&domain->devices)) {
1890 info = list_entry(domain->devices.next,
1891 struct device_domain_info, link);
1892 list_del(&info->link);
1893 list_del(&info->global);
1894 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001895 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001896 spin_unlock_irqrestore(&device_domain_lock, flags);
1897
Yu Zhao93a23a72009-05-18 13:51:37 +08001898 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01001899 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001900 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001901 free_devinfo_mem(info);
1902
1903 spin_lock_irqsave(&device_domain_lock, flags);
1904 }
1905 spin_unlock_irqrestore(&device_domain_lock, flags);
1906}
1907
1908/*
1909 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001910 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001911 */
Kay, Allen M38717942008-09-09 18:37:29 +03001912static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001913find_domain(struct pci_dev *pdev)
1914{
1915 struct device_domain_info *info;
1916
1917 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001918 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001919 if (info)
1920 return info->domain;
1921 return NULL;
1922}
1923
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001924/* domain is initialized */
1925static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1926{
1927 struct dmar_domain *domain, *found = NULL;
1928 struct intel_iommu *iommu;
1929 struct dmar_drhd_unit *drhd;
1930 struct device_domain_info *info, *tmp;
1931 struct pci_dev *dev_tmp;
1932 unsigned long flags;
1933 int bus = 0, devfn = 0;
David Woodhouse276dbf92009-04-04 01:45:37 +01001934 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001935 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001936
1937 domain = find_domain(pdev);
1938 if (domain)
1939 return domain;
1940
David Woodhouse276dbf92009-04-04 01:45:37 +01001941 segment = pci_domain_nr(pdev->bus);
1942
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001943 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1944 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001945 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001946 bus = dev_tmp->subordinate->number;
1947 devfn = 0;
1948 } else {
1949 bus = dev_tmp->bus->number;
1950 devfn = dev_tmp->devfn;
1951 }
1952 spin_lock_irqsave(&device_domain_lock, flags);
1953 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001954 if (info->segment == segment &&
1955 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001956 found = info->domain;
1957 break;
1958 }
1959 }
1960 spin_unlock_irqrestore(&device_domain_lock, flags);
1961 /* pcie-pci bridge already has a domain, uses it */
1962 if (found) {
1963 domain = found;
1964 goto found_domain;
1965 }
1966 }
1967
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001968 domain = alloc_domain();
1969 if (!domain)
1970 goto error;
1971
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001972 /* Allocate new domain for the device */
1973 drhd = dmar_find_matched_drhd_unit(pdev);
1974 if (!drhd) {
1975 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
1976 pci_name(pdev));
1977 return NULL;
1978 }
1979 iommu = drhd->iommu;
1980
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001981 ret = iommu_attach_domain(domain, iommu);
1982 if (ret) {
Alex Williamson2fe97232011-03-04 14:52:30 -07001983 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001984 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001985 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001986
1987 if (domain_init(domain, gaw)) {
1988 domain_exit(domain);
1989 goto error;
1990 }
1991
1992 /* register pcie-to-pci device */
1993 if (dev_tmp) {
1994 info = alloc_devinfo_mem();
1995 if (!info) {
1996 domain_exit(domain);
1997 goto error;
1998 }
David Woodhouse276dbf92009-04-04 01:45:37 +01001999 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002000 info->bus = bus;
2001 info->devfn = devfn;
2002 info->dev = NULL;
2003 info->domain = domain;
2004 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08002005 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002006
2007 /* pcie-to-pci bridge already has a domain, uses it */
2008 found = NULL;
2009 spin_lock_irqsave(&device_domain_lock, flags);
2010 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01002011 if (tmp->segment == segment &&
2012 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002013 found = tmp->domain;
2014 break;
2015 }
2016 }
2017 if (found) {
Jiri Slaby00dfff72010-06-14 17:17:32 +02002018 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002019 free_devinfo_mem(info);
2020 domain_exit(domain);
2021 domain = found;
2022 } else {
2023 list_add(&info->link, &domain->devices);
2024 list_add(&info->global, &device_domain_list);
Jiri Slaby00dfff72010-06-14 17:17:32 +02002025 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002026 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002027 }
2028
2029found_domain:
2030 info = alloc_devinfo_mem();
2031 if (!info)
2032 goto error;
David Woodhouse276dbf92009-04-04 01:45:37 +01002033 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002034 info->bus = pdev->bus->number;
2035 info->devfn = pdev->devfn;
2036 info->dev = pdev;
2037 info->domain = domain;
2038 spin_lock_irqsave(&device_domain_lock, flags);
2039 /* somebody is fast */
2040 found = find_domain(pdev);
2041 if (found != NULL) {
2042 spin_unlock_irqrestore(&device_domain_lock, flags);
2043 if (found != domain) {
2044 domain_exit(domain);
2045 domain = found;
2046 }
2047 free_devinfo_mem(info);
2048 return domain;
2049 }
2050 list_add(&info->link, &domain->devices);
2051 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002052 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002053 spin_unlock_irqrestore(&device_domain_lock, flags);
2054 return domain;
2055error:
2056 /* recheck it here, maybe others set it */
2057 return find_domain(pdev);
2058}
2059
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002060static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002061#define IDENTMAP_ALL 1
2062#define IDENTMAP_GFX 2
2063#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002064
David Woodhouseb2132032009-06-26 18:50:28 +01002065static int iommu_domain_identity_map(struct dmar_domain *domain,
2066 unsigned long long start,
2067 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002068{
David Woodhousec5395d52009-06-28 16:35:56 +01002069 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2070 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002071
David Woodhousec5395d52009-06-28 16:35:56 +01002072 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2073 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002074 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002075 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002076 }
2077
David Woodhousec5395d52009-06-28 16:35:56 +01002078 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2079 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002080 /*
2081 * RMRR range might have overlap with physical memory range,
2082 * clear it first
2083 */
David Woodhousec5395d52009-06-28 16:35:56 +01002084 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002085
David Woodhousec5395d52009-06-28 16:35:56 +01002086 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2087 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002088 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002089}
2090
2091static int iommu_prepare_identity_map(struct pci_dev *pdev,
2092 unsigned long long start,
2093 unsigned long long end)
2094{
2095 struct dmar_domain *domain;
2096 int ret;
2097
David Woodhousec7ab48d2009-06-26 19:10:36 +01002098 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002099 if (!domain)
2100 return -ENOMEM;
2101
David Woodhouse19943b02009-08-04 16:19:20 +01002102 /* For _hardware_ passthrough, don't bother. But for software
2103 passthrough, we do it anyway -- it may indicate a memory
2104 range which is reserved in E820, so which didn't get set
2105 up to start with in si_domain */
2106 if (domain == si_domain && hw_pass_through) {
2107 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2108 pci_name(pdev), start, end);
2109 return 0;
2110 }
2111
2112 printk(KERN_INFO
2113 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2114 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002115
David Woodhouse5595b522009-12-02 09:21:55 +00002116 if (end < start) {
2117 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2118 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2119 dmi_get_system_info(DMI_BIOS_VENDOR),
2120 dmi_get_system_info(DMI_BIOS_VERSION),
2121 dmi_get_system_info(DMI_PRODUCT_VERSION));
2122 ret = -EIO;
2123 goto error;
2124 }
2125
David Woodhouse2ff729f2009-08-26 14:25:41 +01002126 if (end >> agaw_to_width(domain->agaw)) {
2127 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2128 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2129 agaw_to_width(domain->agaw),
2130 dmi_get_system_info(DMI_BIOS_VENDOR),
2131 dmi_get_system_info(DMI_BIOS_VERSION),
2132 dmi_get_system_info(DMI_PRODUCT_VERSION));
2133 ret = -EIO;
2134 goto error;
2135 }
David Woodhouse19943b02009-08-04 16:19:20 +01002136
David Woodhouseb2132032009-06-26 18:50:28 +01002137 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002138 if (ret)
2139 goto error;
2140
2141 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002142 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002143 if (ret)
2144 goto error;
2145
2146 return 0;
2147
2148 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002149 domain_exit(domain);
2150 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002151}
2152
2153static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2154 struct pci_dev *pdev)
2155{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002156 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002157 return 0;
2158 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002159 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002160}
2161
Suresh Siddhad3f13812011-08-23 17:05:25 -07002162#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002163static inline void iommu_prepare_isa(void)
2164{
2165 struct pci_dev *pdev;
2166 int ret;
2167
2168 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2169 if (!pdev)
2170 return;
2171
David Woodhousec7ab48d2009-06-26 19:10:36 +01002172 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002173 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002174
2175 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002176 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2177 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002178
2179}
2180#else
2181static inline void iommu_prepare_isa(void)
2182{
2183 return;
2184}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002185#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002186
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002187static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002188
Matt Kraai071e1372009-08-23 22:30:22 -07002189static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002190{
2191 struct dmar_drhd_unit *drhd;
2192 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002193 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002194
2195 si_domain = alloc_domain();
2196 if (!si_domain)
2197 return -EFAULT;
2198
David Woodhousec7ab48d2009-06-26 19:10:36 +01002199 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002200
2201 for_each_active_iommu(iommu, drhd) {
2202 ret = iommu_attach_domain(si_domain, iommu);
2203 if (ret) {
2204 domain_exit(si_domain);
2205 return -EFAULT;
2206 }
2207 }
2208
2209 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2210 domain_exit(si_domain);
2211 return -EFAULT;
2212 }
2213
2214 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2215
David Woodhouse19943b02009-08-04 16:19:20 +01002216 if (hw)
2217 return 0;
2218
David Woodhousec7ab48d2009-06-26 19:10:36 +01002219 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002220 unsigned long start_pfn, end_pfn;
2221 int i;
2222
2223 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2224 ret = iommu_domain_identity_map(si_domain,
2225 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2226 if (ret)
2227 return ret;
2228 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002229 }
2230
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002231 return 0;
2232}
2233
2234static void domain_remove_one_dev_info(struct dmar_domain *domain,
2235 struct pci_dev *pdev);
2236static int identity_mapping(struct pci_dev *pdev)
2237{
2238 struct device_domain_info *info;
2239
2240 if (likely(!iommu_identity_mapping))
2241 return 0;
2242
Mike Traviscb452a42011-05-28 13:15:03 -05002243 info = pdev->dev.archdata.iommu;
2244 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2245 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002246
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002247 return 0;
2248}
2249
2250static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002251 struct pci_dev *pdev,
2252 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002253{
2254 struct device_domain_info *info;
2255 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002256 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002257
2258 info = alloc_devinfo_mem();
2259 if (!info)
2260 return -ENOMEM;
2261
David Woodhouse5fe60f42009-08-09 10:53:41 +01002262 ret = domain_context_mapping(domain, pdev, translation);
2263 if (ret) {
2264 free_devinfo_mem(info);
2265 return ret;
2266 }
2267
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002268 info->segment = pci_domain_nr(pdev->bus);
2269 info->bus = pdev->bus->number;
2270 info->devfn = pdev->devfn;
2271 info->dev = pdev;
2272 info->domain = domain;
2273
2274 spin_lock_irqsave(&device_domain_lock, flags);
2275 list_add(&info->link, &domain->devices);
2276 list_add(&info->global, &device_domain_list);
2277 pdev->dev.archdata.iommu = info;
2278 spin_unlock_irqrestore(&device_domain_lock, flags);
2279
2280 return 0;
2281}
2282
David Woodhouse6941af22009-07-04 18:24:27 +01002283static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2284{
David Woodhousee0fc7e02009-09-30 09:12:17 -07002285 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2286 return 1;
2287
2288 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2289 return 1;
2290
2291 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2292 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002293
David Woodhouse3dfc8132009-07-04 19:11:08 +01002294 /*
2295 * We want to start off with all devices in the 1:1 domain, and
2296 * take them out later if we find they can't access all of memory.
2297 *
2298 * However, we can't do this for PCI devices behind bridges,
2299 * because all PCI devices behind the same bridge will end up
2300 * with the same source-id on their transactions.
2301 *
2302 * Practically speaking, we can't change things around for these
2303 * devices at run-time, because we can't be sure there'll be no
2304 * DMA transactions in flight for any of their siblings.
2305 *
2306 * So PCI devices (unless they're on the root bus) as well as
2307 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2308 * the 1:1 domain, just in _case_ one of their siblings turns out
2309 * not to be able to map all of memory.
2310 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002311 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002312 if (!pci_is_root_bus(pdev->bus))
2313 return 0;
2314 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2315 return 0;
2316 } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
2317 return 0;
2318
2319 /*
2320 * At boot time, we don't yet know if devices will be 64-bit capable.
2321 * Assume that they will -- if they turn out not to be, then we can
2322 * take them out of the 1:1 domain later.
2323 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002324 if (!startup) {
2325 /*
2326 * If the device's dma_mask is less than the system's memory
2327 * size then this is not a candidate for identity mapping.
2328 */
2329 u64 dma_mask = pdev->dma_mask;
2330
2331 if (pdev->dev.coherent_dma_mask &&
2332 pdev->dev.coherent_dma_mask < dma_mask)
2333 dma_mask = pdev->dev.coherent_dma_mask;
2334
2335 return dma_mask >= dma_get_required_mask(&pdev->dev);
2336 }
David Woodhouse6941af22009-07-04 18:24:27 +01002337
2338 return 1;
2339}
2340
Matt Kraai071e1372009-08-23 22:30:22 -07002341static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002342{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002343 struct pci_dev *pdev = NULL;
2344 int ret;
2345
David Woodhouse19943b02009-08-04 16:19:20 +01002346 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002347 if (ret)
2348 return -EFAULT;
2349
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002350 for_each_pci_dev(pdev) {
Mike Travis825507d2011-05-28 13:15:06 -05002351 /* Skip Host/PCI Bridge devices */
2352 if (IS_BRIDGE_HOST_DEVICE(pdev))
2353 continue;
David Woodhouse6941af22009-07-04 18:24:27 +01002354 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse19943b02009-08-04 16:19:20 +01002355 printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
2356 hw ? "hardware" : "software", pci_name(pdev));
David Woodhousec7ab48d2009-06-26 19:10:36 +01002357
David Woodhouse5fe60f42009-08-09 10:53:41 +01002358 ret = domain_add_dev_info(si_domain, pdev,
David Woodhouse19943b02009-08-04 16:19:20 +01002359 hw ? CONTEXT_TT_PASS_THROUGH :
David Woodhouse62edf5d2009-07-04 10:59:46 +01002360 CONTEXT_TT_MULTI_LEVEL);
2361 if (ret)
2362 return ret;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002363 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002364 }
2365
2366 return 0;
2367}
2368
Joseph Cihulab7792602011-05-03 00:08:37 -07002369static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002370{
2371 struct dmar_drhd_unit *drhd;
2372 struct dmar_rmrr_unit *rmrr;
2373 struct pci_dev *pdev;
2374 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002375 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002376
2377 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002378 * for each drhd
2379 * allocate root
2380 * initialize and program root entry to not present
2381 * endfor
2382 */
2383 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002384 g_num_of_iommus++;
2385 /*
2386 * lock not needed as this is only incremented in the single
2387 * threaded kernel __init code path all other access are read
2388 * only
2389 */
2390 }
2391
Weidong Hand9630fe2008-12-08 11:06:32 +08002392 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2393 GFP_KERNEL);
2394 if (!g_iommus) {
2395 printk(KERN_ERR "Allocating global iommu array failed\n");
2396 ret = -ENOMEM;
2397 goto error;
2398 }
2399
mark gross80b20dd2008-04-18 13:53:58 -07002400 deferred_flush = kzalloc(g_num_of_iommus *
2401 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2402 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002403 ret = -ENOMEM;
2404 goto error;
2405 }
2406
mark gross5e0d2a62008-03-04 15:22:08 -08002407 for_each_drhd_unit(drhd) {
2408 if (drhd->ignored)
2409 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002410
2411 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002412 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002413
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002414 ret = iommu_init_domains(iommu);
2415 if (ret)
2416 goto error;
2417
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002418 /*
2419 * TBD:
2420 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002421 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002422 */
2423 ret = iommu_alloc_root_entry(iommu);
2424 if (ret) {
2425 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2426 goto error;
2427 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002428 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002429 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002430 }
2431
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002432 /*
2433 * Start from the sane iommu hardware state.
2434 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002435 for_each_drhd_unit(drhd) {
2436 if (drhd->ignored)
2437 continue;
2438
2439 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002440
2441 /*
2442 * If the queued invalidation is already initialized by us
2443 * (for example, while enabling interrupt-remapping) then
2444 * we got the things already rolling from a sane state.
2445 */
2446 if (iommu->qi)
2447 continue;
2448
2449 /*
2450 * Clear any previous faults.
2451 */
2452 dmar_fault(-1, iommu);
2453 /*
2454 * Disable queued invalidation if supported and already enabled
2455 * before OS handover.
2456 */
2457 dmar_disable_qi(iommu);
2458 }
2459
2460 for_each_drhd_unit(drhd) {
2461 if (drhd->ignored)
2462 continue;
2463
2464 iommu = drhd->iommu;
2465
Youquan Songa77b67d2008-10-16 16:31:56 -07002466 if (dmar_enable_qi(iommu)) {
2467 /*
2468 * Queued Invalidate not enabled, use Register Based
2469 * Invalidate
2470 */
2471 iommu->flush.flush_context = __iommu_flush_context;
2472 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002473 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002474 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002475 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002476 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002477 } else {
2478 iommu->flush.flush_context = qi_flush_context;
2479 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002480 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002481 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002482 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002483 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002484 }
2485 }
2486
David Woodhouse19943b02009-08-04 16:19:20 +01002487 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002488 iommu_identity_mapping |= IDENTMAP_ALL;
2489
Suresh Siddhad3f13812011-08-23 17:05:25 -07002490#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002491 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002492#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002493
2494 check_tylersburg_isoch();
2495
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002496 /*
2497 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002498 * identity mappings for rmrr, gfx, and isa and may fall back to static
2499 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002500 */
David Woodhouse19943b02009-08-04 16:19:20 +01002501 if (iommu_identity_mapping) {
2502 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2503 if (ret) {
2504 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2505 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002506 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002507 }
David Woodhouse19943b02009-08-04 16:19:20 +01002508 /*
2509 * For each rmrr
2510 * for each dev attached to rmrr
2511 * do
2512 * locate drhd for dev, alloc domain for dev
2513 * allocate free domain
2514 * allocate page table entries for rmrr
2515 * if context not allocated for bus
2516 * allocate and init context
2517 * set present in root table for this bus
2518 * init context with domain, translation etc
2519 * endfor
2520 * endfor
2521 */
2522 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2523 for_each_rmrr_units(rmrr) {
2524 for (i = 0; i < rmrr->devices_cnt; i++) {
2525 pdev = rmrr->devices[i];
2526 /*
2527 * some BIOS lists non-exist devices in DMAR
2528 * table.
2529 */
2530 if (!pdev)
2531 continue;
2532 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2533 if (ret)
2534 printk(KERN_ERR
2535 "IOMMU: mapping reserved region failed\n");
2536 }
2537 }
2538
2539 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002540
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002541 /*
2542 * for each drhd
2543 * enable fault log
2544 * global invalidate context cache
2545 * global invalidate iotlb
2546 * enable translation
2547 */
2548 for_each_drhd_unit(drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002549 if (drhd->ignored) {
2550 /*
2551 * we always have to disable PMRs or DMA may fail on
2552 * this device
2553 */
2554 if (force_on)
2555 iommu_disable_protect_mem_regions(drhd->iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002556 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002557 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002558 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002559
2560 iommu_flush_write_buffer(iommu);
2561
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002562 ret = dmar_set_interrupt(iommu);
2563 if (ret)
2564 goto error;
2565
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002566 iommu_set_root_entry(iommu);
2567
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002568 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002569 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002570
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002571 ret = iommu_enable_translation(iommu);
2572 if (ret)
2573 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002574
2575 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002576 }
2577
2578 return 0;
2579error:
2580 for_each_drhd_unit(drhd) {
2581 if (drhd->ignored)
2582 continue;
2583 iommu = drhd->iommu;
2584 free_iommu(iommu);
2585 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002586 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002587 return ret;
2588}
2589
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002590/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002591static struct iova *intel_alloc_iova(struct device *dev,
2592 struct dmar_domain *domain,
2593 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002594{
2595 struct pci_dev *pdev = to_pci_dev(dev);
2596 struct iova *iova = NULL;
2597
David Woodhouse875764d2009-06-28 21:20:51 +01002598 /* Restrict dma_mask to the width that the iommu can handle */
2599 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2600
2601 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002602 /*
2603 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002604 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002605 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002606 */
David Woodhouse875764d2009-06-28 21:20:51 +01002607 iova = alloc_iova(&domain->iovad, nrpages,
2608 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2609 if (iova)
2610 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002611 }
David Woodhouse875764d2009-06-28 21:20:51 +01002612 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2613 if (unlikely(!iova)) {
2614 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2615 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002616 return NULL;
2617 }
2618
2619 return iova;
2620}
2621
David Woodhouse147202a2009-07-07 19:43:20 +01002622static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002623{
2624 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002625 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002626
2627 domain = get_domain_for_dev(pdev,
2628 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2629 if (!domain) {
2630 printk(KERN_ERR
2631 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002632 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002633 }
2634
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002635 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002636 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002637 ret = domain_context_mapping(domain, pdev,
2638 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002639 if (ret) {
2640 printk(KERN_ERR
2641 "Domain context map for %s failed",
2642 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002643 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002644 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002645 }
2646
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002647 return domain;
2648}
2649
David Woodhouse147202a2009-07-07 19:43:20 +01002650static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2651{
2652 struct device_domain_info *info;
2653
2654 /* No lock here, assumes no domain exit in normal case */
2655 info = dev->dev.archdata.iommu;
2656 if (likely(info))
2657 return info->domain;
2658
2659 return __get_valid_domain_for_dev(dev);
2660}
2661
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002662static int iommu_dummy(struct pci_dev *pdev)
2663{
2664 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2665}
2666
2667/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002668static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002669{
David Woodhouse73676832009-07-04 14:08:36 +01002670 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002671 int found;
2672
David Woodhouse73676832009-07-04 14:08:36 +01002673 if (unlikely(dev->bus != &pci_bus_type))
2674 return 1;
2675
2676 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002677 if (iommu_dummy(pdev))
2678 return 1;
2679
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002680 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002681 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002682
2683 found = identity_mapping(pdev);
2684 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002685 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002686 return 1;
2687 else {
2688 /*
2689 * 32 bit DMA is removed from si_domain and fall back
2690 * to non-identity mapping.
2691 */
2692 domain_remove_one_dev_info(si_domain, pdev);
2693 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2694 pci_name(pdev));
2695 return 0;
2696 }
2697 } else {
2698 /*
2699 * In case of a detached 64 bit DMA device from vm, the device
2700 * is put into si_domain for identity mapping.
2701 */
David Woodhouse6941af22009-07-04 18:24:27 +01002702 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002703 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002704 ret = domain_add_dev_info(si_domain, pdev,
2705 hw_pass_through ?
2706 CONTEXT_TT_PASS_THROUGH :
2707 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002708 if (!ret) {
2709 printk(KERN_INFO "64bit %s uses identity mapping\n",
2710 pci_name(pdev));
2711 return 1;
2712 }
2713 }
2714 }
2715
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002716 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002717}
2718
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002719static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2720 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002721{
2722 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002723 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002724 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002725 struct iova *iova;
2726 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002727 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002728 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002729 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002730
2731 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002732
David Woodhouse73676832009-07-04 14:08:36 +01002733 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002734 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002735
2736 domain = get_valid_domain_for_dev(pdev);
2737 if (!domain)
2738 return 0;
2739
Weidong Han8c11e792008-12-08 15:29:22 +08002740 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002741 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002742
Mike Travisc681d0b2011-05-28 13:15:05 -05002743 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002744 if (!iova)
2745 goto error;
2746
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002747 /*
2748 * Check if DMAR supports zero-length reads on write only
2749 * mappings..
2750 */
2751 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002752 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002753 prot |= DMA_PTE_READ;
2754 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2755 prot |= DMA_PTE_WRITE;
2756 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002757 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002758 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002759 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002760 * is not a big problem
2761 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002762 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002763 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002764 if (ret)
2765 goto error;
2766
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002767 /* it's a non-present to present mapping. Only flush if caching mode */
2768 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002769 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002770 else
Weidong Han8c11e792008-12-08 15:29:22 +08002771 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002772
David Woodhouse03d6a242009-06-28 15:33:46 +01002773 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2774 start_paddr += paddr & ~PAGE_MASK;
2775 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002776
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002777error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002778 if (iova)
2779 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002780 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002781 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002782 return 0;
2783}
2784
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002785static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2786 unsigned long offset, size_t size,
2787 enum dma_data_direction dir,
2788 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002789{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002790 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2791 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002792}
2793
mark gross5e0d2a62008-03-04 15:22:08 -08002794static void flush_unmaps(void)
2795{
mark gross80b20dd2008-04-18 13:53:58 -07002796 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002797
mark gross5e0d2a62008-03-04 15:22:08 -08002798 timer_on = 0;
2799
2800 /* just flush them all */
2801 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002802 struct intel_iommu *iommu = g_iommus[i];
2803 if (!iommu)
2804 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002805
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002806 if (!deferred_flush[i].next)
2807 continue;
2808
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002809 /* In caching mode, global flushes turn emulation expensive */
2810 if (!cap_caching_mode(iommu->cap))
2811 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002812 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002813 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002814 unsigned long mask;
2815 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002816 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002817
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002818 /* On real hardware multiple invalidations are expensive */
2819 if (cap_caching_mode(iommu->cap))
2820 iommu_flush_iotlb_psi(iommu, domain->id,
2821 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2822 else {
2823 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2824 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2825 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2826 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002827 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002828 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002829 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002830 }
2831
mark gross5e0d2a62008-03-04 15:22:08 -08002832 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002833}
2834
2835static void flush_unmaps_timeout(unsigned long data)
2836{
mark gross80b20dd2008-04-18 13:53:58 -07002837 unsigned long flags;
2838
2839 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002840 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002841 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002842}
2843
2844static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2845{
2846 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002847 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002848 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002849
2850 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002851 if (list_size == HIGH_WATER_MARK)
2852 flush_unmaps();
2853
Weidong Han8c11e792008-12-08 15:29:22 +08002854 iommu = domain_get_iommu(dom);
2855 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002856
mark gross80b20dd2008-04-18 13:53:58 -07002857 next = deferred_flush[iommu_id].next;
2858 deferred_flush[iommu_id].domain[next] = dom;
2859 deferred_flush[iommu_id].iova[next] = iova;
2860 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002861
2862 if (!timer_on) {
2863 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2864 timer_on = 1;
2865 }
2866 list_size++;
2867 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2868}
2869
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002870static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2871 size_t size, enum dma_data_direction dir,
2872 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002873{
2874 struct pci_dev *pdev = to_pci_dev(dev);
2875 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002876 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002877 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002878 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002879
David Woodhouse73676832009-07-04 14:08:36 +01002880 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002881 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002882
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002883 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002884 BUG_ON(!domain);
2885
Weidong Han8c11e792008-12-08 15:29:22 +08002886 iommu = domain_get_iommu(domain);
2887
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002888 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002889 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2890 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002891 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002892
David Woodhoused794dc92009-06-28 00:27:49 +01002893 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2894 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002895
David Woodhoused794dc92009-06-28 00:27:49 +01002896 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2897 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002898
2899 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002900 dma_pte_clear_range(domain, start_pfn, last_pfn);
2901
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002902 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002903 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2904
mark gross5e0d2a62008-03-04 15:22:08 -08002905 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002906 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002907 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002908 /* free iova */
2909 __free_iova(&domain->iovad, iova);
2910 } else {
2911 add_unmap(domain, iova);
2912 /*
2913 * queue up the release of the unmap to save the 1/6th of the
2914 * cpu used up by the iotlb flush operation...
2915 */
mark gross5e0d2a62008-03-04 15:22:08 -08002916 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002917}
2918
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002919static void *intel_alloc_coherent(struct device *hwdev, size_t size,
2920 dma_addr_t *dma_handle, gfp_t flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002921{
2922 void *vaddr;
2923 int order;
2924
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002925 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002926 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002927
2928 if (!iommu_no_mapping(hwdev))
2929 flags &= ~(GFP_DMA | GFP_DMA32);
2930 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
2931 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
2932 flags |= GFP_DMA;
2933 else
2934 flags |= GFP_DMA32;
2935 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002936
2937 vaddr = (void *)__get_free_pages(flags, order);
2938 if (!vaddr)
2939 return NULL;
2940 memset(vaddr, 0, size);
2941
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002942 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2943 DMA_BIDIRECTIONAL,
2944 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002945 if (*dma_handle)
2946 return vaddr;
2947 free_pages((unsigned long)vaddr, order);
2948 return NULL;
2949}
2950
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002951static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
2952 dma_addr_t dma_handle)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002953{
2954 int order;
2955
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002956 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002957 order = get_order(size);
2958
David Woodhouse0db9b7a2009-07-14 02:01:57 +01002959 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002960 free_pages((unsigned long)vaddr, order);
2961}
2962
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002963static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
2964 int nelems, enum dma_data_direction dir,
2965 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002966{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002967 struct pci_dev *pdev = to_pci_dev(hwdev);
2968 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002969 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002970 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002971 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002972
David Woodhouse73676832009-07-04 14:08:36 +01002973 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002974 return;
2975
2976 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08002977 BUG_ON(!domain);
2978
2979 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002980
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07002981 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01002982 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
2983 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002984 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002985
David Woodhoused794dc92009-06-28 00:27:49 +01002986 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2987 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002988
2989 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002990 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002991
David Woodhoused794dc92009-06-28 00:27:49 +01002992 /* free page tables */
2993 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2994
David Woodhouseacea0012009-07-14 01:55:11 +01002995 if (intel_iommu_strict) {
2996 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002997 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01002998 /* free iova */
2999 __free_iova(&domain->iovad, iova);
3000 } else {
3001 add_unmap(domain, iova);
3002 /*
3003 * queue up the release of the unmap to save the 1/6th of the
3004 * cpu used up by the iotlb flush operation...
3005 */
3006 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003007}
3008
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003009static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003010 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003011{
3012 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003013 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003014
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003015 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003016 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003017 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003018 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003019 }
3020 return nelems;
3021}
3022
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003023static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3024 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003025{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003026 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003027 struct pci_dev *pdev = to_pci_dev(hwdev);
3028 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003029 size_t size = 0;
3030 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003031 struct iova *iova = NULL;
3032 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003033 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003034 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003035 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003036
3037 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003038 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003039 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003040
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003041 domain = get_valid_domain_for_dev(pdev);
3042 if (!domain)
3043 return 0;
3044
Weidong Han8c11e792008-12-08 15:29:22 +08003045 iommu = domain_get_iommu(domain);
3046
David Woodhouseb536d242009-06-28 14:49:31 +01003047 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003048 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003049
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003050 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3051 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003052 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003053 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003054 return 0;
3055 }
3056
3057 /*
3058 * Check if DMAR supports zero-length reads on write only
3059 * mappings..
3060 */
3061 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003062 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003063 prot |= DMA_PTE_READ;
3064 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3065 prot |= DMA_PTE_WRITE;
3066
David Woodhouseb536d242009-06-28 14:49:31 +01003067 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003068
Fenghua Yuf5329592009-08-04 15:09:37 -07003069 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003070 if (unlikely(ret)) {
3071 /* clear the page */
3072 dma_pte_clear_range(domain, start_vpfn,
3073 start_vpfn + size - 1);
3074 /* free page tables */
3075 dma_pte_free_pagetable(domain, start_vpfn,
3076 start_vpfn + size - 1);
3077 /* free iova */
3078 __free_iova(&domain->iovad, iova);
3079 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003080 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003081
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003082 /* it's a non-present to present mapping. Only flush if caching mode */
3083 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003084 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003085 else
Weidong Han8c11e792008-12-08 15:29:22 +08003086 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003087
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003088 return nelems;
3089}
3090
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003091static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3092{
3093 return !dma_addr;
3094}
3095
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003096struct dma_map_ops intel_dma_ops = {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003097 .alloc_coherent = intel_alloc_coherent,
3098 .free_coherent = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003099 .map_sg = intel_map_sg,
3100 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003101 .map_page = intel_map_page,
3102 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003103 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003104};
3105
3106static inline int iommu_domain_cache_init(void)
3107{
3108 int ret = 0;
3109
3110 iommu_domain_cache = kmem_cache_create("iommu_domain",
3111 sizeof(struct dmar_domain),
3112 0,
3113 SLAB_HWCACHE_ALIGN,
3114
3115 NULL);
3116 if (!iommu_domain_cache) {
3117 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3118 ret = -ENOMEM;
3119 }
3120
3121 return ret;
3122}
3123
3124static inline int iommu_devinfo_cache_init(void)
3125{
3126 int ret = 0;
3127
3128 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3129 sizeof(struct device_domain_info),
3130 0,
3131 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003132 NULL);
3133 if (!iommu_devinfo_cache) {
3134 printk(KERN_ERR "Couldn't create devinfo cache\n");
3135 ret = -ENOMEM;
3136 }
3137
3138 return ret;
3139}
3140
3141static inline int iommu_iova_cache_init(void)
3142{
3143 int ret = 0;
3144
3145 iommu_iova_cache = kmem_cache_create("iommu_iova",
3146 sizeof(struct iova),
3147 0,
3148 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003149 NULL);
3150 if (!iommu_iova_cache) {
3151 printk(KERN_ERR "Couldn't create iova cache\n");
3152 ret = -ENOMEM;
3153 }
3154
3155 return ret;
3156}
3157
3158static int __init iommu_init_mempool(void)
3159{
3160 int ret;
3161 ret = iommu_iova_cache_init();
3162 if (ret)
3163 return ret;
3164
3165 ret = iommu_domain_cache_init();
3166 if (ret)
3167 goto domain_error;
3168
3169 ret = iommu_devinfo_cache_init();
3170 if (!ret)
3171 return ret;
3172
3173 kmem_cache_destroy(iommu_domain_cache);
3174domain_error:
3175 kmem_cache_destroy(iommu_iova_cache);
3176
3177 return -ENOMEM;
3178}
3179
3180static void __init iommu_exit_mempool(void)
3181{
3182 kmem_cache_destroy(iommu_devinfo_cache);
3183 kmem_cache_destroy(iommu_domain_cache);
3184 kmem_cache_destroy(iommu_iova_cache);
3185
3186}
3187
Dan Williams556ab452010-07-23 15:47:56 -07003188static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3189{
3190 struct dmar_drhd_unit *drhd;
3191 u32 vtbar;
3192 int rc;
3193
3194 /* We know that this device on this chipset has its own IOMMU.
3195 * If we find it under a different IOMMU, then the BIOS is lying
3196 * to us. Hope that the IOMMU for this device is actually
3197 * disabled, and it needs no translation...
3198 */
3199 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3200 if (rc) {
3201 /* "can't" happen */
3202 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3203 return;
3204 }
3205 vtbar &= 0xffff0000;
3206
3207 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3208 drhd = dmar_find_matched_drhd_unit(pdev);
3209 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3210 TAINT_FIRMWARE_WORKAROUND,
3211 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3212 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3213}
3214DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3215
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003216static void __init init_no_remapping_devices(void)
3217{
3218 struct dmar_drhd_unit *drhd;
3219
3220 for_each_drhd_unit(drhd) {
3221 if (!drhd->include_all) {
3222 int i;
3223 for (i = 0; i < drhd->devices_cnt; i++)
3224 if (drhd->devices[i] != NULL)
3225 break;
3226 /* ignore DMAR unit if no pci devices exist */
3227 if (i == drhd->devices_cnt)
3228 drhd->ignored = 1;
3229 }
3230 }
3231
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003232 for_each_drhd_unit(drhd) {
3233 int i;
3234 if (drhd->ignored || drhd->include_all)
3235 continue;
3236
3237 for (i = 0; i < drhd->devices_cnt; i++)
3238 if (drhd->devices[i] &&
David Woodhousec0771df2011-10-14 20:59:46 +01003239 !IS_GFX_DEVICE(drhd->devices[i]))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003240 break;
3241
3242 if (i < drhd->devices_cnt)
3243 continue;
3244
David Woodhousec0771df2011-10-14 20:59:46 +01003245 /* This IOMMU has *only* gfx devices. Either bypass it or
3246 set the gfx_mapped flag, as appropriate */
3247 if (dmar_map_gfx) {
3248 intel_iommu_gfx_mapped = 1;
3249 } else {
3250 drhd->ignored = 1;
3251 for (i = 0; i < drhd->devices_cnt; i++) {
3252 if (!drhd->devices[i])
3253 continue;
3254 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3255 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003256 }
3257 }
3258}
3259
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003260#ifdef CONFIG_SUSPEND
3261static int init_iommu_hw(void)
3262{
3263 struct dmar_drhd_unit *drhd;
3264 struct intel_iommu *iommu = NULL;
3265
3266 for_each_active_iommu(iommu, drhd)
3267 if (iommu->qi)
3268 dmar_reenable_qi(iommu);
3269
Joseph Cihulab7792602011-05-03 00:08:37 -07003270 for_each_iommu(iommu, drhd) {
3271 if (drhd->ignored) {
3272 /*
3273 * we always have to disable PMRs or DMA may fail on
3274 * this device
3275 */
3276 if (force_on)
3277 iommu_disable_protect_mem_regions(iommu);
3278 continue;
3279 }
3280
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003281 iommu_flush_write_buffer(iommu);
3282
3283 iommu_set_root_entry(iommu);
3284
3285 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003286 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003287 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003288 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003289 if (iommu_enable_translation(iommu))
3290 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003291 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003292 }
3293
3294 return 0;
3295}
3296
3297static void iommu_flush_all(void)
3298{
3299 struct dmar_drhd_unit *drhd;
3300 struct intel_iommu *iommu;
3301
3302 for_each_active_iommu(iommu, drhd) {
3303 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003304 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003305 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003306 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003307 }
3308}
3309
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003310static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003311{
3312 struct dmar_drhd_unit *drhd;
3313 struct intel_iommu *iommu = NULL;
3314 unsigned long flag;
3315
3316 for_each_active_iommu(iommu, drhd) {
3317 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3318 GFP_ATOMIC);
3319 if (!iommu->iommu_state)
3320 goto nomem;
3321 }
3322
3323 iommu_flush_all();
3324
3325 for_each_active_iommu(iommu, drhd) {
3326 iommu_disable_translation(iommu);
3327
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003328 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003329
3330 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3331 readl(iommu->reg + DMAR_FECTL_REG);
3332 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3333 readl(iommu->reg + DMAR_FEDATA_REG);
3334 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3335 readl(iommu->reg + DMAR_FEADDR_REG);
3336 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3337 readl(iommu->reg + DMAR_FEUADDR_REG);
3338
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003339 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003340 }
3341 return 0;
3342
3343nomem:
3344 for_each_active_iommu(iommu, drhd)
3345 kfree(iommu->iommu_state);
3346
3347 return -ENOMEM;
3348}
3349
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003350static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003351{
3352 struct dmar_drhd_unit *drhd;
3353 struct intel_iommu *iommu = NULL;
3354 unsigned long flag;
3355
3356 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003357 if (force_on)
3358 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3359 else
3360 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003361 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003362 }
3363
3364 for_each_active_iommu(iommu, drhd) {
3365
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003366 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003367
3368 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3369 iommu->reg + DMAR_FECTL_REG);
3370 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3371 iommu->reg + DMAR_FEDATA_REG);
3372 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3373 iommu->reg + DMAR_FEADDR_REG);
3374 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3375 iommu->reg + DMAR_FEUADDR_REG);
3376
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003377 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003378 }
3379
3380 for_each_active_iommu(iommu, drhd)
3381 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003382}
3383
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003384static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003385 .resume = iommu_resume,
3386 .suspend = iommu_suspend,
3387};
3388
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003389static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003390{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003391 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003392}
3393
3394#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003395static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003396#endif /* CONFIG_PM */
3397
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003398LIST_HEAD(dmar_rmrr_units);
3399
3400static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3401{
3402 list_add(&rmrr->list, &dmar_rmrr_units);
3403}
3404
3405
3406int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3407{
3408 struct acpi_dmar_reserved_memory *rmrr;
3409 struct dmar_rmrr_unit *rmrru;
3410
3411 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3412 if (!rmrru)
3413 return -ENOMEM;
3414
3415 rmrru->hdr = header;
3416 rmrr = (struct acpi_dmar_reserved_memory *)header;
3417 rmrru->base_address = rmrr->base_address;
3418 rmrru->end_address = rmrr->end_address;
3419
3420 dmar_register_rmrr_unit(rmrru);
3421 return 0;
3422}
3423
3424static int __init
3425rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3426{
3427 struct acpi_dmar_reserved_memory *rmrr;
3428 int ret;
3429
3430 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
3431 ret = dmar_parse_dev_scope((void *)(rmrr + 1),
3432 ((void *)rmrr) + rmrr->header.length,
3433 &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
3434
3435 if (ret || (rmrru->devices_cnt == 0)) {
3436 list_del(&rmrru->list);
3437 kfree(rmrru);
3438 }
3439 return ret;
3440}
3441
3442static LIST_HEAD(dmar_atsr_units);
3443
3444int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3445{
3446 struct acpi_dmar_atsr *atsr;
3447 struct dmar_atsr_unit *atsru;
3448
3449 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3450 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3451 if (!atsru)
3452 return -ENOMEM;
3453
3454 atsru->hdr = hdr;
3455 atsru->include_all = atsr->flags & 0x1;
3456
3457 list_add(&atsru->list, &dmar_atsr_units);
3458
3459 return 0;
3460}
3461
3462static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3463{
3464 int rc;
3465 struct acpi_dmar_atsr *atsr;
3466
3467 if (atsru->include_all)
3468 return 0;
3469
3470 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3471 rc = dmar_parse_dev_scope((void *)(atsr + 1),
3472 (void *)atsr + atsr->header.length,
3473 &atsru->devices_cnt, &atsru->devices,
3474 atsr->segment);
3475 if (rc || !atsru->devices_cnt) {
3476 list_del(&atsru->list);
3477 kfree(atsru);
3478 }
3479
3480 return rc;
3481}
3482
3483int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3484{
3485 int i;
3486 struct pci_bus *bus;
3487 struct acpi_dmar_atsr *atsr;
3488 struct dmar_atsr_unit *atsru;
3489
3490 dev = pci_physfn(dev);
3491
3492 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3493 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3494 if (atsr->segment == pci_domain_nr(dev->bus))
3495 goto found;
3496 }
3497
3498 return 0;
3499
3500found:
3501 for (bus = dev->bus; bus; bus = bus->parent) {
3502 struct pci_dev *bridge = bus->self;
3503
3504 if (!bridge || !pci_is_pcie(bridge) ||
3505 bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
3506 return 0;
3507
3508 if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
3509 for (i = 0; i < atsru->devices_cnt; i++)
3510 if (atsru->devices[i] == bridge)
3511 return 1;
3512 break;
3513 }
3514 }
3515
3516 if (atsru->include_all)
3517 return 1;
3518
3519 return 0;
3520}
3521
3522int dmar_parse_rmrr_atsr_dev(void)
3523{
3524 struct dmar_rmrr_unit *rmrr, *rmrr_n;
3525 struct dmar_atsr_unit *atsr, *atsr_n;
3526 int ret = 0;
3527
3528 list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
3529 ret = rmrr_parse_dev(rmrr);
3530 if (ret)
3531 return ret;
3532 }
3533
3534 list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
3535 ret = atsr_parse_dev(atsr);
3536 if (ret)
3537 return ret;
3538 }
3539
3540 return ret;
3541}
3542
Fenghua Yu99dcade2009-11-11 07:23:06 -08003543/*
3544 * Here we only respond to action of unbound device from driver.
3545 *
3546 * Added device is not attached to its DMAR domain here yet. That will happen
3547 * when mapping the device to iova.
3548 */
3549static int device_notifier(struct notifier_block *nb,
3550 unsigned long action, void *data)
3551{
3552 struct device *dev = data;
3553 struct pci_dev *pdev = to_pci_dev(dev);
3554 struct dmar_domain *domain;
3555
David Woodhouse44cd6132009-12-02 10:18:30 +00003556 if (iommu_no_mapping(dev))
3557 return 0;
3558
Fenghua Yu99dcade2009-11-11 07:23:06 -08003559 domain = find_domain(pdev);
3560 if (!domain)
3561 return 0;
3562
Alex Williamsona97590e2011-03-04 14:52:16 -07003563 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
Fenghua Yu99dcade2009-11-11 07:23:06 -08003564 domain_remove_one_dev_info(domain, pdev);
3565
Alex Williamsona97590e2011-03-04 14:52:16 -07003566 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3567 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3568 list_empty(&domain->devices))
3569 domain_exit(domain);
3570 }
3571
Fenghua Yu99dcade2009-11-11 07:23:06 -08003572 return 0;
3573}
3574
3575static struct notifier_block device_nb = {
3576 .notifier_call = device_notifier,
3577};
3578
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003579int __init intel_iommu_init(void)
3580{
3581 int ret = 0;
3582
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003583 /* VT-d is required for a TXT/tboot launch, so enforce that */
3584 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003585
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003586 if (dmar_table_init()) {
3587 if (force_on)
3588 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003589 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003590 }
3591
Suresh Siddhac2c72862011-08-23 17:05:19 -07003592 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003593 if (force_on)
3594 panic("tboot: Failed to initialize DMAR device scope\n");
3595 return -ENODEV;
3596 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003597
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003598 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003599 return -ENODEV;
3600
Joseph Cihula51a63e62011-03-21 11:04:24 -07003601 if (iommu_init_mempool()) {
3602 if (force_on)
3603 panic("tboot: Failed to initialize iommu memory\n");
3604 return -ENODEV;
3605 }
3606
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003607 if (list_empty(&dmar_rmrr_units))
3608 printk(KERN_INFO "DMAR: No RMRR found\n");
3609
3610 if (list_empty(&dmar_atsr_units))
3611 printk(KERN_INFO "DMAR: No ATSR found\n");
3612
Joseph Cihula51a63e62011-03-21 11:04:24 -07003613 if (dmar_init_reserved_ranges()) {
3614 if (force_on)
3615 panic("tboot: Failed to reserve iommu ranges\n");
3616 return -ENODEV;
3617 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003618
3619 init_no_remapping_devices();
3620
Joseph Cihulab7792602011-05-03 00:08:37 -07003621 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003622 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003623 if (force_on)
3624 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003625 printk(KERN_ERR "IOMMU: dmar init failed\n");
3626 put_iova_domain(&reserved_iova_list);
3627 iommu_exit_mempool();
3628 return ret;
3629 }
3630 printk(KERN_INFO
3631 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3632
mark gross5e0d2a62008-03-04 15:22:08 -08003633 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003634#ifdef CONFIG_SWIOTLB
3635 swiotlb = 0;
3636#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003637 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003638
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003639 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003640
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003641 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003642
Fenghua Yu99dcade2009-11-11 07:23:06 -08003643 bus_register_notifier(&pci_bus_type, &device_nb);
3644
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003645 return 0;
3646}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003647
Han, Weidong3199aa62009-02-26 17:31:12 +08003648static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3649 struct pci_dev *pdev)
3650{
3651 struct pci_dev *tmp, *parent;
3652
3653 if (!iommu || !pdev)
3654 return;
3655
3656 /* dependent device detach */
3657 tmp = pci_find_upstream_pcie_bridge(pdev);
3658 /* Secondary interface's bus number and devfn 0 */
3659 if (tmp) {
3660 parent = pdev->bus->self;
3661 while (parent != tmp) {
3662 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01003663 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003664 parent = parent->bus->self;
3665 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003666 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003667 iommu_detach_dev(iommu,
3668 tmp->subordinate->number, 0);
3669 else /* this is a legacy PCI bridge */
David Woodhouse276dbf92009-04-04 01:45:37 +01003670 iommu_detach_dev(iommu, tmp->bus->number,
3671 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003672 }
3673}
3674
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003675static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003676 struct pci_dev *pdev)
3677{
3678 struct device_domain_info *info;
3679 struct intel_iommu *iommu;
3680 unsigned long flags;
3681 int found = 0;
3682 struct list_head *entry, *tmp;
3683
David Woodhouse276dbf92009-04-04 01:45:37 +01003684 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3685 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003686 if (!iommu)
3687 return;
3688
3689 spin_lock_irqsave(&device_domain_lock, flags);
3690 list_for_each_safe(entry, tmp, &domain->devices) {
3691 info = list_entry(entry, struct device_domain_info, link);
Mike Habeck8519dc42011-05-28 13:15:07 -05003692 if (info->segment == pci_domain_nr(pdev->bus) &&
3693 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003694 info->devfn == pdev->devfn) {
3695 list_del(&info->link);
3696 list_del(&info->global);
3697 if (info->dev)
3698 info->dev->dev.archdata.iommu = NULL;
3699 spin_unlock_irqrestore(&device_domain_lock, flags);
3700
Yu Zhao93a23a72009-05-18 13:51:37 +08003701 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003702 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003703 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003704 free_devinfo_mem(info);
3705
3706 spin_lock_irqsave(&device_domain_lock, flags);
3707
3708 if (found)
3709 break;
3710 else
3711 continue;
3712 }
3713
3714 /* if there is no other devices under the same iommu
3715 * owned by this domain, clear this iommu in iommu_bmp
3716 * update iommu count and coherency
3717 */
David Woodhouse276dbf92009-04-04 01:45:37 +01003718 if (iommu == device_to_iommu(info->segment, info->bus,
3719 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003720 found = 1;
3721 }
3722
Roland Dreier3e7abe22011-07-20 06:22:21 -07003723 spin_unlock_irqrestore(&device_domain_lock, flags);
3724
Weidong Hanc7151a82008-12-08 22:51:37 +08003725 if (found == 0) {
3726 unsigned long tmp_flags;
3727 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
3728 clear_bit(iommu->seq_id, &domain->iommu_bmp);
3729 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003730 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003731 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003732
Alex Williamson9b4554b2011-05-24 12:19:04 -04003733 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3734 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3735 spin_lock_irqsave(&iommu->lock, tmp_flags);
3736 clear_bit(domain->id, iommu->domain_ids);
3737 iommu->domains[domain->id] = NULL;
3738 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3739 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003740 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003741}
3742
3743static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3744{
3745 struct device_domain_info *info;
3746 struct intel_iommu *iommu;
3747 unsigned long flags1, flags2;
3748
3749 spin_lock_irqsave(&device_domain_lock, flags1);
3750 while (!list_empty(&domain->devices)) {
3751 info = list_entry(domain->devices.next,
3752 struct device_domain_info, link);
3753 list_del(&info->link);
3754 list_del(&info->global);
3755 if (info->dev)
3756 info->dev->dev.archdata.iommu = NULL;
3757
3758 spin_unlock_irqrestore(&device_domain_lock, flags1);
3759
Yu Zhao93a23a72009-05-18 13:51:37 +08003760 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01003761 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003762 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003763 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003764
3765 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003766 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003767 */
3768 spin_lock_irqsave(&domain->iommu_lock, flags2);
3769 if (test_and_clear_bit(iommu->seq_id,
3770 &domain->iommu_bmp)) {
3771 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003772 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003773 }
3774 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3775
3776 free_devinfo_mem(info);
3777 spin_lock_irqsave(&device_domain_lock, flags1);
3778 }
3779 spin_unlock_irqrestore(&device_domain_lock, flags1);
3780}
3781
Weidong Han5e98c4b2008-12-08 23:03:27 +08003782/* domain id for virtual machine, it won't be set in context */
3783static unsigned long vm_domid;
3784
3785static struct dmar_domain *iommu_alloc_vm_domain(void)
3786{
3787 struct dmar_domain *domain;
3788
3789 domain = alloc_domain_mem();
3790 if (!domain)
3791 return NULL;
3792
3793 domain->id = vm_domid++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003794 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003795 memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
3796 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3797
3798 return domain;
3799}
3800
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003801static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003802{
3803 int adjust_width;
3804
3805 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003806 spin_lock_init(&domain->iommu_lock);
3807
3808 domain_reserve_special_ranges(domain);
3809
3810 /* calculate AGAW */
3811 domain->gaw = guest_width;
3812 adjust_width = guestwidth_to_adjustwidth(guest_width);
3813 domain->agaw = width_to_agaw(adjust_width);
3814
3815 INIT_LIST_HEAD(&domain->devices);
3816
3817 domain->iommu_count = 0;
3818 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003819 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003820 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003821 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003822 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003823
3824 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003825 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003826 if (!domain->pgd)
3827 return -ENOMEM;
3828 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3829 return 0;
3830}
3831
3832static void iommu_free_vm_domain(struct dmar_domain *domain)
3833{
3834 unsigned long flags;
3835 struct dmar_drhd_unit *drhd;
3836 struct intel_iommu *iommu;
3837 unsigned long i;
3838 unsigned long ndomains;
3839
3840 for_each_drhd_unit(drhd) {
3841 if (drhd->ignored)
3842 continue;
3843 iommu = drhd->iommu;
3844
3845 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08003846 for_each_set_bit(i, iommu->domain_ids, ndomains) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003847 if (iommu->domains[i] == domain) {
3848 spin_lock_irqsave(&iommu->lock, flags);
3849 clear_bit(i, iommu->domain_ids);
3850 iommu->domains[i] = NULL;
3851 spin_unlock_irqrestore(&iommu->lock, flags);
3852 break;
3853 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08003854 }
3855 }
3856}
3857
3858static void vm_domain_exit(struct dmar_domain *domain)
3859{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003860 /* Domain 0 is reserved, so dont process it */
3861 if (!domain)
3862 return;
3863
3864 vm_domain_remove_all_dev_info(domain);
3865 /* destroy iovas */
3866 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003867
3868 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003869 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003870
3871 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003872 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003873
3874 iommu_free_vm_domain(domain);
3875 free_domain_mem(domain);
3876}
3877
Joerg Roedel5d450802008-12-03 14:52:32 +01003878static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003879{
Joerg Roedel5d450802008-12-03 14:52:32 +01003880 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003881
Joerg Roedel5d450802008-12-03 14:52:32 +01003882 dmar_domain = iommu_alloc_vm_domain();
3883 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003884 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003885 "intel_iommu_domain_init: dmar_domain == NULL\n");
3886 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003887 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003888 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003889 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003890 "intel_iommu_domain_init() failed\n");
3891 vm_domain_exit(dmar_domain);
3892 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003893 }
Allen Kay8140a952011-10-14 12:32:17 -07003894 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003895 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003896
Joerg Roedel5d450802008-12-03 14:52:32 +01003897 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003898}
Kay, Allen M38717942008-09-09 18:37:29 +03003899
Joerg Roedel5d450802008-12-03 14:52:32 +01003900static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003901{
Joerg Roedel5d450802008-12-03 14:52:32 +01003902 struct dmar_domain *dmar_domain = domain->priv;
3903
3904 domain->priv = NULL;
3905 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003906}
Kay, Allen M38717942008-09-09 18:37:29 +03003907
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003908static int intel_iommu_attach_device(struct iommu_domain *domain,
3909 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003910{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003911 struct dmar_domain *dmar_domain = domain->priv;
3912 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003913 struct intel_iommu *iommu;
3914 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03003915
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003916 /* normally pdev is not mapped */
3917 if (unlikely(domain_context_mapped(pdev))) {
3918 struct dmar_domain *old_domain;
3919
3920 old_domain = find_domain(pdev);
3921 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003922 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3923 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3924 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003925 else
3926 domain_remove_dev_info(old_domain);
3927 }
3928 }
3929
David Woodhouse276dbf92009-04-04 01:45:37 +01003930 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3931 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003932 if (!iommu)
3933 return -ENODEV;
3934
3935 /* check if this iommu agaw is sufficient for max mapped address */
3936 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01003937 if (addr_width > cap_mgaw(iommu->cap))
3938 addr_width = cap_mgaw(iommu->cap);
3939
3940 if (dmar_domain->max_addr > (1LL << addr_width)) {
3941 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003942 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01003943 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003944 return -EFAULT;
3945 }
Tom Lyona99c47a2010-05-17 08:20:45 +01003946 dmar_domain->gaw = addr_width;
3947
3948 /*
3949 * Knock out extra levels of page tables if necessary
3950 */
3951 while (iommu->agaw < dmar_domain->agaw) {
3952 struct dma_pte *pte;
3953
3954 pte = dmar_domain->pgd;
3955 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08003956 dmar_domain->pgd = (struct dma_pte *)
3957 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01003958 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01003959 }
3960 dmar_domain->agaw--;
3961 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003962
David Woodhouse5fe60f42009-08-09 10:53:41 +01003963 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003964}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003965
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003966static void intel_iommu_detach_device(struct iommu_domain *domain,
3967 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003968{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003969 struct dmar_domain *dmar_domain = domain->priv;
3970 struct pci_dev *pdev = to_pci_dev(dev);
3971
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003972 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003973}
Kay, Allen M38717942008-09-09 18:37:29 +03003974
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003975static int intel_iommu_map(struct iommu_domain *domain,
3976 unsigned long iova, phys_addr_t hpa,
3977 int gfp_order, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003978{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003979 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003980 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003981 int prot = 0;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003982 size_t size;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003983 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003984
Joerg Roedeldde57a22008-12-03 15:04:09 +01003985 if (iommu_prot & IOMMU_READ)
3986 prot |= DMA_PTE_READ;
3987 if (iommu_prot & IOMMU_WRITE)
3988 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08003989 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
3990 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003991
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003992 size = PAGE_SIZE << gfp_order;
David Woodhouse163cc522009-06-28 00:51:17 +01003993 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003994 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003995 u64 end;
3996
3997 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01003998 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003999 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004000 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004001 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004002 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004003 return -EFAULT;
4004 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004005 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004006 }
David Woodhousead051222009-06-28 14:22:28 +01004007 /* Round up size to next multiple of PAGE_SIZE, if it and
4008 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004009 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004010 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4011 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004012 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004013}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004014
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004015static int intel_iommu_unmap(struct iommu_domain *domain,
4016 unsigned long iova, int gfp_order)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004017{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004018 struct dmar_domain *dmar_domain = domain->priv;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004019 size_t size = PAGE_SIZE << gfp_order;
Allen Kay292827c2011-10-14 12:31:54 -07004020 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01004021
Allen Kay292827c2011-10-14 12:31:54 -07004022 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004023 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004024
David Woodhouse163cc522009-06-28 00:51:17 +01004025 if (dmar_domain->max_addr == iova + size)
4026 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004027
Allen Kay292827c2011-10-14 12:31:54 -07004028 return order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004029}
Kay, Allen M38717942008-09-09 18:37:29 +03004030
Joerg Roedeld14d6572008-12-03 15:06:57 +01004031static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
4032 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004033{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004034 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004035 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004036 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004037
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004038 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004039 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004040 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004041
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004042 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004043}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004044
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004045static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4046 unsigned long cap)
4047{
4048 struct dmar_domain *dmar_domain = domain->priv;
4049
4050 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4051 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004052 if (cap == IOMMU_CAP_INTR_REMAP)
4053 return intr_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004054
4055 return 0;
4056}
4057
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004058static struct iommu_ops intel_iommu_ops = {
4059 .domain_init = intel_iommu_domain_init,
4060 .domain_destroy = intel_iommu_domain_destroy,
4061 .attach_dev = intel_iommu_attach_device,
4062 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004063 .map = intel_iommu_map,
4064 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004065 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004066 .domain_has_cap = intel_iommu_domain_has_cap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004067};
David Woodhouse9af88142009-02-13 23:18:03 +00004068
4069static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
4070{
4071 /*
4072 * Mobile 4 Series Chipset neglects to set RWBF capability,
4073 * but needs it:
4074 */
4075 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4076 rwbf_quirk = 1;
David Woodhouse2d9e6672010-06-15 10:57:57 +01004077
4078 /* https://bugzilla.redhat.com/show_bug.cgi?id=538163 */
4079 if (dev->revision == 0x07) {
4080 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4081 dmar_map_gfx = 0;
4082 }
David Woodhouse9af88142009-02-13 23:18:03 +00004083}
4084
4085DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004086
Adam Jacksoneecfd572010-08-25 21:17:34 +01004087#define GGC 0x52
4088#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4089#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4090#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4091#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4092#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4093#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4094#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4095#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4096
David Woodhouse9eecabc2010-09-21 22:28:23 +01004097static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
4098{
4099 unsigned short ggc;
4100
Adam Jacksoneecfd572010-08-25 21:17:34 +01004101 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004102 return;
4103
Adam Jacksoneecfd572010-08-25 21:17:34 +01004104 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004105 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4106 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004107 } else if (dmar_map_gfx) {
4108 /* we have to ensure the gfx device is idle before we flush */
4109 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4110 intel_iommu_strict = 1;
4111 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004112}
4113DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4114DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4115DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4116DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4117
David Woodhousee0fc7e02009-09-30 09:12:17 -07004118/* On Tylersburg chipsets, some BIOSes have been known to enable the
4119 ISOCH DMAR unit for the Azalia sound device, but not give it any
4120 TLB entries, which causes it to deadlock. Check for that. We do
4121 this in a function called from init_dmars(), instead of in a PCI
4122 quirk, because we don't want to print the obnoxious "BIOS broken"
4123 message if VT-d is actually disabled.
4124*/
4125static void __init check_tylersburg_isoch(void)
4126{
4127 struct pci_dev *pdev;
4128 uint32_t vtisochctrl;
4129
4130 /* If there's no Azalia in the system anyway, forget it. */
4131 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4132 if (!pdev)
4133 return;
4134 pci_dev_put(pdev);
4135
4136 /* System Management Registers. Might be hidden, in which case
4137 we can't do the sanity check. But that's OK, because the
4138 known-broken BIOSes _don't_ actually hide it, so far. */
4139 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4140 if (!pdev)
4141 return;
4142
4143 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4144 pci_dev_put(pdev);
4145 return;
4146 }
4147
4148 pci_dev_put(pdev);
4149
4150 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4151 if (vtisochctrl & 1)
4152 return;
4153
4154 /* Drop all bits other than the number of TLB entries */
4155 vtisochctrl &= 0x1c;
4156
4157 /* If we have the recommended number of TLB entries (16), fine. */
4158 if (vtisochctrl == 0x10)
4159 return;
4160
4161 /* Zero TLB entries? You get to ride the short bus to school. */
4162 if (!vtisochctrl) {
4163 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4164 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4165 dmi_get_system_info(DMI_BIOS_VENDOR),
4166 dmi_get_system_info(DMI_BIOS_VERSION),
4167 dmi_get_system_info(DMI_PRODUCT_VERSION));
4168 iommu_identity_mapping |= IDENTMAP_AZALIA;
4169 return;
4170 }
4171
4172 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4173 vtisochctrl);
4174}