blob: dd255c578ad9a0d98ec1fdae03f9d0474309fcf3 [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
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070051#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
52#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070053#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070054
55#define IOAPIC_RANGE_START (0xfee00000)
56#define IOAPIC_RANGE_END (0xfeefffff)
57#define IOVA_START_ADDR (0x1000)
58
59#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
60
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070061#define MAX_AGAW_WIDTH 64
62
David Woodhouse2ebe3152009-09-19 07:34:04 -070063#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
64#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
65
66/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
67 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
68#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
69 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
70#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070071
Mark McLoughlinf27be032008-11-20 15:49:43 +000072#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070073#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070074#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080075
Andrew Mortondf08cdc2010-09-22 13:05:11 -070076/* page table handling */
77#define LEVEL_STRIDE (9)
78#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
79
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +020080/*
81 * This bitmap is used to advertise the page sizes our hardware support
82 * to the IOMMU core, which will then use this information to split
83 * physically contiguous memory regions it is mapping into page sizes
84 * that we support.
85 *
86 * Traditionally the IOMMU core just handed us the mappings directly,
87 * after making sure the size is an order of a 4KiB page and that the
88 * mapping has natural alignment.
89 *
90 * To retain this behavior, we currently advertise that we support
91 * all page sizes that are an order of 4KiB.
92 *
93 * If at some point we'd like to utilize the IOMMU core's new behavior,
94 * we could change this to advertise the real page sizes we support.
95 */
96#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
97
Andrew Mortondf08cdc2010-09-22 13:05:11 -070098static inline int agaw_to_level(int agaw)
99{
100 return agaw + 2;
101}
102
103static inline int agaw_to_width(int agaw)
104{
105 return 30 + agaw * LEVEL_STRIDE;
106}
107
108static inline int width_to_agaw(int width)
109{
110 return (width - 30) / LEVEL_STRIDE;
111}
112
113static inline unsigned int level_to_offset_bits(int level)
114{
115 return (level - 1) * LEVEL_STRIDE;
116}
117
118static inline int pfn_level_offset(unsigned long pfn, int level)
119{
120 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
121}
122
123static inline unsigned long level_mask(int level)
124{
125 return -1UL << level_to_offset_bits(level);
126}
127
128static inline unsigned long level_size(int level)
129{
130 return 1UL << level_to_offset_bits(level);
131}
132
133static inline unsigned long align_to_level(unsigned long pfn, int level)
134{
135 return (pfn + level_size(level) - 1) & level_mask(level);
136}
David Woodhousefd18de52009-05-10 23:57:41 +0100137
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100138static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
139{
140 return 1 << ((lvl - 1) * LEVEL_STRIDE);
141}
142
David Woodhousedd4e8312009-06-27 16:21:20 +0100143/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
144 are never going to work. */
145static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
146{
147 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
148}
149
150static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
151{
152 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
153}
154static inline unsigned long page_to_dma_pfn(struct page *pg)
155{
156 return mm_to_dma_pfn(page_to_pfn(pg));
157}
158static inline unsigned long virt_to_dma_pfn(void *p)
159{
160 return page_to_dma_pfn(virt_to_page(p));
161}
162
Weidong Hand9630fe2008-12-08 11:06:32 +0800163/* global iommu list, set NULL for ignored DMAR units */
164static struct intel_iommu **g_iommus;
165
David Woodhousee0fc7e02009-09-30 09:12:17 -0700166static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000167static int rwbf_quirk;
168
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000169/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700170 * set to 1 to panic kernel if can't successfully enable VT-d
171 * (used when kernel is launched w/ TXT)
172 */
173static int force_on = 0;
174
175/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000176 * 0: Present
177 * 1-11: Reserved
178 * 12-63: Context Ptr (12 - (haw-1))
179 * 64-127: Reserved
180 */
181struct root_entry {
182 u64 val;
183 u64 rsvd1;
184};
185#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
186static inline bool root_present(struct root_entry *root)
187{
188 return (root->val & 1);
189}
190static inline void set_root_present(struct root_entry *root)
191{
192 root->val |= 1;
193}
194static inline void set_root_value(struct root_entry *root, unsigned long value)
195{
196 root->val |= value & VTD_PAGE_MASK;
197}
198
199static inline struct context_entry *
200get_context_addr_from_root(struct root_entry *root)
201{
202 return (struct context_entry *)
203 (root_present(root)?phys_to_virt(
204 root->val & VTD_PAGE_MASK) :
205 NULL);
206}
207
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000208/*
209 * low 64 bits:
210 * 0: present
211 * 1: fault processing disable
212 * 2-3: translation type
213 * 12-63: address space root
214 * high 64 bits:
215 * 0-2: address width
216 * 3-6: aval
217 * 8-23: domain id
218 */
219struct context_entry {
220 u64 lo;
221 u64 hi;
222};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000223
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000224static inline bool context_present(struct context_entry *context)
225{
226 return (context->lo & 1);
227}
228static inline void context_set_present(struct context_entry *context)
229{
230 context->lo |= 1;
231}
232
233static inline void context_set_fault_enable(struct context_entry *context)
234{
235 context->lo &= (((u64)-1) << 2) | 1;
236}
237
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000238static inline void context_set_translation_type(struct context_entry *context,
239 unsigned long value)
240{
241 context->lo &= (((u64)-1) << 4) | 3;
242 context->lo |= (value & 3) << 2;
243}
244
245static inline void context_set_address_root(struct context_entry *context,
246 unsigned long value)
247{
248 context->lo |= value & VTD_PAGE_MASK;
249}
250
251static inline void context_set_address_width(struct context_entry *context,
252 unsigned long value)
253{
254 context->hi |= value & 7;
255}
256
257static inline void context_set_domain_id(struct context_entry *context,
258 unsigned long value)
259{
260 context->hi |= (value & ((1 << 16) - 1)) << 8;
261}
262
263static inline void context_clear_entry(struct context_entry *context)
264{
265 context->lo = 0;
266 context->hi = 0;
267}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000268
Mark McLoughlin622ba122008-11-20 15:49:46 +0000269/*
270 * 0: readable
271 * 1: writable
272 * 2-6: reserved
273 * 7: super page
Sheng Yang9cf06692009-03-18 15:33:07 +0800274 * 8-10: available
275 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000276 * 12-63: Host physcial address
277 */
278struct dma_pte {
279 u64 val;
280};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000281
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000282static inline void dma_clear_pte(struct dma_pte *pte)
283{
284 pte->val = 0;
285}
286
287static inline void dma_set_pte_readable(struct dma_pte *pte)
288{
289 pte->val |= DMA_PTE_READ;
290}
291
292static inline void dma_set_pte_writable(struct dma_pte *pte)
293{
294 pte->val |= DMA_PTE_WRITE;
295}
296
Sheng Yang9cf06692009-03-18 15:33:07 +0800297static inline void dma_set_pte_snp(struct dma_pte *pte)
298{
299 pte->val |= DMA_PTE_SNP;
300}
301
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000302static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
303{
304 pte->val = (pte->val & ~3) | (prot & 3);
305}
306
307static inline u64 dma_pte_addr(struct dma_pte *pte)
308{
David Woodhousec85994e2009-07-01 19:21:24 +0100309#ifdef CONFIG_64BIT
310 return pte->val & VTD_PAGE_MASK;
311#else
312 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100313 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100314#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000315}
316
David Woodhousedd4e8312009-06-27 16:21:20 +0100317static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000318{
David Woodhousedd4e8312009-06-27 16:21:20 +0100319 pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000320}
321
322static inline bool dma_pte_present(struct dma_pte *pte)
323{
324 return (pte->val & 3) != 0;
325}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000326
Allen Kay4399c8b2011-10-14 12:32:46 -0700327static inline bool dma_pte_superpage(struct dma_pte *pte)
328{
329 return (pte->val & (1 << 7));
330}
331
David Woodhouse75e6bf92009-07-02 11:21:16 +0100332static inline int first_pte_in_page(struct dma_pte *pte)
333{
334 return !((unsigned long)pte & ~VTD_PAGE_MASK);
335}
336
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700337/*
338 * This domain is a statically identity mapping domain.
339 * 1. This domain creats a static 1:1 mapping to all usable memory.
340 * 2. It maps to each iommu if successful.
341 * 3. Each iommu mapps to this domain if successful.
342 */
David Woodhouse19943b02009-08-04 16:19:20 +0100343static struct dmar_domain *si_domain;
344static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700345
Weidong Han3b5410e2008-12-08 09:17:15 +0800346/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100347#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800348
Weidong Han1ce28fe2008-12-08 16:35:39 +0800349/* domain represents a virtual machine, more than one devices
350 * across iommus may be owned in one domain, e.g. kvm guest.
351 */
352#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
353
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700354/* si_domain contains mulitple devices */
355#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
356
Mike Travis1b198bb2012-03-05 15:05:16 -0800357/* define the limit of IOMMUs supported in each domain */
358#ifdef CONFIG_X86
359# define IOMMU_UNITS_SUPPORTED MAX_IO_APICS
360#else
361# define IOMMU_UNITS_SUPPORTED 64
362#endif
363
Mark McLoughlin99126f72008-11-20 15:49:47 +0000364struct dmar_domain {
365 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700366 int nid; /* node id */
Mike Travis1b198bb2012-03-05 15:05:16 -0800367 DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
368 /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000369
370 struct list_head devices; /* all devices' list */
371 struct iova_domain iovad; /* iova's that belong to this domain */
372
373 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000374 int gaw; /* max guest address width */
375
376 /* adjusted guest address width, 0 is level 2 30-bit */
377 int agaw;
378
Weidong Han3b5410e2008-12-08 09:17:15 +0800379 int flags; /* flags to find out type of domain */
Weidong Han8e604092008-12-08 15:49:06 +0800380
381 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800382 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800383 int iommu_count; /* reference count of iommu */
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100384 int iommu_superpage;/* Level of superpages supported:
385 0 == 4KiB (no superpages), 1 == 2MiB,
386 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
Weidong Hanc7151a82008-12-08 22:51:37 +0800387 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800388 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000389};
390
Mark McLoughlina647dac2008-11-20 15:49:48 +0000391/* PCI domain-device relationship */
392struct device_domain_info {
393 struct list_head link; /* link to domain siblings */
394 struct list_head global; /* link to global list */
David Woodhouse276dbf92009-04-04 01:45:37 +0100395 int segment; /* PCI domain */
396 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000397 u8 devfn; /* PCI devfn number */
Stefan Assmann45e829e2009-12-03 06:49:24 -0500398 struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800399 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000400 struct dmar_domain *domain; /* pointer to domain */
401};
402
mark gross5e0d2a62008-03-04 15:22:08 -0800403static void flush_unmaps_timeout(unsigned long data);
404
405DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
406
mark gross80b20dd2008-04-18 13:53:58 -0700407#define HIGH_WATER_MARK 250
408struct deferred_flush_tables {
409 int next;
410 struct iova *iova[HIGH_WATER_MARK];
411 struct dmar_domain *domain[HIGH_WATER_MARK];
412};
413
414static struct deferred_flush_tables *deferred_flush;
415
mark gross5e0d2a62008-03-04 15:22:08 -0800416/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800417static int g_num_of_iommus;
418
419static DEFINE_SPINLOCK(async_umap_flush_lock);
420static LIST_HEAD(unmaps_to_do);
421
422static int timer_on;
423static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800424
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700425static void domain_remove_dev_info(struct dmar_domain *domain);
426
Suresh Siddhad3f13812011-08-23 17:05:25 -0700427#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800428int dmar_disabled = 0;
429#else
430int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700431#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800432
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200433int intel_iommu_enabled = 0;
434EXPORT_SYMBOL_GPL(intel_iommu_enabled);
435
David Woodhouse2d9e6672010-06-15 10:57:57 +0100436static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700437static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800438static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100439static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700440
David Woodhousec0771df2011-10-14 20:59:46 +0100441int intel_iommu_gfx_mapped;
442EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
443
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700444#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
445static DEFINE_SPINLOCK(device_domain_lock);
446static LIST_HEAD(device_domain_list);
447
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100448static struct iommu_ops intel_iommu_ops;
449
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700450static int __init intel_iommu_setup(char *str)
451{
452 if (!str)
453 return -EINVAL;
454 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800455 if (!strncmp(str, "on", 2)) {
456 dmar_disabled = 0;
457 printk(KERN_INFO "Intel-IOMMU: enabled\n");
458 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700459 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800460 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700461 } else if (!strncmp(str, "igfx_off", 8)) {
462 dmar_map_gfx = 0;
463 printk(KERN_INFO
464 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700465 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800466 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700467 "Intel-IOMMU: Forcing DAC for PCI devices\n");
468 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800469 } else if (!strncmp(str, "strict", 6)) {
470 printk(KERN_INFO
471 "Intel-IOMMU: disable batched IOTLB flush\n");
472 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100473 } else if (!strncmp(str, "sp_off", 6)) {
474 printk(KERN_INFO
475 "Intel-IOMMU: disable supported super page\n");
476 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700477 }
478
479 str += strcspn(str, ",");
480 while (*str == ',')
481 str++;
482 }
483 return 0;
484}
485__setup("intel_iommu=", intel_iommu_setup);
486
487static struct kmem_cache *iommu_domain_cache;
488static struct kmem_cache *iommu_devinfo_cache;
489static struct kmem_cache *iommu_iova_cache;
490
Suresh Siddha4c923d42009-10-02 11:01:24 -0700491static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700492{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700493 struct page *page;
494 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700495
Suresh Siddha4c923d42009-10-02 11:01:24 -0700496 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
497 if (page)
498 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700499 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700500}
501
502static inline void free_pgtable_page(void *vaddr)
503{
504 free_page((unsigned long)vaddr);
505}
506
507static inline void *alloc_domain_mem(void)
508{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900509 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700510}
511
Kay, Allen M38717942008-09-09 18:37:29 +0300512static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700513{
514 kmem_cache_free(iommu_domain_cache, vaddr);
515}
516
517static inline void * alloc_devinfo_mem(void)
518{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900519 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700520}
521
522static inline void free_devinfo_mem(void *vaddr)
523{
524 kmem_cache_free(iommu_devinfo_cache, vaddr);
525}
526
527struct iova *alloc_iova_mem(void)
528{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900529 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700530}
531
532void free_iova_mem(struct iova *iova)
533{
534 kmem_cache_free(iommu_iova_cache, iova);
535}
536
Weidong Han1b573682008-12-08 15:34:06 +0800537
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700538static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800539{
540 unsigned long sagaw;
541 int agaw = -1;
542
543 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700544 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800545 agaw >= 0; agaw--) {
546 if (test_bit(agaw, &sagaw))
547 break;
548 }
549
550 return agaw;
551}
552
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700553/*
554 * Calculate max SAGAW for each iommu.
555 */
556int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
557{
558 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
559}
560
561/*
562 * calculate agaw for each iommu.
563 * "SAGAW" may be different across iommus, use a default agaw, and
564 * get a supported less agaw for iommus that don't support the default agaw.
565 */
566int iommu_calculate_agaw(struct intel_iommu *iommu)
567{
568 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
569}
570
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700571/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800572static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
573{
574 int iommu_id;
575
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700576 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800577 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700578 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800579
Mike Travis1b198bb2012-03-05 15:05:16 -0800580 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800581 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
582 return NULL;
583
584 return g_iommus[iommu_id];
585}
586
Weidong Han8e604092008-12-08 15:49:06 +0800587static void domain_update_iommu_coherency(struct dmar_domain *domain)
588{
589 int i;
590
Alex Williamson63b2f082011-11-11 17:26:44 -0700591 i = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
592
593 domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0;
Weidong Han8e604092008-12-08 15:49:06 +0800594
Mike Travis1b198bb2012-03-05 15:05:16 -0800595 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e604092008-12-08 15:49:06 +0800596 if (!ecap_coherent(g_iommus[i]->ecap)) {
597 domain->iommu_coherency = 0;
598 break;
599 }
Weidong Han8e604092008-12-08 15:49:06 +0800600 }
601}
602
Sheng Yang58c610b2009-03-18 15:33:05 +0800603static void domain_update_iommu_snooping(struct dmar_domain *domain)
604{
605 int i;
606
607 domain->iommu_snooping = 1;
608
Mike Travis1b198bb2012-03-05 15:05:16 -0800609 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800610 if (!ecap_sc_support(g_iommus[i]->ecap)) {
611 domain->iommu_snooping = 0;
612 break;
613 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800614 }
615}
616
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100617static void domain_update_iommu_superpage(struct dmar_domain *domain)
618{
Allen Kay8140a952011-10-14 12:32:17 -0700619 struct dmar_drhd_unit *drhd;
620 struct intel_iommu *iommu = NULL;
621 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100622
623 if (!intel_iommu_superpage) {
624 domain->iommu_superpage = 0;
625 return;
626 }
627
Allen Kay8140a952011-10-14 12:32:17 -0700628 /* set iommu_superpage to the smallest common denominator */
629 for_each_active_iommu(iommu, drhd) {
630 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100631 if (!mask) {
632 break;
633 }
634 }
635 domain->iommu_superpage = fls(mask);
636}
637
Sheng Yang58c610b2009-03-18 15:33:05 +0800638/* Some capabilities may be different across iommus */
639static void domain_update_iommu_cap(struct dmar_domain *domain)
640{
641 domain_update_iommu_coherency(domain);
642 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100643 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800644}
645
David Woodhouse276dbf92009-04-04 01:45:37 +0100646static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800647{
648 struct dmar_drhd_unit *drhd = NULL;
649 int i;
650
651 for_each_drhd_unit(drhd) {
652 if (drhd->ignored)
653 continue;
David Woodhouse276dbf92009-04-04 01:45:37 +0100654 if (segment != drhd->segment)
655 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800656
David Woodhouse924b6232009-04-04 00:39:25 +0100657 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000658 if (drhd->devices[i] &&
659 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800660 drhd->devices[i]->devfn == devfn)
661 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700662 if (drhd->devices[i] &&
663 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100664 drhd->devices[i]->subordinate->number <= bus &&
665 drhd->devices[i]->subordinate->subordinate >= bus)
666 return drhd->iommu;
667 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800668
669 if (drhd->include_all)
670 return drhd->iommu;
671 }
672
673 return NULL;
674}
675
Weidong Han5331fe62008-12-08 23:00:00 +0800676static void domain_flush_cache(struct dmar_domain *domain,
677 void *addr, int size)
678{
679 if (!domain->iommu_coherency)
680 clflush_cache_range(addr, size);
681}
682
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700683/* Gets context entry for a given bus and devfn */
684static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
685 u8 bus, u8 devfn)
686{
687 struct root_entry *root;
688 struct context_entry *context;
689 unsigned long phy_addr;
690 unsigned long flags;
691
692 spin_lock_irqsave(&iommu->lock, flags);
693 root = &iommu->root_entry[bus];
694 context = get_context_addr_from_root(root);
695 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700696 context = (struct context_entry *)
697 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700698 if (!context) {
699 spin_unlock_irqrestore(&iommu->lock, flags);
700 return NULL;
701 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700702 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700703 phy_addr = virt_to_phys((void *)context);
704 set_root_value(root, phy_addr);
705 set_root_present(root);
706 __iommu_flush_cache(iommu, root, sizeof(*root));
707 }
708 spin_unlock_irqrestore(&iommu->lock, flags);
709 return &context[devfn];
710}
711
712static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
713{
714 struct root_entry *root;
715 struct context_entry *context;
716 int ret;
717 unsigned long flags;
718
719 spin_lock_irqsave(&iommu->lock, flags);
720 root = &iommu->root_entry[bus];
721 context = get_context_addr_from_root(root);
722 if (!context) {
723 ret = 0;
724 goto out;
725 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000726 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700727out:
728 spin_unlock_irqrestore(&iommu->lock, flags);
729 return ret;
730}
731
732static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
733{
734 struct root_entry *root;
735 struct context_entry *context;
736 unsigned long flags;
737
738 spin_lock_irqsave(&iommu->lock, flags);
739 root = &iommu->root_entry[bus];
740 context = get_context_addr_from_root(root);
741 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000742 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700743 __iommu_flush_cache(iommu, &context[devfn], \
744 sizeof(*context));
745 }
746 spin_unlock_irqrestore(&iommu->lock, flags);
747}
748
749static void free_context_table(struct intel_iommu *iommu)
750{
751 struct root_entry *root;
752 int i;
753 unsigned long flags;
754 struct context_entry *context;
755
756 spin_lock_irqsave(&iommu->lock, flags);
757 if (!iommu->root_entry) {
758 goto out;
759 }
760 for (i = 0; i < ROOT_ENTRY_NR; i++) {
761 root = &iommu->root_entry[i];
762 context = get_context_addr_from_root(root);
763 if (context)
764 free_pgtable_page(context);
765 }
766 free_pgtable_page(iommu->root_entry);
767 iommu->root_entry = NULL;
768out:
769 spin_unlock_irqrestore(&iommu->lock, flags);
770}
771
David Woodhouseb026fd22009-06-28 10:37:25 +0100772static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
Allen Kay4399c8b2011-10-14 12:32:46 -0700773 unsigned long pfn, int target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700774{
David Woodhouseb026fd22009-06-28 10:37:25 +0100775 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700776 struct dma_pte *parent, *pte = NULL;
777 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700778 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700779
780 BUG_ON(!domain->pgd);
Julian Stecklina3dc062d2013-10-09 10:03:52 +0200781
782 if (addr_width < BITS_PER_LONG && pfn >> addr_width)
783 /* Address beyond IOMMU's addressing capabilities. */
784 return NULL;
785
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700786 parent = domain->pgd;
787
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700788 while (level > 0) {
789 void *tmp_page;
790
David Woodhouseb026fd22009-06-28 10:37:25 +0100791 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700792 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700793 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100794 break;
795 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700796 break;
797
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000798 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100799 uint64_t pteval;
800
Suresh Siddha4c923d42009-10-02 11:01:24 -0700801 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700802
David Woodhouse206a73c2009-07-01 19:30:28 +0100803 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700804 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100805
David Woodhousec85994e2009-07-01 19:21:24 +0100806 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400807 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 +0100808 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
809 /* Someone else set it while we were thinking; use theirs. */
810 free_pgtable_page(tmp_page);
811 } else {
812 dma_pte_addr(pte);
813 domain_flush_cache(domain, pte, sizeof(*pte));
814 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700815 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000816 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700817 level--;
818 }
819
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700820 return pte;
821}
822
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100823
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700824/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100825static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
826 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100827 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700828{
829 struct dma_pte *parent, *pte = NULL;
830 int total = agaw_to_level(domain->agaw);
831 int offset;
832
833 parent = domain->pgd;
834 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100835 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700836 pte = &parent[offset];
837 if (level == total)
838 return pte;
839
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100840 if (!dma_pte_present(pte)) {
841 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700842 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100843 }
844
845 if (pte->val & DMA_PTE_LARGE_PAGE) {
846 *large_page = total;
847 return pte;
848 }
849
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000850 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700851 total--;
852 }
853 return NULL;
854}
855
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700856/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700857static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100858 unsigned long start_pfn,
859 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700860{
David Woodhouse04b18e62009-06-27 19:15:01 +0100861 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100862 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100863 struct dma_pte *first_pte, *pte;
Allen Kay292827c2011-10-14 12:31:54 -0700864 int order;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700865
David Woodhouse04b18e62009-06-27 19:15:01 +0100866 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100867 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700868 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100869
David Woodhouse04b18e62009-06-27 19:15:01 +0100870 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700871 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100872 large_page = 1;
873 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100874 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100875 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100876 continue;
877 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100878 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100879 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100880 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100881 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100882 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
883
David Woodhouse310a5ab2009-06-28 18:52:20 +0100884 domain_flush_cache(domain, first_pte,
885 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700886
887 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700888
889 order = (large_page - 1) * 9;
890 return order;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700891}
892
Alex Williamson4013fc22013-06-15 10:27:19 -0600893static void dma_pte_free_level(struct dmar_domain *domain, int level,
894 struct dma_pte *pte, unsigned long pfn,
895 unsigned long start_pfn, unsigned long last_pfn)
896{
897 pfn = max(start_pfn, pfn);
898 pte = &pte[pfn_level_offset(pfn, level)];
899
900 do {
901 unsigned long level_pfn;
902 struct dma_pte *level_pte;
903
904 if (!dma_pte_present(pte) || dma_pte_superpage(pte))
905 goto next;
906
907 level_pfn = pfn & level_mask(level - 1);
908 level_pte = phys_to_virt(dma_pte_addr(pte));
909
910 if (level > 2)
911 dma_pte_free_level(domain, level - 1, level_pte,
912 level_pfn, start_pfn, last_pfn);
913
914 /* If range covers entire pagetable, free it */
915 if (!(start_pfn > level_pfn ||
Alex Williamson55931652014-01-21 15:48:18 -0800916 last_pfn < level_pfn + level_size(level) - 1)) {
Alex Williamson4013fc22013-06-15 10:27:19 -0600917 dma_clear_pte(pte);
918 domain_flush_cache(domain, pte, sizeof(*pte));
919 free_pgtable_page(level_pte);
920 }
921next:
922 pfn += level_size(level);
923 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
924}
925
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700926/* free page table pages. last level pte should already be cleared */
927static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100928 unsigned long start_pfn,
929 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700930{
David Woodhouse6660c632009-06-27 22:41:00 +0100931 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700932
David Woodhouse6660c632009-06-27 22:41:00 +0100933 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
934 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700935 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700936
David Woodhousef3a0a522009-06-30 03:40:07 +0100937 /* We don't need lock here; nobody else touches the iova range */
Alex Williamson4013fc22013-06-15 10:27:19 -0600938 dma_pte_free_level(domain, agaw_to_level(domain->agaw),
939 domain->pgd, 0, start_pfn, last_pfn);
David Woodhouse6660c632009-06-27 22:41:00 +0100940
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700941 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100942 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700943 free_pgtable_page(domain->pgd);
944 domain->pgd = NULL;
945 }
946}
947
948/* iommu handling */
949static int iommu_alloc_root_entry(struct intel_iommu *iommu)
950{
951 struct root_entry *root;
952 unsigned long flags;
953
Suresh Siddha4c923d42009-10-02 11:01:24 -0700954 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700955 if (!root)
956 return -ENOMEM;
957
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700958 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700959
960 spin_lock_irqsave(&iommu->lock, flags);
961 iommu->root_entry = root;
962 spin_unlock_irqrestore(&iommu->lock, flags);
963
964 return 0;
965}
966
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700967static void iommu_set_root_entry(struct intel_iommu *iommu)
968{
969 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100970 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700971 unsigned long flag;
972
973 addr = iommu->root_entry;
974
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200975 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700976 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
977
David Woodhousec416daa2009-05-10 20:30:58 +0100978 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700979
980 /* Make sure hardware complete it */
981 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100982 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700983
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200984 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700985}
986
987static void iommu_flush_write_buffer(struct intel_iommu *iommu)
988{
989 u32 val;
990 unsigned long flag;
991
David Woodhouse9af88142009-02-13 23:18:03 +0000992 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700993 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700994
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200995 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100996 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700997
998 /* Make sure hardware complete it */
999 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001000 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001001
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001002 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001003}
1004
1005/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001006static void __iommu_flush_context(struct intel_iommu *iommu,
1007 u16 did, u16 source_id, u8 function_mask,
1008 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001009{
1010 u64 val = 0;
1011 unsigned long flag;
1012
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001013 switch (type) {
1014 case DMA_CCMD_GLOBAL_INVL:
1015 val = DMA_CCMD_GLOBAL_INVL;
1016 break;
1017 case DMA_CCMD_DOMAIN_INVL:
1018 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1019 break;
1020 case DMA_CCMD_DEVICE_INVL:
1021 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1022 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1023 break;
1024 default:
1025 BUG();
1026 }
1027 val |= DMA_CCMD_ICC;
1028
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001029 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001030 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1031
1032 /* Make sure hardware complete it */
1033 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1034 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1035
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001036 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001037}
1038
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001039/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001040static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1041 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001042{
1043 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1044 u64 val = 0, val_iva = 0;
1045 unsigned long flag;
1046
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001047 switch (type) {
1048 case DMA_TLB_GLOBAL_FLUSH:
1049 /* global flush doesn't need set IVA_REG */
1050 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1051 break;
1052 case DMA_TLB_DSI_FLUSH:
1053 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1054 break;
1055 case DMA_TLB_PSI_FLUSH:
1056 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1057 /* Note: always flush non-leaf currently */
1058 val_iva = size_order | addr;
1059 break;
1060 default:
1061 BUG();
1062 }
1063 /* Note: set drain read/write */
1064#if 0
1065 /*
1066 * This is probably to be super secure.. Looks like we can
1067 * ignore it without any impact.
1068 */
1069 if (cap_read_drain(iommu->cap))
1070 val |= DMA_TLB_READ_DRAIN;
1071#endif
1072 if (cap_write_drain(iommu->cap))
1073 val |= DMA_TLB_WRITE_DRAIN;
1074
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001075 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001076 /* Note: Only uses first TLB reg currently */
1077 if (val_iva)
1078 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1079 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1080
1081 /* Make sure hardware complete it */
1082 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1083 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1084
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001085 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001086
1087 /* check IOTLB invalidation granularity */
1088 if (DMA_TLB_IAIG(val) == 0)
1089 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1090 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1091 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001092 (unsigned long long)DMA_TLB_IIRG(type),
1093 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001094}
1095
Yu Zhao93a23a72009-05-18 13:51:37 +08001096static struct device_domain_info *iommu_support_dev_iotlb(
1097 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001098{
Yu Zhao93a23a72009-05-18 13:51:37 +08001099 int found = 0;
1100 unsigned long flags;
1101 struct device_domain_info *info;
1102 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1103
1104 if (!ecap_dev_iotlb_support(iommu->ecap))
1105 return NULL;
1106
1107 if (!iommu->qi)
1108 return NULL;
1109
1110 spin_lock_irqsave(&device_domain_lock, flags);
1111 list_for_each_entry(info, &domain->devices, link)
1112 if (info->bus == bus && info->devfn == devfn) {
1113 found = 1;
1114 break;
1115 }
1116 spin_unlock_irqrestore(&device_domain_lock, flags);
1117
1118 if (!found || !info->dev)
1119 return NULL;
1120
1121 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1122 return NULL;
1123
1124 if (!dmar_find_matched_atsr_unit(info->dev))
1125 return NULL;
1126
1127 info->iommu = iommu;
1128
1129 return info;
1130}
1131
1132static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1133{
1134 if (!info)
1135 return;
1136
1137 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1138}
1139
1140static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1141{
1142 if (!info->dev || !pci_ats_enabled(info->dev))
1143 return;
1144
1145 pci_disable_ats(info->dev);
1146}
1147
1148static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1149 u64 addr, unsigned mask)
1150{
1151 u16 sid, qdep;
1152 unsigned long flags;
1153 struct device_domain_info *info;
1154
1155 spin_lock_irqsave(&device_domain_lock, flags);
1156 list_for_each_entry(info, &domain->devices, link) {
1157 if (!info->dev || !pci_ats_enabled(info->dev))
1158 continue;
1159
1160 sid = info->bus << 8 | info->devfn;
1161 qdep = pci_ats_queue_depth(info->dev);
1162 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1163 }
1164 spin_unlock_irqrestore(&device_domain_lock, flags);
1165}
1166
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001167static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001168 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001169{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001170 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001171 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001172
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001173 BUG_ON(pages == 0);
1174
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001175 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001176 * Fallback to domain selective flush if no PSI support or the size is
1177 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001178 * PSI requires page size to be 2 ^ x, and the base address is naturally
1179 * aligned to the size
1180 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001181 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1182 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001183 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001184 else
1185 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1186 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001187
1188 /*
Nadav Amit82653632010-04-01 13:24:40 +03001189 * In caching mode, changes of pages from non-present to present require
1190 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001191 */
Nadav Amit82653632010-04-01 13:24:40 +03001192 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001193 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001194}
1195
mark grossf8bab732008-02-08 04:18:38 -08001196static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1197{
1198 u32 pmen;
1199 unsigned long flags;
1200
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001201 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001202 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1203 pmen &= ~DMA_PMEN_EPM;
1204 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1205
1206 /* wait for the protected region status bit to clear */
1207 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1208 readl, !(pmen & DMA_PMEN_PRS), pmen);
1209
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001210 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001211}
1212
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001213static int iommu_enable_translation(struct intel_iommu *iommu)
1214{
1215 u32 sts;
1216 unsigned long flags;
1217
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001218 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001219 iommu->gcmd |= DMA_GCMD_TE;
1220 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001221
1222 /* Make sure hardware complete it */
1223 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001224 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001225
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001226 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001227 return 0;
1228}
1229
1230static int iommu_disable_translation(struct intel_iommu *iommu)
1231{
1232 u32 sts;
1233 unsigned long flag;
1234
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001235 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001236 iommu->gcmd &= ~DMA_GCMD_TE;
1237 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1238
1239 /* Make sure hardware complete it */
1240 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001241 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001242
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001243 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001244 return 0;
1245}
1246
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001247
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001248static int iommu_init_domains(struct intel_iommu *iommu)
1249{
1250 unsigned long ndomains;
1251 unsigned long nlongs;
1252
1253 ndomains = cap_ndoms(iommu->cap);
Masanari Iida68aeb962012-01-25 00:25:52 +09001254 pr_debug("IOMMU %d: Number of Domains supported <%ld>\n", iommu->seq_id,
Yinghai Lu680a7522010-04-08 19:58:23 +01001255 ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001256 nlongs = BITS_TO_LONGS(ndomains);
1257
Donald Dutile94a91b52009-08-20 16:51:34 -04001258 spin_lock_init(&iommu->lock);
1259
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001260 /* TBD: there might be 64K domains,
1261 * consider other allocation for future chip
1262 */
1263 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1264 if (!iommu->domain_ids) {
1265 printk(KERN_ERR "Allocating domain id array failed\n");
1266 return -ENOMEM;
1267 }
1268 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1269 GFP_KERNEL);
1270 if (!iommu->domains) {
1271 printk(KERN_ERR "Allocating domain array failed\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001272 return -ENOMEM;
1273 }
1274
1275 /*
1276 * if Caching mode is set, then invalid translations are tagged
1277 * with domainid 0. Hence we need to pre-allocate it.
1278 */
1279 if (cap_caching_mode(iommu->cap))
1280 set_bit(0, iommu->domain_ids);
1281 return 0;
1282}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001283
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001284
1285static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001286static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001287
1288void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001289{
1290 struct dmar_domain *domain;
1291 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001292 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001293
Donald Dutile94a91b52009-08-20 16:51:34 -04001294 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001295 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001296 domain = iommu->domains[i];
1297 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001298
Donald Dutile94a91b52009-08-20 16:51:34 -04001299 spin_lock_irqsave(&domain->iommu_lock, flags);
1300 if (--domain->iommu_count == 0) {
1301 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1302 vm_domain_exit(domain);
1303 else
1304 domain_exit(domain);
1305 }
1306 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001307 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001308 }
1309
1310 if (iommu->gcmd & DMA_GCMD_TE)
1311 iommu_disable_translation(iommu);
1312
1313 if (iommu->irq) {
Thomas Gleixnerdced35a2011-03-28 17:49:12 +02001314 irq_set_handler_data(iommu->irq, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001315 /* This will mask the irq */
1316 free_irq(iommu->irq, iommu);
1317 destroy_irq(iommu->irq);
1318 }
1319
1320 kfree(iommu->domains);
1321 kfree(iommu->domain_ids);
1322
Weidong Hand9630fe2008-12-08 11:06:32 +08001323 g_iommus[iommu->seq_id] = NULL;
1324
1325 /* if all iommus are freed, free g_iommus */
1326 for (i = 0; i < g_num_of_iommus; i++) {
1327 if (g_iommus[i])
1328 break;
1329 }
1330
1331 if (i == g_num_of_iommus)
1332 kfree(g_iommus);
1333
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001334 /* free context mapping */
1335 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001336}
1337
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001338static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001339{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001340 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001341
1342 domain = alloc_domain_mem();
1343 if (!domain)
1344 return NULL;
1345
Suresh Siddha4c923d42009-10-02 11:01:24 -07001346 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08001347 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001348 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001349
1350 return domain;
1351}
1352
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001353static int iommu_attach_domain(struct dmar_domain *domain,
1354 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001355{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001356 int num;
1357 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001358 unsigned long flags;
1359
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001360 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001361
1362 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001363
1364 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1365 if (num >= ndomains) {
1366 spin_unlock_irqrestore(&iommu->lock, flags);
1367 printk(KERN_ERR "IOMMU: no free domain ids\n");
1368 return -ENOMEM;
1369 }
1370
1371 domain->id = num;
1372 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001373 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001374 iommu->domains[num] = domain;
1375 spin_unlock_irqrestore(&iommu->lock, flags);
1376
1377 return 0;
1378}
1379
1380static void iommu_detach_domain(struct dmar_domain *domain,
1381 struct intel_iommu *iommu)
1382{
1383 unsigned long flags;
1384 int num, ndomains;
1385 int found = 0;
1386
1387 spin_lock_irqsave(&iommu->lock, flags);
1388 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001389 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001390 if (iommu->domains[num] == domain) {
1391 found = 1;
1392 break;
1393 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001394 }
1395
1396 if (found) {
1397 clear_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001398 clear_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001399 iommu->domains[num] = NULL;
1400 }
Weidong Han8c11e792008-12-08 15:29:22 +08001401 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001402}
1403
1404static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001405static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001406
Joseph Cihula51a63e62011-03-21 11:04:24 -07001407static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001408{
1409 struct pci_dev *pdev = NULL;
1410 struct iova *iova;
1411 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001412
David Millerf6611972008-02-06 01:36:23 -08001413 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001414
Mark Gross8a443df2008-03-04 14:59:31 -08001415 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1416 &reserved_rbtree_key);
1417
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001418 /* IOAPIC ranges shouldn't be accessed by DMA */
1419 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1420 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001421 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001422 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001423 return -ENODEV;
1424 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001425
1426 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1427 for_each_pci_dev(pdev) {
1428 struct resource *r;
1429
1430 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1431 r = &pdev->resource[i];
1432 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1433 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001434 iova = reserve_iova(&reserved_iova_list,
1435 IOVA_PFN(r->start),
1436 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001437 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001438 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001439 return -ENODEV;
1440 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001441 }
1442 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001443 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001444}
1445
1446static void domain_reserve_special_ranges(struct dmar_domain *domain)
1447{
1448 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1449}
1450
1451static inline int guestwidth_to_adjustwidth(int gaw)
1452{
1453 int agaw;
1454 int r = (gaw - 12) % 9;
1455
1456 if (r == 0)
1457 agaw = gaw;
1458 else
1459 agaw = gaw + 9 - r;
1460 if (agaw > 64)
1461 agaw = 64;
1462 return agaw;
1463}
1464
1465static int domain_init(struct dmar_domain *domain, int guest_width)
1466{
1467 struct intel_iommu *iommu;
1468 int adjust_width, agaw;
1469 unsigned long sagaw;
1470
David Millerf6611972008-02-06 01:36:23 -08001471 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001472 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001473
1474 domain_reserve_special_ranges(domain);
1475
1476 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001477 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001478 if (guest_width > cap_mgaw(iommu->cap))
1479 guest_width = cap_mgaw(iommu->cap);
1480 domain->gaw = guest_width;
1481 adjust_width = guestwidth_to_adjustwidth(guest_width);
1482 agaw = width_to_agaw(adjust_width);
1483 sagaw = cap_sagaw(iommu->cap);
1484 if (!test_bit(agaw, &sagaw)) {
1485 /* hardware doesn't support it, choose a bigger one */
1486 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1487 agaw = find_next_bit(&sagaw, 5, agaw);
1488 if (agaw >= 5)
1489 return -ENODEV;
1490 }
1491 domain->agaw = agaw;
1492 INIT_LIST_HEAD(&domain->devices);
1493
Weidong Han8e604092008-12-08 15:49:06 +08001494 if (ecap_coherent(iommu->ecap))
1495 domain->iommu_coherency = 1;
1496 else
1497 domain->iommu_coherency = 0;
1498
Sheng Yang58c610b2009-03-18 15:33:05 +08001499 if (ecap_sc_support(iommu->ecap))
1500 domain->iommu_snooping = 1;
1501 else
1502 domain->iommu_snooping = 0;
1503
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001504 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Weidong Hanc7151a82008-12-08 22:51:37 +08001505 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001506 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001507
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001508 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001509 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001510 if (!domain->pgd)
1511 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001512 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001513 return 0;
1514}
1515
1516static void domain_exit(struct dmar_domain *domain)
1517{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001518 struct dmar_drhd_unit *drhd;
1519 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001520
1521 /* Domain 0 is reserved, so dont process it */
1522 if (!domain)
1523 return;
1524
Alex Williamson7b668352011-05-24 12:02:41 +01001525 /* Flush any lazy unmaps that may reference this domain */
1526 if (!intel_iommu_strict)
1527 flush_unmaps_timeout(0);
1528
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001529 domain_remove_dev_info(domain);
1530 /* destroy iovas */
1531 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001532
1533 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001534 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001535
1536 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001537 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001538
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001539 for_each_active_iommu(iommu, drhd)
Mike Travis1b198bb2012-03-05 15:05:16 -08001540 if (test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001541 iommu_detach_domain(domain, iommu);
1542
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001543 free_domain_mem(domain);
1544}
1545
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001546static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1547 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001548{
1549 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001550 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001551 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001552 struct dma_pte *pgd;
1553 unsigned long num;
1554 unsigned long ndomains;
1555 int id;
1556 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001557 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001558
1559 pr_debug("Set context mapping for %02x:%02x.%d\n",
1560 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001561
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001562 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001563 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1564 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001565
David Woodhouse276dbf92009-04-04 01:45:37 +01001566 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001567 if (!iommu)
1568 return -ENODEV;
1569
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001570 context = device_to_context_entry(iommu, bus, devfn);
1571 if (!context)
1572 return -ENOMEM;
1573 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001574 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001575 spin_unlock_irqrestore(&iommu->lock, flags);
1576 return 0;
1577 }
1578
Weidong Hanea6606b2008-12-08 23:08:15 +08001579 id = domain->id;
1580 pgd = domain->pgd;
1581
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001582 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1583 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001584 int found = 0;
1585
1586 /* find an available domain id for this device in iommu */
1587 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001588 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001589 if (iommu->domains[num] == domain) {
1590 id = num;
1591 found = 1;
1592 break;
1593 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001594 }
1595
1596 if (found == 0) {
1597 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1598 if (num >= ndomains) {
1599 spin_unlock_irqrestore(&iommu->lock, flags);
1600 printk(KERN_ERR "IOMMU: no free domain ids\n");
1601 return -EFAULT;
1602 }
1603
1604 set_bit(num, iommu->domain_ids);
1605 iommu->domains[num] = domain;
1606 id = num;
1607 }
1608
1609 /* Skip top levels of page tables for
1610 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001611 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001612 */
Chris Wright1672af12009-12-02 12:06:34 -08001613 if (translation != CONTEXT_TT_PASS_THROUGH) {
1614 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1615 pgd = phys_to_virt(dma_pte_addr(pgd));
1616 if (!dma_pte_present(pgd)) {
1617 spin_unlock_irqrestore(&iommu->lock, flags);
1618 return -ENOMEM;
1619 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001620 }
1621 }
1622 }
1623
1624 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001625
Yu Zhao93a23a72009-05-18 13:51:37 +08001626 if (translation != CONTEXT_TT_PASS_THROUGH) {
1627 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1628 translation = info ? CONTEXT_TT_DEV_IOTLB :
1629 CONTEXT_TT_MULTI_LEVEL;
1630 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001631 /*
1632 * In pass through mode, AW must be programmed to indicate the largest
1633 * AGAW value supported by hardware. And ASR is ignored by hardware.
1634 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001635 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001636 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001637 else {
1638 context_set_address_root(context, virt_to_phys(pgd));
1639 context_set_address_width(context, iommu->agaw);
1640 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001641
1642 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001643 context_set_fault_enable(context);
1644 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001645 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001646
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001647 /*
1648 * It's a non-present to present mapping. If hardware doesn't cache
1649 * non-present entry we only need to flush the write-buffer. If the
1650 * _does_ cache non-present entries, then it does so in the special
1651 * domain #0, which we have to flush:
1652 */
1653 if (cap_caching_mode(iommu->cap)) {
1654 iommu->flush.flush_context(iommu, 0,
1655 (((u16)bus) << 8) | devfn,
1656 DMA_CCMD_MASK_NOBIT,
1657 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001658 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001659 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001660 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001661 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001662 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001663 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001664
1665 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001666 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001667 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001668 if (domain->iommu_count == 1)
1669 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001670 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001671 }
1672 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001673 return 0;
1674}
1675
1676static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001677domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1678 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001679{
1680 int ret;
1681 struct pci_dev *tmp, *parent;
1682
David Woodhouse276dbf92009-04-04 01:45:37 +01001683 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001684 pdev->bus->number, pdev->devfn,
1685 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001686 if (ret)
1687 return ret;
1688
1689 /* dependent device mapping */
1690 tmp = pci_find_upstream_pcie_bridge(pdev);
1691 if (!tmp)
1692 return 0;
1693 /* Secondary interface's bus number and devfn 0 */
1694 parent = pdev->bus->self;
1695 while (parent != tmp) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001696 ret = domain_context_mapping_one(domain,
1697 pci_domain_nr(parent->bus),
1698 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001699 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001700 if (ret)
1701 return ret;
1702 parent = parent->bus->self;
1703 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001704 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001705 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001706 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001707 tmp->subordinate->number, 0,
1708 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001709 else /* this is a legacy PCI bridge */
1710 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001711 pci_domain_nr(tmp->bus),
1712 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001713 tmp->devfn,
1714 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001715}
1716
Weidong Han5331fe62008-12-08 23:00:00 +08001717static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001718{
1719 int ret;
1720 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001721 struct intel_iommu *iommu;
1722
David Woodhouse276dbf92009-04-04 01:45:37 +01001723 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1724 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001725 if (!iommu)
1726 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001727
David Woodhouse276dbf92009-04-04 01:45:37 +01001728 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001729 if (!ret)
1730 return ret;
1731 /* dependent device mapping */
1732 tmp = pci_find_upstream_pcie_bridge(pdev);
1733 if (!tmp)
1734 return ret;
1735 /* Secondary interface's bus number and devfn 0 */
1736 parent = pdev->bus->self;
1737 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001738 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01001739 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001740 if (!ret)
1741 return ret;
1742 parent = parent->bus->self;
1743 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001744 if (pci_is_pcie(tmp))
David Woodhouse276dbf92009-04-04 01:45:37 +01001745 return device_context_mapped(iommu, tmp->subordinate->number,
1746 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001747 else
David Woodhouse276dbf92009-04-04 01:45:37 +01001748 return device_context_mapped(iommu, tmp->bus->number,
1749 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001750}
1751
Fenghua Yuf5329592009-08-04 15:09:37 -07001752/* Returns a number of VTD pages, but aligned to MM page size */
1753static inline unsigned long aligned_nrpages(unsigned long host_addr,
1754 size_t size)
1755{
1756 host_addr &= ~PAGE_MASK;
1757 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1758}
1759
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001760/* Return largest possible superpage level for a given mapping */
1761static inline int hardware_largepage_caps(struct dmar_domain *domain,
1762 unsigned long iov_pfn,
1763 unsigned long phy_pfn,
1764 unsigned long pages)
1765{
1766 int support, level = 1;
1767 unsigned long pfnmerge;
1768
1769 support = domain->iommu_superpage;
1770
1771 /* To use a large page, the virtual *and* physical addresses
1772 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1773 of them will mean we have to use smaller pages. So just
1774 merge them and check both at once. */
1775 pfnmerge = iov_pfn | phy_pfn;
1776
1777 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1778 pages >>= VTD_STRIDE_SHIFT;
1779 if (!pages)
1780 break;
1781 pfnmerge >>= VTD_STRIDE_SHIFT;
1782 level++;
1783 support--;
1784 }
1785 return level;
1786}
1787
David Woodhouse9051aa02009-06-29 12:30:54 +01001788static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1789 struct scatterlist *sg, unsigned long phys_pfn,
1790 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001791{
1792 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001793 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001794 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001795 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001796 unsigned int largepage_lvl = 0;
1797 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001798
1799 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1800
1801 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1802 return -EINVAL;
1803
1804 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1805
David Woodhouse9051aa02009-06-29 12:30:54 +01001806 if (sg)
1807 sg_res = 0;
1808 else {
1809 sg_res = nr_pages + 1;
1810 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1811 }
1812
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001813 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001814 uint64_t tmp;
1815
David Woodhousee1605492009-06-29 11:17:38 +01001816 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001817 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001818 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1819 sg->dma_length = sg->length;
1820 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001821 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001822 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001823
David Woodhousee1605492009-06-29 11:17:38 +01001824 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001825 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1826
1827 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001828 if (!pte)
1829 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001830 /* It is large page*/
Woodhouse, David16639bc2012-12-19 13:25:35 +00001831 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001832 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David16639bc2012-12-19 13:25:35 +00001833 /* Ensure that old small page tables are removed to make room
1834 for superpage, if they exist. */
1835 dma_pte_clear_range(domain, iov_pfn,
1836 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1837 dma_pte_free_pagetable(domain, iov_pfn,
1838 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1839 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001840 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David16639bc2012-12-19 13:25:35 +00001841 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001842
David Woodhousee1605492009-06-29 11:17:38 +01001843 }
1844 /* We don't need lock here, nobody else
1845 * touches the iova range
1846 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001847 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001848 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001849 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001850 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1851 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001852 if (dumps) {
1853 dumps--;
1854 debug_dma_dump_mappings(NULL);
1855 }
1856 WARN_ON(1);
1857 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001858
1859 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1860
1861 BUG_ON(nr_pages < lvl_pages);
1862 BUG_ON(sg_res < lvl_pages);
1863
1864 nr_pages -= lvl_pages;
1865 iov_pfn += lvl_pages;
1866 phys_pfn += lvl_pages;
1867 pteval += lvl_pages * VTD_PAGE_SIZE;
1868 sg_res -= lvl_pages;
1869
1870 /* If the next PTE would be the first in a new page, then we
1871 need to flush the cache on the entries we've just written.
1872 And then we'll need to recalculate 'pte', so clear it and
1873 let it get set again in the if (!pte) block above.
1874
1875 If we're done (!nr_pages) we need to flush the cache too.
1876
1877 Also if we've been setting superpages, we may need to
1878 recalculate 'pte' and switch back to smaller pages for the
1879 end of the mapping, if the trailing size is not enough to
1880 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001881 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001882 if (!nr_pages || first_pte_in_page(pte) ||
1883 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001884 domain_flush_cache(domain, first_pte,
1885 (void *)pte - (void *)first_pte);
1886 pte = NULL;
1887 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001888
1889 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001890 sg = sg_next(sg);
1891 }
1892 return 0;
1893}
1894
David Woodhouse9051aa02009-06-29 12:30:54 +01001895static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1896 struct scatterlist *sg, unsigned long nr_pages,
1897 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001898{
David Woodhouse9051aa02009-06-29 12:30:54 +01001899 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1900}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001901
David Woodhouse9051aa02009-06-29 12:30:54 +01001902static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1903 unsigned long phys_pfn, unsigned long nr_pages,
1904 int prot)
1905{
1906 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001907}
1908
Weidong Hanc7151a82008-12-08 22:51:37 +08001909static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001910{
Weidong Hanc7151a82008-12-08 22:51:37 +08001911 if (!iommu)
1912 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001913
1914 clear_context_table(iommu, bus, devfn);
1915 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001916 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001917 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001918}
1919
1920static void domain_remove_dev_info(struct dmar_domain *domain)
1921{
1922 struct device_domain_info *info;
1923 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001924 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001925
1926 spin_lock_irqsave(&device_domain_lock, flags);
1927 while (!list_empty(&domain->devices)) {
1928 info = list_entry(domain->devices.next,
1929 struct device_domain_info, link);
1930 list_del(&info->link);
1931 list_del(&info->global);
1932 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001933 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001934 spin_unlock_irqrestore(&device_domain_lock, flags);
1935
Yu Zhao93a23a72009-05-18 13:51:37 +08001936 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01001937 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001938 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001939 free_devinfo_mem(info);
1940
1941 spin_lock_irqsave(&device_domain_lock, flags);
1942 }
1943 spin_unlock_irqrestore(&device_domain_lock, flags);
1944}
1945
1946/*
1947 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001948 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001949 */
Kay, Allen M38717942008-09-09 18:37:29 +03001950static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001951find_domain(struct pci_dev *pdev)
1952{
1953 struct device_domain_info *info;
1954
1955 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001956 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001957 if (info)
1958 return info->domain;
1959 return NULL;
1960}
1961
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001962/* domain is initialized */
1963static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1964{
1965 struct dmar_domain *domain, *found = NULL;
1966 struct intel_iommu *iommu;
1967 struct dmar_drhd_unit *drhd;
1968 struct device_domain_info *info, *tmp;
1969 struct pci_dev *dev_tmp;
1970 unsigned long flags;
1971 int bus = 0, devfn = 0;
David Woodhouse276dbf92009-04-04 01:45:37 +01001972 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001973 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001974
1975 domain = find_domain(pdev);
1976 if (domain)
1977 return domain;
1978
David Woodhouse276dbf92009-04-04 01:45:37 +01001979 segment = pci_domain_nr(pdev->bus);
1980
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001981 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1982 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001983 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001984 bus = dev_tmp->subordinate->number;
1985 devfn = 0;
1986 } else {
1987 bus = dev_tmp->bus->number;
1988 devfn = dev_tmp->devfn;
1989 }
1990 spin_lock_irqsave(&device_domain_lock, flags);
1991 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001992 if (info->segment == segment &&
1993 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001994 found = info->domain;
1995 break;
1996 }
1997 }
1998 spin_unlock_irqrestore(&device_domain_lock, flags);
1999 /* pcie-pci bridge already has a domain, uses it */
2000 if (found) {
2001 domain = found;
2002 goto found_domain;
2003 }
2004 }
2005
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002006 domain = alloc_domain();
2007 if (!domain)
2008 goto error;
2009
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002010 /* Allocate new domain for the device */
2011 drhd = dmar_find_matched_drhd_unit(pdev);
2012 if (!drhd) {
2013 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2014 pci_name(pdev));
2015 return NULL;
2016 }
2017 iommu = drhd->iommu;
2018
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002019 ret = iommu_attach_domain(domain, iommu);
2020 if (ret) {
Alex Williamson2fe97232011-03-04 14:52:30 -07002021 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002022 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002023 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002024
2025 if (domain_init(domain, gaw)) {
2026 domain_exit(domain);
2027 goto error;
2028 }
2029
2030 /* register pcie-to-pci device */
2031 if (dev_tmp) {
2032 info = alloc_devinfo_mem();
2033 if (!info) {
2034 domain_exit(domain);
2035 goto error;
2036 }
David Woodhouse276dbf92009-04-04 01:45:37 +01002037 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002038 info->bus = bus;
2039 info->devfn = devfn;
2040 info->dev = NULL;
2041 info->domain = domain;
2042 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08002043 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002044
2045 /* pcie-to-pci bridge already has a domain, uses it */
2046 found = NULL;
2047 spin_lock_irqsave(&device_domain_lock, flags);
2048 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01002049 if (tmp->segment == segment &&
2050 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002051 found = tmp->domain;
2052 break;
2053 }
2054 }
2055 if (found) {
Jiri Slaby00dfff72010-06-14 17:17:32 +02002056 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002057 free_devinfo_mem(info);
2058 domain_exit(domain);
2059 domain = found;
2060 } else {
2061 list_add(&info->link, &domain->devices);
2062 list_add(&info->global, &device_domain_list);
Jiri Slaby00dfff72010-06-14 17:17:32 +02002063 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002064 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002065 }
2066
2067found_domain:
2068 info = alloc_devinfo_mem();
2069 if (!info)
2070 goto error;
David Woodhouse276dbf92009-04-04 01:45:37 +01002071 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002072 info->bus = pdev->bus->number;
2073 info->devfn = pdev->devfn;
2074 info->dev = pdev;
2075 info->domain = domain;
2076 spin_lock_irqsave(&device_domain_lock, flags);
2077 /* somebody is fast */
2078 found = find_domain(pdev);
2079 if (found != NULL) {
2080 spin_unlock_irqrestore(&device_domain_lock, flags);
2081 if (found != domain) {
2082 domain_exit(domain);
2083 domain = found;
2084 }
2085 free_devinfo_mem(info);
2086 return domain;
2087 }
2088 list_add(&info->link, &domain->devices);
2089 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002090 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002091 spin_unlock_irqrestore(&device_domain_lock, flags);
2092 return domain;
2093error:
2094 /* recheck it here, maybe others set it */
2095 return find_domain(pdev);
2096}
2097
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002098static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002099#define IDENTMAP_ALL 1
2100#define IDENTMAP_GFX 2
2101#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002102
David Woodhouseb2132032009-06-26 18:50:28 +01002103static int iommu_domain_identity_map(struct dmar_domain *domain,
2104 unsigned long long start,
2105 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002106{
David Woodhousec5395d52009-06-28 16:35:56 +01002107 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2108 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002109
David Woodhousec5395d52009-06-28 16:35:56 +01002110 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2111 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002112 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002113 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002114 }
2115
David Woodhousec5395d52009-06-28 16:35:56 +01002116 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2117 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002118 /*
2119 * RMRR range might have overlap with physical memory range,
2120 * clear it first
2121 */
David Woodhousec5395d52009-06-28 16:35:56 +01002122 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002123
David Woodhousec5395d52009-06-28 16:35:56 +01002124 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2125 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002126 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002127}
2128
2129static int iommu_prepare_identity_map(struct pci_dev *pdev,
2130 unsigned long long start,
2131 unsigned long long end)
2132{
2133 struct dmar_domain *domain;
2134 int ret;
2135
David Woodhousec7ab48d2009-06-26 19:10:36 +01002136 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002137 if (!domain)
2138 return -ENOMEM;
2139
David Woodhouse19943b02009-08-04 16:19:20 +01002140 /* For _hardware_ passthrough, don't bother. But for software
2141 passthrough, we do it anyway -- it may indicate a memory
2142 range which is reserved in E820, so which didn't get set
2143 up to start with in si_domain */
2144 if (domain == si_domain && hw_pass_through) {
2145 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2146 pci_name(pdev), start, end);
2147 return 0;
2148 }
2149
2150 printk(KERN_INFO
2151 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2152 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002153
David Woodhouse5595b522009-12-02 09:21:55 +00002154 if (end < start) {
2155 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2156 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2157 dmi_get_system_info(DMI_BIOS_VENDOR),
2158 dmi_get_system_info(DMI_BIOS_VERSION),
2159 dmi_get_system_info(DMI_PRODUCT_VERSION));
2160 ret = -EIO;
2161 goto error;
2162 }
2163
David Woodhouse2ff729f2009-08-26 14:25:41 +01002164 if (end >> agaw_to_width(domain->agaw)) {
2165 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2166 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2167 agaw_to_width(domain->agaw),
2168 dmi_get_system_info(DMI_BIOS_VENDOR),
2169 dmi_get_system_info(DMI_BIOS_VERSION),
2170 dmi_get_system_info(DMI_PRODUCT_VERSION));
2171 ret = -EIO;
2172 goto error;
2173 }
David Woodhouse19943b02009-08-04 16:19:20 +01002174
David Woodhouseb2132032009-06-26 18:50:28 +01002175 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002176 if (ret)
2177 goto error;
2178
2179 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002180 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002181 if (ret)
2182 goto error;
2183
2184 return 0;
2185
2186 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002187 domain_exit(domain);
2188 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002189}
2190
2191static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2192 struct pci_dev *pdev)
2193{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002194 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002195 return 0;
2196 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002197 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002198}
2199
Suresh Siddhad3f13812011-08-23 17:05:25 -07002200#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002201static inline void iommu_prepare_isa(void)
2202{
2203 struct pci_dev *pdev;
2204 int ret;
2205
2206 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2207 if (!pdev)
2208 return;
2209
David Woodhousec7ab48d2009-06-26 19:10:36 +01002210 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002211 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002212
2213 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002214 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2215 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002216
2217}
2218#else
2219static inline void iommu_prepare_isa(void)
2220{
2221 return;
2222}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002223#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002224
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002225static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002226
Matt Kraai071e1372009-08-23 22:30:22 -07002227static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002228{
2229 struct dmar_drhd_unit *drhd;
2230 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002231 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002232
2233 si_domain = alloc_domain();
2234 if (!si_domain)
2235 return -EFAULT;
2236
David Woodhousec7ab48d2009-06-26 19:10:36 +01002237 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002238
2239 for_each_active_iommu(iommu, drhd) {
2240 ret = iommu_attach_domain(si_domain, iommu);
2241 if (ret) {
2242 domain_exit(si_domain);
2243 return -EFAULT;
2244 }
2245 }
2246
2247 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2248 domain_exit(si_domain);
2249 return -EFAULT;
2250 }
2251
2252 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2253
David Woodhouse19943b02009-08-04 16:19:20 +01002254 if (hw)
2255 return 0;
2256
David Woodhousec7ab48d2009-06-26 19:10:36 +01002257 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002258 unsigned long start_pfn, end_pfn;
2259 int i;
2260
2261 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2262 ret = iommu_domain_identity_map(si_domain,
2263 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2264 if (ret)
2265 return ret;
2266 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002267 }
2268
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002269 return 0;
2270}
2271
2272static void domain_remove_one_dev_info(struct dmar_domain *domain,
2273 struct pci_dev *pdev);
2274static int identity_mapping(struct pci_dev *pdev)
2275{
2276 struct device_domain_info *info;
2277
2278 if (likely(!iommu_identity_mapping))
2279 return 0;
2280
Mike Traviscb452a42011-05-28 13:15:03 -05002281 info = pdev->dev.archdata.iommu;
2282 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2283 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002284
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002285 return 0;
2286}
2287
2288static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002289 struct pci_dev *pdev,
2290 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002291{
2292 struct device_domain_info *info;
2293 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002294 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002295
2296 info = alloc_devinfo_mem();
2297 if (!info)
2298 return -ENOMEM;
2299
2300 info->segment = pci_domain_nr(pdev->bus);
2301 info->bus = pdev->bus->number;
2302 info->devfn = pdev->devfn;
2303 info->dev = pdev;
2304 info->domain = domain;
2305
2306 spin_lock_irqsave(&device_domain_lock, flags);
2307 list_add(&info->link, &domain->devices);
2308 list_add(&info->global, &device_domain_list);
2309 pdev->dev.archdata.iommu = info;
2310 spin_unlock_irqrestore(&device_domain_lock, flags);
2311
David Woodhousee568e5e2012-05-25 17:42:54 +01002312 ret = domain_context_mapping(domain, pdev, translation);
2313 if (ret) {
2314 spin_lock_irqsave(&device_domain_lock, flags);
2315 list_del(&info->link);
2316 list_del(&info->global);
2317 pdev->dev.archdata.iommu = NULL;
2318 spin_unlock_irqrestore(&device_domain_lock, flags);
2319 free_devinfo_mem(info);
2320 return ret;
2321 }
2322
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002323 return 0;
2324}
2325
Tom Mingarelli5ad78132012-11-20 19:43:17 +00002326static bool device_has_rmrr(struct pci_dev *dev)
2327{
2328 struct dmar_rmrr_unit *rmrr;
2329 int i;
2330
2331 for_each_rmrr_units(rmrr) {
2332 for (i = 0; i < rmrr->devices_cnt; i++) {
2333 /*
2334 * Return TRUE if this RMRR contains the device that
2335 * is passed in.
2336 */
2337 if (rmrr->devices[i] == dev)
2338 return true;
2339 }
2340 }
2341 return false;
2342}
2343
David Woodhouse6941af22009-07-04 18:24:27 +01002344static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2345{
Tom Mingarelli5ad78132012-11-20 19:43:17 +00002346
2347 /*
2348 * We want to prevent any device associated with an RMRR from
2349 * getting placed into the SI Domain. This is done because
2350 * problems exist when devices are moved in and out of domains
2351 * and their respective RMRR info is lost. We exempt USB devices
2352 * from this process due to their usage of RMRRs that are known
2353 * to not be needed after BIOS hand-off to OS.
2354 */
2355 if (device_has_rmrr(pdev) &&
2356 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2357 return 0;
2358
David Woodhousee0fc7e02009-09-30 09:12:17 -07002359 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2360 return 1;
2361
2362 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2363 return 1;
2364
2365 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2366 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002367
David Woodhouse3dfc8132009-07-04 19:11:08 +01002368 /*
2369 * We want to start off with all devices in the 1:1 domain, and
2370 * take them out later if we find they can't access all of memory.
2371 *
2372 * However, we can't do this for PCI devices behind bridges,
2373 * because all PCI devices behind the same bridge will end up
2374 * with the same source-id on their transactions.
2375 *
2376 * Practically speaking, we can't change things around for these
2377 * devices at run-time, because we can't be sure there'll be no
2378 * DMA transactions in flight for any of their siblings.
2379 *
2380 * So PCI devices (unless they're on the root bus) as well as
2381 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2382 * the 1:1 domain, just in _case_ one of their siblings turns out
2383 * not to be able to map all of memory.
2384 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002385 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002386 if (!pci_is_root_bus(pdev->bus))
2387 return 0;
2388 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2389 return 0;
2390 } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
2391 return 0;
2392
2393 /*
2394 * At boot time, we don't yet know if devices will be 64-bit capable.
2395 * Assume that they will -- if they turn out not to be, then we can
2396 * take them out of the 1:1 domain later.
2397 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002398 if (!startup) {
2399 /*
2400 * If the device's dma_mask is less than the system's memory
2401 * size then this is not a candidate for identity mapping.
2402 */
2403 u64 dma_mask = pdev->dma_mask;
2404
2405 if (pdev->dev.coherent_dma_mask &&
2406 pdev->dev.coherent_dma_mask < dma_mask)
2407 dma_mask = pdev->dev.coherent_dma_mask;
2408
2409 return dma_mask >= dma_get_required_mask(&pdev->dev);
2410 }
David Woodhouse6941af22009-07-04 18:24:27 +01002411
2412 return 1;
2413}
2414
Matt Kraai071e1372009-08-23 22:30:22 -07002415static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002416{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002417 struct pci_dev *pdev = NULL;
2418 int ret;
2419
David Woodhouse19943b02009-08-04 16:19:20 +01002420 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002421 if (ret)
2422 return -EFAULT;
2423
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002424 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002425 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002426 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002427 hw ? CONTEXT_TT_PASS_THROUGH :
2428 CONTEXT_TT_MULTI_LEVEL);
2429 if (ret) {
2430 /* device not associated with an iommu */
2431 if (ret == -ENODEV)
2432 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002433 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002434 }
2435 pr_info("IOMMU: %s identity mapping for device %s\n",
2436 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002437 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002438 }
2439
2440 return 0;
2441}
2442
Joseph Cihulab7792602011-05-03 00:08:37 -07002443static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002444{
2445 struct dmar_drhd_unit *drhd;
2446 struct dmar_rmrr_unit *rmrr;
2447 struct pci_dev *pdev;
2448 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002449 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002450
2451 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002452 * for each drhd
2453 * allocate root
2454 * initialize and program root entry to not present
2455 * endfor
2456 */
2457 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002458 /*
2459 * lock not needed as this is only incremented in the single
2460 * threaded kernel __init code path all other access are read
2461 * only
2462 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002463 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2464 g_num_of_iommus++;
2465 continue;
2466 }
2467 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2468 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002469 }
2470
Weidong Hand9630fe2008-12-08 11:06:32 +08002471 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2472 GFP_KERNEL);
2473 if (!g_iommus) {
2474 printk(KERN_ERR "Allocating global iommu array failed\n");
2475 ret = -ENOMEM;
2476 goto error;
2477 }
2478
mark gross80b20dd2008-04-18 13:53:58 -07002479 deferred_flush = kzalloc(g_num_of_iommus *
2480 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2481 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002482 ret = -ENOMEM;
2483 goto error;
2484 }
2485
mark gross5e0d2a62008-03-04 15:22:08 -08002486 for_each_drhd_unit(drhd) {
2487 if (drhd->ignored)
2488 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002489
2490 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002491 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002492
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002493 ret = iommu_init_domains(iommu);
2494 if (ret)
2495 goto error;
2496
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002497 /*
2498 * TBD:
2499 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002500 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002501 */
2502 ret = iommu_alloc_root_entry(iommu);
2503 if (ret) {
2504 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2505 goto error;
2506 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002507 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002508 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002509 }
2510
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002511 /*
2512 * Start from the sane iommu hardware state.
2513 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002514 for_each_drhd_unit(drhd) {
2515 if (drhd->ignored)
2516 continue;
2517
2518 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002519
2520 /*
2521 * If the queued invalidation is already initialized by us
2522 * (for example, while enabling interrupt-remapping) then
2523 * we got the things already rolling from a sane state.
2524 */
2525 if (iommu->qi)
2526 continue;
2527
2528 /*
2529 * Clear any previous faults.
2530 */
2531 dmar_fault(-1, iommu);
2532 /*
2533 * Disable queued invalidation if supported and already enabled
2534 * before OS handover.
2535 */
2536 dmar_disable_qi(iommu);
2537 }
2538
2539 for_each_drhd_unit(drhd) {
2540 if (drhd->ignored)
2541 continue;
2542
2543 iommu = drhd->iommu;
2544
Youquan Songa77b67d2008-10-16 16:31:56 -07002545 if (dmar_enable_qi(iommu)) {
2546 /*
2547 * Queued Invalidate not enabled, use Register Based
2548 * Invalidate
2549 */
2550 iommu->flush.flush_context = __iommu_flush_context;
2551 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002552 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002553 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002554 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002555 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002556 } else {
2557 iommu->flush.flush_context = qi_flush_context;
2558 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002559 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002560 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002561 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002562 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002563 }
2564 }
2565
David Woodhouse19943b02009-08-04 16:19:20 +01002566 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002567 iommu_identity_mapping |= IDENTMAP_ALL;
2568
Suresh Siddhad3f13812011-08-23 17:05:25 -07002569#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002570 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002571#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002572
2573 check_tylersburg_isoch();
2574
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002575 /*
2576 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002577 * identity mappings for rmrr, gfx, and isa and may fall back to static
2578 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002579 */
David Woodhouse19943b02009-08-04 16:19:20 +01002580 if (iommu_identity_mapping) {
2581 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2582 if (ret) {
2583 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2584 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002585 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002586 }
David Woodhouse19943b02009-08-04 16:19:20 +01002587 /*
2588 * For each rmrr
2589 * for each dev attached to rmrr
2590 * do
2591 * locate drhd for dev, alloc domain for dev
2592 * allocate free domain
2593 * allocate page table entries for rmrr
2594 * if context not allocated for bus
2595 * allocate and init context
2596 * set present in root table for this bus
2597 * init context with domain, translation etc
2598 * endfor
2599 * endfor
2600 */
2601 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2602 for_each_rmrr_units(rmrr) {
2603 for (i = 0; i < rmrr->devices_cnt; i++) {
2604 pdev = rmrr->devices[i];
2605 /*
2606 * some BIOS lists non-exist devices in DMAR
2607 * table.
2608 */
2609 if (!pdev)
2610 continue;
2611 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2612 if (ret)
2613 printk(KERN_ERR
2614 "IOMMU: mapping reserved region failed\n");
2615 }
2616 }
2617
2618 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002619
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002620 /*
2621 * for each drhd
2622 * enable fault log
2623 * global invalidate context cache
2624 * global invalidate iotlb
2625 * enable translation
2626 */
2627 for_each_drhd_unit(drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002628 if (drhd->ignored) {
2629 /*
2630 * we always have to disable PMRs or DMA may fail on
2631 * this device
2632 */
2633 if (force_on)
2634 iommu_disable_protect_mem_regions(drhd->iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002635 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002636 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002637 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002638
2639 iommu_flush_write_buffer(iommu);
2640
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002641 ret = dmar_set_interrupt(iommu);
2642 if (ret)
2643 goto error;
2644
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002645 iommu_set_root_entry(iommu);
2646
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002647 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002648 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002649
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002650 ret = iommu_enable_translation(iommu);
2651 if (ret)
2652 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002653
2654 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002655 }
2656
2657 return 0;
2658error:
2659 for_each_drhd_unit(drhd) {
2660 if (drhd->ignored)
2661 continue;
2662 iommu = drhd->iommu;
2663 free_iommu(iommu);
2664 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002665 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002666 return ret;
2667}
2668
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002669/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002670static struct iova *intel_alloc_iova(struct device *dev,
2671 struct dmar_domain *domain,
2672 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002673{
2674 struct pci_dev *pdev = to_pci_dev(dev);
2675 struct iova *iova = NULL;
2676
David Woodhouse875764d2009-06-28 21:20:51 +01002677 /* Restrict dma_mask to the width that the iommu can handle */
2678 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2679
2680 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002681 /*
2682 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002683 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002684 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002685 */
David Woodhouse875764d2009-06-28 21:20:51 +01002686 iova = alloc_iova(&domain->iovad, nrpages,
2687 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2688 if (iova)
2689 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002690 }
David Woodhouse875764d2009-06-28 21:20:51 +01002691 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2692 if (unlikely(!iova)) {
2693 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2694 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002695 return NULL;
2696 }
2697
2698 return iova;
2699}
2700
David Woodhouse147202a2009-07-07 19:43:20 +01002701static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002702{
2703 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002704 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002705
2706 domain = get_domain_for_dev(pdev,
2707 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2708 if (!domain) {
2709 printk(KERN_ERR
2710 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002711 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002712 }
2713
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002714 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002715 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002716 ret = domain_context_mapping(domain, pdev,
2717 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002718 if (ret) {
2719 printk(KERN_ERR
2720 "Domain context map for %s failed",
2721 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002722 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002723 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002724 }
2725
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002726 return domain;
2727}
2728
David Woodhouse147202a2009-07-07 19:43:20 +01002729static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2730{
2731 struct device_domain_info *info;
2732
2733 /* No lock here, assumes no domain exit in normal case */
2734 info = dev->dev.archdata.iommu;
2735 if (likely(info))
2736 return info->domain;
2737
2738 return __get_valid_domain_for_dev(dev);
2739}
2740
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002741static int iommu_dummy(struct pci_dev *pdev)
2742{
2743 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2744}
2745
2746/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002747static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002748{
David Woodhouse73676832009-07-04 14:08:36 +01002749 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002750 int found;
2751
David Woodhouse73676832009-07-04 14:08:36 +01002752 if (unlikely(dev->bus != &pci_bus_type))
2753 return 1;
2754
2755 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002756 if (iommu_dummy(pdev))
2757 return 1;
2758
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002759 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002760 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002761
2762 found = identity_mapping(pdev);
2763 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002764 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002765 return 1;
2766 else {
2767 /*
2768 * 32 bit DMA is removed from si_domain and fall back
2769 * to non-identity mapping.
2770 */
2771 domain_remove_one_dev_info(si_domain, pdev);
2772 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2773 pci_name(pdev));
2774 return 0;
2775 }
2776 } else {
2777 /*
2778 * In case of a detached 64 bit DMA device from vm, the device
2779 * is put into si_domain for identity mapping.
2780 */
David Woodhouse6941af22009-07-04 18:24:27 +01002781 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002782 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002783 ret = domain_add_dev_info(si_domain, pdev,
2784 hw_pass_through ?
2785 CONTEXT_TT_PASS_THROUGH :
2786 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002787 if (!ret) {
2788 printk(KERN_INFO "64bit %s uses identity mapping\n",
2789 pci_name(pdev));
2790 return 1;
2791 }
2792 }
2793 }
2794
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002795 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002796}
2797
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002798static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2799 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002800{
2801 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002802 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002803 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002804 struct iova *iova;
2805 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002806 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002807 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002808 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002809
2810 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002811
David Woodhouse73676832009-07-04 14:08:36 +01002812 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002813 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002814
2815 domain = get_valid_domain_for_dev(pdev);
2816 if (!domain)
2817 return 0;
2818
Weidong Han8c11e792008-12-08 15:29:22 +08002819 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002820 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002821
Mike Travisc681d0b2011-05-28 13:15:05 -05002822 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002823 if (!iova)
2824 goto error;
2825
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002826 /*
2827 * Check if DMAR supports zero-length reads on write only
2828 * mappings..
2829 */
2830 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002831 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002832 prot |= DMA_PTE_READ;
2833 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2834 prot |= DMA_PTE_WRITE;
2835 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002836 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002837 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002838 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002839 * is not a big problem
2840 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002841 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002842 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002843 if (ret)
2844 goto error;
2845
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002846 /* it's a non-present to present mapping. Only flush if caching mode */
2847 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002848 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002849 else
Weidong Han8c11e792008-12-08 15:29:22 +08002850 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002851
David Woodhouse03d6a242009-06-28 15:33:46 +01002852 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2853 start_paddr += paddr & ~PAGE_MASK;
2854 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002855
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002856error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002857 if (iova)
2858 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002859 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002860 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002861 return 0;
2862}
2863
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002864static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2865 unsigned long offset, size_t size,
2866 enum dma_data_direction dir,
2867 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002868{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002869 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2870 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002871}
2872
mark gross5e0d2a62008-03-04 15:22:08 -08002873static void flush_unmaps(void)
2874{
mark gross80b20dd2008-04-18 13:53:58 -07002875 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002876
mark gross5e0d2a62008-03-04 15:22:08 -08002877 timer_on = 0;
2878
2879 /* just flush them all */
2880 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002881 struct intel_iommu *iommu = g_iommus[i];
2882 if (!iommu)
2883 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002884
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002885 if (!deferred_flush[i].next)
2886 continue;
2887
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002888 /* In caching mode, global flushes turn emulation expensive */
2889 if (!cap_caching_mode(iommu->cap))
2890 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002891 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002892 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002893 unsigned long mask;
2894 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002895 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002896
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002897 /* On real hardware multiple invalidations are expensive */
2898 if (cap_caching_mode(iommu->cap))
2899 iommu_flush_iotlb_psi(iommu, domain->id,
2900 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2901 else {
2902 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2903 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2904 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2905 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002906 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002907 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002908 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002909 }
2910
mark gross5e0d2a62008-03-04 15:22:08 -08002911 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002912}
2913
2914static void flush_unmaps_timeout(unsigned long data)
2915{
mark gross80b20dd2008-04-18 13:53:58 -07002916 unsigned long flags;
2917
2918 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002919 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002920 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002921}
2922
2923static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2924{
2925 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002926 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002927 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002928
2929 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002930 if (list_size == HIGH_WATER_MARK)
2931 flush_unmaps();
2932
Weidong Han8c11e792008-12-08 15:29:22 +08002933 iommu = domain_get_iommu(dom);
2934 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002935
mark gross80b20dd2008-04-18 13:53:58 -07002936 next = deferred_flush[iommu_id].next;
2937 deferred_flush[iommu_id].domain[next] = dom;
2938 deferred_flush[iommu_id].iova[next] = iova;
2939 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002940
2941 if (!timer_on) {
2942 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2943 timer_on = 1;
2944 }
2945 list_size++;
2946 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2947}
2948
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002949static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2950 size_t size, enum dma_data_direction dir,
2951 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002952{
2953 struct pci_dev *pdev = to_pci_dev(dev);
2954 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002955 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002956 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002957 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002958
David Woodhouse73676832009-07-04 14:08:36 +01002959 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002960 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002961
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002962 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002963 BUG_ON(!domain);
2964
Weidong Han8c11e792008-12-08 15:29:22 +08002965 iommu = domain_get_iommu(domain);
2966
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002967 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002968 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2969 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002970 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002971
David Woodhoused794dc92009-06-28 00:27:49 +01002972 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2973 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002974
David Woodhoused794dc92009-06-28 00:27:49 +01002975 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2976 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002977
2978 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002979 dma_pte_clear_range(domain, start_pfn, last_pfn);
2980
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002981 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002982 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2983
mark gross5e0d2a62008-03-04 15:22:08 -08002984 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002985 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002986 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002987 /* free iova */
2988 __free_iova(&domain->iovad, iova);
2989 } else {
2990 add_unmap(domain, iova);
2991 /*
2992 * queue up the release of the unmap to save the 1/6th of the
2993 * cpu used up by the iotlb flush operation...
2994 */
mark gross5e0d2a62008-03-04 15:22:08 -08002995 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002996}
2997
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002998static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02002999 dma_addr_t *dma_handle, gfp_t flags,
3000 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003001{
3002 void *vaddr;
3003 int order;
3004
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003005 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003006 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07003007
3008 if (!iommu_no_mapping(hwdev))
3009 flags &= ~(GFP_DMA | GFP_DMA32);
3010 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
3011 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
3012 flags |= GFP_DMA;
3013 else
3014 flags |= GFP_DMA32;
3015 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003016
3017 vaddr = (void *)__get_free_pages(flags, order);
3018 if (!vaddr)
3019 return NULL;
3020 memset(vaddr, 0, size);
3021
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003022 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
3023 DMA_BIDIRECTIONAL,
3024 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003025 if (*dma_handle)
3026 return vaddr;
3027 free_pages((unsigned long)vaddr, order);
3028 return NULL;
3029}
3030
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003031static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003032 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003033{
3034 int order;
3035
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003036 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003037 order = get_order(size);
3038
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003039 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003040 free_pages((unsigned long)vaddr, order);
3041}
3042
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003043static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3044 int nelems, enum dma_data_direction dir,
3045 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003046{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003047 struct pci_dev *pdev = to_pci_dev(hwdev);
3048 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003049 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003050 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003051 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003052
David Woodhouse73676832009-07-04 14:08:36 +01003053 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003054 return;
3055
3056 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003057 BUG_ON(!domain);
3058
3059 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003060
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003061 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003062 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3063 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003064 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003065
David Woodhoused794dc92009-06-28 00:27:49 +01003066 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3067 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003068
3069 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003070 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003071
David Woodhoused794dc92009-06-28 00:27:49 +01003072 /* free page tables */
3073 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3074
David Woodhouseacea0012009-07-14 01:55:11 +01003075 if (intel_iommu_strict) {
3076 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003077 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003078 /* free iova */
3079 __free_iova(&domain->iovad, iova);
3080 } else {
3081 add_unmap(domain, iova);
3082 /*
3083 * queue up the release of the unmap to save the 1/6th of the
3084 * cpu used up by the iotlb flush operation...
3085 */
3086 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003087}
3088
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003089static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003090 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003091{
3092 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003093 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003094
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003095 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003096 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003097 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003098 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003099 }
3100 return nelems;
3101}
3102
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003103static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3104 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003105{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003106 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003107 struct pci_dev *pdev = to_pci_dev(hwdev);
3108 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003109 size_t size = 0;
3110 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003111 struct iova *iova = NULL;
3112 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003113 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003114 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003115 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003116
3117 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003118 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003119 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003120
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003121 domain = get_valid_domain_for_dev(pdev);
3122 if (!domain)
3123 return 0;
3124
Weidong Han8c11e792008-12-08 15:29:22 +08003125 iommu = domain_get_iommu(domain);
3126
David Woodhouseb536d242009-06-28 14:49:31 +01003127 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003128 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003129
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003130 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3131 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003132 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003133 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003134 return 0;
3135 }
3136
3137 /*
3138 * Check if DMAR supports zero-length reads on write only
3139 * mappings..
3140 */
3141 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003142 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003143 prot |= DMA_PTE_READ;
3144 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3145 prot |= DMA_PTE_WRITE;
3146
David Woodhouseb536d242009-06-28 14:49:31 +01003147 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003148
Fenghua Yuf5329592009-08-04 15:09:37 -07003149 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003150 if (unlikely(ret)) {
3151 /* clear the page */
3152 dma_pte_clear_range(domain, start_vpfn,
3153 start_vpfn + size - 1);
3154 /* free page tables */
3155 dma_pte_free_pagetable(domain, start_vpfn,
3156 start_vpfn + size - 1);
3157 /* free iova */
3158 __free_iova(&domain->iovad, iova);
3159 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003160 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003161
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003162 /* it's a non-present to present mapping. Only flush if caching mode */
3163 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003164 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003165 else
Weidong Han8c11e792008-12-08 15:29:22 +08003166 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003167
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003168 return nelems;
3169}
3170
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003171static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3172{
3173 return !dma_addr;
3174}
3175
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003176struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003177 .alloc = intel_alloc_coherent,
3178 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003179 .map_sg = intel_map_sg,
3180 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003181 .map_page = intel_map_page,
3182 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003183 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003184};
3185
3186static inline int iommu_domain_cache_init(void)
3187{
3188 int ret = 0;
3189
3190 iommu_domain_cache = kmem_cache_create("iommu_domain",
3191 sizeof(struct dmar_domain),
3192 0,
3193 SLAB_HWCACHE_ALIGN,
3194
3195 NULL);
3196 if (!iommu_domain_cache) {
3197 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3198 ret = -ENOMEM;
3199 }
3200
3201 return ret;
3202}
3203
3204static inline int iommu_devinfo_cache_init(void)
3205{
3206 int ret = 0;
3207
3208 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3209 sizeof(struct device_domain_info),
3210 0,
3211 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003212 NULL);
3213 if (!iommu_devinfo_cache) {
3214 printk(KERN_ERR "Couldn't create devinfo cache\n");
3215 ret = -ENOMEM;
3216 }
3217
3218 return ret;
3219}
3220
3221static inline int iommu_iova_cache_init(void)
3222{
3223 int ret = 0;
3224
3225 iommu_iova_cache = kmem_cache_create("iommu_iova",
3226 sizeof(struct iova),
3227 0,
3228 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003229 NULL);
3230 if (!iommu_iova_cache) {
3231 printk(KERN_ERR "Couldn't create iova cache\n");
3232 ret = -ENOMEM;
3233 }
3234
3235 return ret;
3236}
3237
3238static int __init iommu_init_mempool(void)
3239{
3240 int ret;
3241 ret = iommu_iova_cache_init();
3242 if (ret)
3243 return ret;
3244
3245 ret = iommu_domain_cache_init();
3246 if (ret)
3247 goto domain_error;
3248
3249 ret = iommu_devinfo_cache_init();
3250 if (!ret)
3251 return ret;
3252
3253 kmem_cache_destroy(iommu_domain_cache);
3254domain_error:
3255 kmem_cache_destroy(iommu_iova_cache);
3256
3257 return -ENOMEM;
3258}
3259
3260static void __init iommu_exit_mempool(void)
3261{
3262 kmem_cache_destroy(iommu_devinfo_cache);
3263 kmem_cache_destroy(iommu_domain_cache);
3264 kmem_cache_destroy(iommu_iova_cache);
3265
3266}
3267
Dan Williams556ab452010-07-23 15:47:56 -07003268static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3269{
3270 struct dmar_drhd_unit *drhd;
3271 u32 vtbar;
3272 int rc;
3273
3274 /* We know that this device on this chipset has its own IOMMU.
3275 * If we find it under a different IOMMU, then the BIOS is lying
3276 * to us. Hope that the IOMMU for this device is actually
3277 * disabled, and it needs no translation...
3278 */
3279 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3280 if (rc) {
3281 /* "can't" happen */
3282 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3283 return;
3284 }
3285 vtbar &= 0xffff0000;
3286
3287 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3288 drhd = dmar_find_matched_drhd_unit(pdev);
3289 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3290 TAINT_FIRMWARE_WORKAROUND,
3291 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3292 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3293}
3294DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3295
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003296static void __init init_no_remapping_devices(void)
3297{
3298 struct dmar_drhd_unit *drhd;
3299
3300 for_each_drhd_unit(drhd) {
3301 if (!drhd->include_all) {
3302 int i;
3303 for (i = 0; i < drhd->devices_cnt; i++)
3304 if (drhd->devices[i] != NULL)
3305 break;
3306 /* ignore DMAR unit if no pci devices exist */
3307 if (i == drhd->devices_cnt)
3308 drhd->ignored = 1;
3309 }
3310 }
3311
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003312 for_each_drhd_unit(drhd) {
3313 int i;
3314 if (drhd->ignored || drhd->include_all)
3315 continue;
3316
3317 for (i = 0; i < drhd->devices_cnt; i++)
3318 if (drhd->devices[i] &&
David Woodhousec0771df2011-10-14 20:59:46 +01003319 !IS_GFX_DEVICE(drhd->devices[i]))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003320 break;
3321
3322 if (i < drhd->devices_cnt)
3323 continue;
3324
David Woodhousec0771df2011-10-14 20:59:46 +01003325 /* This IOMMU has *only* gfx devices. Either bypass it or
3326 set the gfx_mapped flag, as appropriate */
3327 if (dmar_map_gfx) {
3328 intel_iommu_gfx_mapped = 1;
3329 } else {
3330 drhd->ignored = 1;
3331 for (i = 0; i < drhd->devices_cnt; i++) {
3332 if (!drhd->devices[i])
3333 continue;
3334 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3335 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003336 }
3337 }
3338}
3339
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003340#ifdef CONFIG_SUSPEND
3341static int init_iommu_hw(void)
3342{
3343 struct dmar_drhd_unit *drhd;
3344 struct intel_iommu *iommu = NULL;
3345
3346 for_each_active_iommu(iommu, drhd)
3347 if (iommu->qi)
3348 dmar_reenable_qi(iommu);
3349
Joseph Cihulab7792602011-05-03 00:08:37 -07003350 for_each_iommu(iommu, drhd) {
3351 if (drhd->ignored) {
3352 /*
3353 * we always have to disable PMRs or DMA may fail on
3354 * this device
3355 */
3356 if (force_on)
3357 iommu_disable_protect_mem_regions(iommu);
3358 continue;
3359 }
3360
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003361 iommu_flush_write_buffer(iommu);
3362
3363 iommu_set_root_entry(iommu);
3364
3365 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003366 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003367 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003368 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003369 if (iommu_enable_translation(iommu))
3370 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003371 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003372 }
3373
3374 return 0;
3375}
3376
3377static void iommu_flush_all(void)
3378{
3379 struct dmar_drhd_unit *drhd;
3380 struct intel_iommu *iommu;
3381
3382 for_each_active_iommu(iommu, drhd) {
3383 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003384 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003385 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003386 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003387 }
3388}
3389
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003390static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003391{
3392 struct dmar_drhd_unit *drhd;
3393 struct intel_iommu *iommu = NULL;
3394 unsigned long flag;
3395
3396 for_each_active_iommu(iommu, drhd) {
3397 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3398 GFP_ATOMIC);
3399 if (!iommu->iommu_state)
3400 goto nomem;
3401 }
3402
3403 iommu_flush_all();
3404
3405 for_each_active_iommu(iommu, drhd) {
3406 iommu_disable_translation(iommu);
3407
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003408 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003409
3410 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3411 readl(iommu->reg + DMAR_FECTL_REG);
3412 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3413 readl(iommu->reg + DMAR_FEDATA_REG);
3414 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3415 readl(iommu->reg + DMAR_FEADDR_REG);
3416 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3417 readl(iommu->reg + DMAR_FEUADDR_REG);
3418
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003419 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003420 }
3421 return 0;
3422
3423nomem:
3424 for_each_active_iommu(iommu, drhd)
3425 kfree(iommu->iommu_state);
3426
3427 return -ENOMEM;
3428}
3429
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003430static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003431{
3432 struct dmar_drhd_unit *drhd;
3433 struct intel_iommu *iommu = NULL;
3434 unsigned long flag;
3435
3436 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003437 if (force_on)
3438 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3439 else
3440 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003441 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003442 }
3443
3444 for_each_active_iommu(iommu, drhd) {
3445
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003446 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003447
3448 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3449 iommu->reg + DMAR_FECTL_REG);
3450 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3451 iommu->reg + DMAR_FEDATA_REG);
3452 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3453 iommu->reg + DMAR_FEADDR_REG);
3454 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3455 iommu->reg + DMAR_FEUADDR_REG);
3456
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003457 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003458 }
3459
3460 for_each_active_iommu(iommu, drhd)
3461 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003462}
3463
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003464static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003465 .resume = iommu_resume,
3466 .suspend = iommu_suspend,
3467};
3468
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003469static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003470{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003471 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003472}
3473
3474#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003475static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003476#endif /* CONFIG_PM */
3477
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003478LIST_HEAD(dmar_rmrr_units);
3479
3480static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3481{
3482 list_add(&rmrr->list, &dmar_rmrr_units);
3483}
3484
3485
3486int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3487{
3488 struct acpi_dmar_reserved_memory *rmrr;
3489 struct dmar_rmrr_unit *rmrru;
3490
3491 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3492 if (!rmrru)
3493 return -ENOMEM;
3494
3495 rmrru->hdr = header;
3496 rmrr = (struct acpi_dmar_reserved_memory *)header;
3497 rmrru->base_address = rmrr->base_address;
3498 rmrru->end_address = rmrr->end_address;
3499
3500 dmar_register_rmrr_unit(rmrru);
3501 return 0;
3502}
3503
3504static int __init
3505rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3506{
3507 struct acpi_dmar_reserved_memory *rmrr;
3508 int ret;
3509
3510 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
3511 ret = dmar_parse_dev_scope((void *)(rmrr + 1),
3512 ((void *)rmrr) + rmrr->header.length,
3513 &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
3514
3515 if (ret || (rmrru->devices_cnt == 0)) {
3516 list_del(&rmrru->list);
3517 kfree(rmrru);
3518 }
3519 return ret;
3520}
3521
3522static LIST_HEAD(dmar_atsr_units);
3523
3524int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3525{
3526 struct acpi_dmar_atsr *atsr;
3527 struct dmar_atsr_unit *atsru;
3528
3529 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3530 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3531 if (!atsru)
3532 return -ENOMEM;
3533
3534 atsru->hdr = hdr;
3535 atsru->include_all = atsr->flags & 0x1;
3536
3537 list_add(&atsru->list, &dmar_atsr_units);
3538
3539 return 0;
3540}
3541
3542static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3543{
3544 int rc;
3545 struct acpi_dmar_atsr *atsr;
3546
3547 if (atsru->include_all)
3548 return 0;
3549
3550 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3551 rc = dmar_parse_dev_scope((void *)(atsr + 1),
3552 (void *)atsr + atsr->header.length,
3553 &atsru->devices_cnt, &atsru->devices,
3554 atsr->segment);
3555 if (rc || !atsru->devices_cnt) {
3556 list_del(&atsru->list);
3557 kfree(atsru);
3558 }
3559
3560 return rc;
3561}
3562
3563int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3564{
3565 int i;
3566 struct pci_bus *bus;
3567 struct acpi_dmar_atsr *atsr;
3568 struct dmar_atsr_unit *atsru;
3569
3570 dev = pci_physfn(dev);
3571
3572 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3573 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3574 if (atsr->segment == pci_domain_nr(dev->bus))
3575 goto found;
3576 }
3577
3578 return 0;
3579
3580found:
3581 for (bus = dev->bus; bus; bus = bus->parent) {
3582 struct pci_dev *bridge = bus->self;
3583
3584 if (!bridge || !pci_is_pcie(bridge) ||
3585 bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
3586 return 0;
3587
3588 if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
3589 for (i = 0; i < atsru->devices_cnt; i++)
3590 if (atsru->devices[i] == bridge)
3591 return 1;
3592 break;
3593 }
3594 }
3595
3596 if (atsru->include_all)
3597 return 1;
3598
3599 return 0;
3600}
3601
Sergey Senozhatskyc8f369a2011-10-26 18:45:39 +03003602int __init dmar_parse_rmrr_atsr_dev(void)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003603{
3604 struct dmar_rmrr_unit *rmrr, *rmrr_n;
3605 struct dmar_atsr_unit *atsr, *atsr_n;
3606 int ret = 0;
3607
3608 list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
3609 ret = rmrr_parse_dev(rmrr);
3610 if (ret)
3611 return ret;
3612 }
3613
3614 list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
3615 ret = atsr_parse_dev(atsr);
3616 if (ret)
3617 return ret;
3618 }
3619
3620 return ret;
3621}
3622
Fenghua Yu99dcade2009-11-11 07:23:06 -08003623/*
3624 * Here we only respond to action of unbound device from driver.
3625 *
3626 * Added device is not attached to its DMAR domain here yet. That will happen
3627 * when mapping the device to iova.
3628 */
3629static int device_notifier(struct notifier_block *nb,
3630 unsigned long action, void *data)
3631{
3632 struct device *dev = data;
3633 struct pci_dev *pdev = to_pci_dev(dev);
3634 struct dmar_domain *domain;
3635
David Woodhouse44cd6132009-12-02 10:18:30 +00003636 if (iommu_no_mapping(dev))
3637 return 0;
3638
Fenghua Yu99dcade2009-11-11 07:23:06 -08003639 domain = find_domain(pdev);
3640 if (!domain)
3641 return 0;
3642
Alex Williamsona97590e2011-03-04 14:52:16 -07003643 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
Fenghua Yu99dcade2009-11-11 07:23:06 -08003644 domain_remove_one_dev_info(domain, pdev);
3645
Alex Williamsona97590e2011-03-04 14:52:16 -07003646 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3647 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3648 list_empty(&domain->devices))
3649 domain_exit(domain);
3650 }
3651
Fenghua Yu99dcade2009-11-11 07:23:06 -08003652 return 0;
3653}
3654
3655static struct notifier_block device_nb = {
3656 .notifier_call = device_notifier,
3657};
3658
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003659int __init intel_iommu_init(void)
3660{
3661 int ret = 0;
Takao Indoh21870a32013-04-23 17:35:03 +09003662 struct dmar_drhd_unit *drhd;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003663
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003664 /* VT-d is required for a TXT/tboot launch, so enforce that */
3665 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003666
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003667 if (dmar_table_init()) {
3668 if (force_on)
3669 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003670 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003671 }
3672
Takao Indoh21870a32013-04-23 17:35:03 +09003673 /*
3674 * Disable translation if already enabled prior to OS handover.
3675 */
3676 for_each_drhd_unit(drhd) {
3677 struct intel_iommu *iommu;
3678
3679 if (drhd->ignored)
3680 continue;
3681
3682 iommu = drhd->iommu;
3683 if (iommu->gcmd & DMA_GCMD_TE)
3684 iommu_disable_translation(iommu);
3685 }
3686
Suresh Siddhac2c72862011-08-23 17:05:19 -07003687 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003688 if (force_on)
3689 panic("tboot: Failed to initialize DMAR device scope\n");
3690 return -ENODEV;
3691 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003692
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003693 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003694 return -ENODEV;
3695
Joseph Cihula51a63e62011-03-21 11:04:24 -07003696 if (iommu_init_mempool()) {
3697 if (force_on)
3698 panic("tboot: Failed to initialize iommu memory\n");
3699 return -ENODEV;
3700 }
3701
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003702 if (list_empty(&dmar_rmrr_units))
3703 printk(KERN_INFO "DMAR: No RMRR found\n");
3704
3705 if (list_empty(&dmar_atsr_units))
3706 printk(KERN_INFO "DMAR: No ATSR found\n");
3707
Joseph Cihula51a63e62011-03-21 11:04:24 -07003708 if (dmar_init_reserved_ranges()) {
3709 if (force_on)
3710 panic("tboot: Failed to reserve iommu ranges\n");
3711 return -ENODEV;
3712 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003713
3714 init_no_remapping_devices();
3715
Joseph Cihulab7792602011-05-03 00:08:37 -07003716 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003717 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003718 if (force_on)
3719 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003720 printk(KERN_ERR "IOMMU: dmar init failed\n");
3721 put_iova_domain(&reserved_iova_list);
3722 iommu_exit_mempool();
3723 return ret;
3724 }
3725 printk(KERN_INFO
3726 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3727
mark gross5e0d2a62008-03-04 15:22:08 -08003728 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003729#ifdef CONFIG_SWIOTLB
3730 swiotlb = 0;
3731#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003732 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003733
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003734 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003735
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003736 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003737
Fenghua Yu99dcade2009-11-11 07:23:06 -08003738 bus_register_notifier(&pci_bus_type, &device_nb);
3739
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003740 intel_iommu_enabled = 1;
3741
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003742 return 0;
3743}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003744
Han, Weidong3199aa62009-02-26 17:31:12 +08003745static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3746 struct pci_dev *pdev)
3747{
3748 struct pci_dev *tmp, *parent;
3749
3750 if (!iommu || !pdev)
3751 return;
3752
3753 /* dependent device detach */
3754 tmp = pci_find_upstream_pcie_bridge(pdev);
3755 /* Secondary interface's bus number and devfn 0 */
3756 if (tmp) {
3757 parent = pdev->bus->self;
3758 while (parent != tmp) {
3759 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01003760 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003761 parent = parent->bus->self;
3762 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003763 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003764 iommu_detach_dev(iommu,
3765 tmp->subordinate->number, 0);
3766 else /* this is a legacy PCI bridge */
David Woodhouse276dbf92009-04-04 01:45:37 +01003767 iommu_detach_dev(iommu, tmp->bus->number,
3768 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003769 }
3770}
3771
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003772static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003773 struct pci_dev *pdev)
3774{
3775 struct device_domain_info *info;
3776 struct intel_iommu *iommu;
3777 unsigned long flags;
3778 int found = 0;
3779 struct list_head *entry, *tmp;
3780
David Woodhouse276dbf92009-04-04 01:45:37 +01003781 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3782 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003783 if (!iommu)
3784 return;
3785
3786 spin_lock_irqsave(&device_domain_lock, flags);
3787 list_for_each_safe(entry, tmp, &domain->devices) {
3788 info = list_entry(entry, struct device_domain_info, link);
Mike Habeck8519dc42011-05-28 13:15:07 -05003789 if (info->segment == pci_domain_nr(pdev->bus) &&
3790 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003791 info->devfn == pdev->devfn) {
3792 list_del(&info->link);
3793 list_del(&info->global);
3794 if (info->dev)
3795 info->dev->dev.archdata.iommu = NULL;
3796 spin_unlock_irqrestore(&device_domain_lock, flags);
3797
Yu Zhao93a23a72009-05-18 13:51:37 +08003798 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003799 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003800 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003801 free_devinfo_mem(info);
3802
3803 spin_lock_irqsave(&device_domain_lock, flags);
3804
3805 if (found)
3806 break;
3807 else
3808 continue;
3809 }
3810
3811 /* if there is no other devices under the same iommu
3812 * owned by this domain, clear this iommu in iommu_bmp
3813 * update iommu count and coherency
3814 */
David Woodhouse276dbf92009-04-04 01:45:37 +01003815 if (iommu == device_to_iommu(info->segment, info->bus,
3816 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003817 found = 1;
3818 }
3819
Roland Dreier3e7abe22011-07-20 06:22:21 -07003820 spin_unlock_irqrestore(&device_domain_lock, flags);
3821
Weidong Hanc7151a82008-12-08 22:51:37 +08003822 if (found == 0) {
3823 unsigned long tmp_flags;
3824 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003825 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003826 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003827 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003828 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003829
Alex Williamson9b4554b2011-05-24 12:19:04 -04003830 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3831 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3832 spin_lock_irqsave(&iommu->lock, tmp_flags);
3833 clear_bit(domain->id, iommu->domain_ids);
3834 iommu->domains[domain->id] = NULL;
3835 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3836 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003837 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003838}
3839
3840static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3841{
3842 struct device_domain_info *info;
3843 struct intel_iommu *iommu;
3844 unsigned long flags1, flags2;
3845
3846 spin_lock_irqsave(&device_domain_lock, flags1);
3847 while (!list_empty(&domain->devices)) {
3848 info = list_entry(domain->devices.next,
3849 struct device_domain_info, link);
3850 list_del(&info->link);
3851 list_del(&info->global);
3852 if (info->dev)
3853 info->dev->dev.archdata.iommu = NULL;
3854
3855 spin_unlock_irqrestore(&device_domain_lock, flags1);
3856
Yu Zhao93a23a72009-05-18 13:51:37 +08003857 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01003858 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003859 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003860 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003861
3862 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003863 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003864 */
3865 spin_lock_irqsave(&domain->iommu_lock, flags2);
3866 if (test_and_clear_bit(iommu->seq_id,
Mike Travis1b198bb2012-03-05 15:05:16 -08003867 domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08003868 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003869 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003870 }
3871 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3872
3873 free_devinfo_mem(info);
3874 spin_lock_irqsave(&device_domain_lock, flags1);
3875 }
3876 spin_unlock_irqrestore(&device_domain_lock, flags1);
3877}
3878
Weidong Han5e98c4b2008-12-08 23:03:27 +08003879/* domain id for virtual machine, it won't be set in context */
3880static unsigned long vm_domid;
3881
3882static struct dmar_domain *iommu_alloc_vm_domain(void)
3883{
3884 struct dmar_domain *domain;
3885
3886 domain = alloc_domain_mem();
3887 if (!domain)
3888 return NULL;
3889
3890 domain->id = vm_domid++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003891 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08003892 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003893 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3894
3895 return domain;
3896}
3897
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003898static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003899{
3900 int adjust_width;
3901
3902 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003903 spin_lock_init(&domain->iommu_lock);
3904
3905 domain_reserve_special_ranges(domain);
3906
3907 /* calculate AGAW */
3908 domain->gaw = guest_width;
3909 adjust_width = guestwidth_to_adjustwidth(guest_width);
3910 domain->agaw = width_to_agaw(adjust_width);
3911
3912 INIT_LIST_HEAD(&domain->devices);
3913
3914 domain->iommu_count = 0;
3915 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003916 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003917 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003918 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003919 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003920
3921 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003922 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003923 if (!domain->pgd)
3924 return -ENOMEM;
3925 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3926 return 0;
3927}
3928
3929static void iommu_free_vm_domain(struct dmar_domain *domain)
3930{
3931 unsigned long flags;
3932 struct dmar_drhd_unit *drhd;
3933 struct intel_iommu *iommu;
3934 unsigned long i;
3935 unsigned long ndomains;
3936
3937 for_each_drhd_unit(drhd) {
3938 if (drhd->ignored)
3939 continue;
3940 iommu = drhd->iommu;
3941
3942 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08003943 for_each_set_bit(i, iommu->domain_ids, ndomains) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003944 if (iommu->domains[i] == domain) {
3945 spin_lock_irqsave(&iommu->lock, flags);
3946 clear_bit(i, iommu->domain_ids);
3947 iommu->domains[i] = NULL;
3948 spin_unlock_irqrestore(&iommu->lock, flags);
3949 break;
3950 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08003951 }
3952 }
3953}
3954
3955static void vm_domain_exit(struct dmar_domain *domain)
3956{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003957 /* Domain 0 is reserved, so dont process it */
3958 if (!domain)
3959 return;
3960
3961 vm_domain_remove_all_dev_info(domain);
3962 /* destroy iovas */
3963 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003964
3965 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003966 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003967
3968 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003969 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003970
3971 iommu_free_vm_domain(domain);
3972 free_domain_mem(domain);
3973}
3974
Joerg Roedel5d450802008-12-03 14:52:32 +01003975static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003976{
Joerg Roedel5d450802008-12-03 14:52:32 +01003977 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003978
Joerg Roedel5d450802008-12-03 14:52:32 +01003979 dmar_domain = iommu_alloc_vm_domain();
3980 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003981 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003982 "intel_iommu_domain_init: dmar_domain == NULL\n");
3983 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003984 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003985 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003986 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003987 "intel_iommu_domain_init() failed\n");
3988 vm_domain_exit(dmar_domain);
3989 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003990 }
Allen Kay8140a952011-10-14 12:32:17 -07003991 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003992 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003993
Joerg Roedel5d450802008-12-03 14:52:32 +01003994 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003995}
Kay, Allen M38717942008-09-09 18:37:29 +03003996
Joerg Roedel5d450802008-12-03 14:52:32 +01003997static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003998{
Joerg Roedel5d450802008-12-03 14:52:32 +01003999 struct dmar_domain *dmar_domain = domain->priv;
4000
4001 domain->priv = NULL;
4002 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03004003}
Kay, Allen M38717942008-09-09 18:37:29 +03004004
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004005static int intel_iommu_attach_device(struct iommu_domain *domain,
4006 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004007{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004008 struct dmar_domain *dmar_domain = domain->priv;
4009 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004010 struct intel_iommu *iommu;
4011 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03004012
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004013 /* normally pdev is not mapped */
4014 if (unlikely(domain_context_mapped(pdev))) {
4015 struct dmar_domain *old_domain;
4016
4017 old_domain = find_domain(pdev);
4018 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004019 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
4020 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
4021 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004022 else
4023 domain_remove_dev_info(old_domain);
4024 }
4025 }
4026
David Woodhouse276dbf92009-04-04 01:45:37 +01004027 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
4028 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004029 if (!iommu)
4030 return -ENODEV;
4031
4032 /* check if this iommu agaw is sufficient for max mapped address */
4033 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01004034 if (addr_width > cap_mgaw(iommu->cap))
4035 addr_width = cap_mgaw(iommu->cap);
4036
4037 if (dmar_domain->max_addr > (1LL << addr_width)) {
4038 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004039 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01004040 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004041 return -EFAULT;
4042 }
Tom Lyona99c47a2010-05-17 08:20:45 +01004043 dmar_domain->gaw = addr_width;
4044
4045 /*
4046 * Knock out extra levels of page tables if necessary
4047 */
4048 while (iommu->agaw < dmar_domain->agaw) {
4049 struct dma_pte *pte;
4050
4051 pte = dmar_domain->pgd;
4052 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08004053 dmar_domain->pgd = (struct dma_pte *)
4054 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01004055 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01004056 }
4057 dmar_domain->agaw--;
4058 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004059
David Woodhouse5fe60f42009-08-09 10:53:41 +01004060 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004061}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004062
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004063static void intel_iommu_detach_device(struct iommu_domain *domain,
4064 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004065{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004066 struct dmar_domain *dmar_domain = domain->priv;
4067 struct pci_dev *pdev = to_pci_dev(dev);
4068
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004069 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03004070}
Kay, Allen M38717942008-09-09 18:37:29 +03004071
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004072static int intel_iommu_map(struct iommu_domain *domain,
4073 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004074 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03004075{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004076 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004077 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004078 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004079 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004080
Joerg Roedeldde57a22008-12-03 15:04:09 +01004081 if (iommu_prot & IOMMU_READ)
4082 prot |= DMA_PTE_READ;
4083 if (iommu_prot & IOMMU_WRITE)
4084 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08004085 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4086 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004087
David Woodhouse163cc522009-06-28 00:51:17 +01004088 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004089 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004090 u64 end;
4091
4092 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01004093 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004094 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004095 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004096 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004097 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004098 return -EFAULT;
4099 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004100 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004101 }
David Woodhousead051222009-06-28 14:22:28 +01004102 /* Round up size to next multiple of PAGE_SIZE, if it and
4103 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004104 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004105 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4106 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004107 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004108}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004109
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004110static size_t intel_iommu_unmap(struct iommu_domain *domain,
4111 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004112{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004113 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07004114 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01004115
Allen Kay292827c2011-10-14 12:31:54 -07004116 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004117 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004118
David Woodhouse163cc522009-06-28 00:51:17 +01004119 if (dmar_domain->max_addr == iova + size)
4120 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004121
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004122 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004123}
Kay, Allen M38717942008-09-09 18:37:29 +03004124
Joerg Roedeld14d6572008-12-03 15:06:57 +01004125static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
4126 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004127{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004128 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004129 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004130 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004131
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004132 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004133 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004134 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004135
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004136 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004137}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004138
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004139static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4140 unsigned long cap)
4141{
4142 struct dmar_domain *dmar_domain = domain->priv;
4143
4144 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4145 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004146 if (cap == IOMMU_CAP_INTR_REMAP)
4147 return intr_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004148
4149 return 0;
4150}
4151
Alex Williamson70ae6f02011-10-21 15:56:11 -04004152/*
4153 * Group numbers are arbitrary. Device with the same group number
4154 * indicate the iommu cannot differentiate between them. To avoid
4155 * tracking used groups we just use the seg|bus|devfn of the lowest
4156 * level we're able to differentiate devices
4157 */
4158static int intel_iommu_device_group(struct device *dev, unsigned int *groupid)
4159{
4160 struct pci_dev *pdev = to_pci_dev(dev);
4161 struct pci_dev *bridge;
4162 union {
4163 struct {
4164 u8 devfn;
4165 u8 bus;
4166 u16 segment;
4167 } pci;
4168 u32 group;
4169 } id;
4170
4171 if (iommu_no_mapping(dev))
4172 return -ENODEV;
4173
4174 id.pci.segment = pci_domain_nr(pdev->bus);
4175 id.pci.bus = pdev->bus->number;
4176 id.pci.devfn = pdev->devfn;
4177
4178 if (!device_to_iommu(id.pci.segment, id.pci.bus, id.pci.devfn))
4179 return -ENODEV;
4180
4181 bridge = pci_find_upstream_pcie_bridge(pdev);
4182 if (bridge) {
4183 if (pci_is_pcie(bridge)) {
4184 id.pci.bus = bridge->subordinate->number;
4185 id.pci.devfn = 0;
4186 } else {
4187 id.pci.bus = bridge->bus->number;
4188 id.pci.devfn = bridge->devfn;
4189 }
4190 }
4191
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004192 if (!pdev->is_virtfn && iommu_group_mf)
4193 id.pci.devfn = PCI_DEVFN(PCI_SLOT(id.pci.devfn), 0);
4194
Alex Williamson70ae6f02011-10-21 15:56:11 -04004195 *groupid = id.group;
4196
4197 return 0;
4198}
4199
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004200static struct iommu_ops intel_iommu_ops = {
4201 .domain_init = intel_iommu_domain_init,
4202 .domain_destroy = intel_iommu_domain_destroy,
4203 .attach_dev = intel_iommu_attach_device,
4204 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004205 .map = intel_iommu_map,
4206 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004207 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004208 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamson70ae6f02011-10-21 15:56:11 -04004209 .device_group = intel_iommu_device_group,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004210 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004211};
David Woodhouse9af88142009-02-13 23:18:03 +00004212
Daniel Vetter4b56ffb2013-01-20 23:50:13 +01004213static void __devinit quirk_iommu_g4x_gfx(struct pci_dev *dev)
4214{
4215 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4216 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4217 dmar_map_gfx = 0;
4218}
4219
4220DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4221DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4222DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4223DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4224DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4225DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4226DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4227
David Woodhouse9af88142009-02-13 23:18:03 +00004228static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
4229{
4230 /*
4231 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetterdf87bd32013-01-21 19:48:59 +01004232 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004233 */
4234 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4235 rwbf_quirk = 1;
4236}
4237
4238DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetterdf87bd32013-01-21 19:48:59 +01004239DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4240DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4241DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4242DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4243DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4244DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004245
Adam Jacksoneecfd572010-08-25 21:17:34 +01004246#define GGC 0x52
4247#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4248#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4249#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4250#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4251#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4252#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4253#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4254#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4255
David Woodhouse9eecabc2010-09-21 22:28:23 +01004256static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
4257{
4258 unsigned short ggc;
4259
Adam Jacksoneecfd572010-08-25 21:17:34 +01004260 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004261 return;
4262
Adam Jacksoneecfd572010-08-25 21:17:34 +01004263 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004264 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4265 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004266 } else if (dmar_map_gfx) {
4267 /* we have to ensure the gfx device is idle before we flush */
4268 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4269 intel_iommu_strict = 1;
4270 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004271}
4272DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4273DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4274DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4275DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4276
David Woodhousee0fc7e02009-09-30 09:12:17 -07004277/* On Tylersburg chipsets, some BIOSes have been known to enable the
4278 ISOCH DMAR unit for the Azalia sound device, but not give it any
4279 TLB entries, which causes it to deadlock. Check for that. We do
4280 this in a function called from init_dmars(), instead of in a PCI
4281 quirk, because we don't want to print the obnoxious "BIOS broken"
4282 message if VT-d is actually disabled.
4283*/
4284static void __init check_tylersburg_isoch(void)
4285{
4286 struct pci_dev *pdev;
4287 uint32_t vtisochctrl;
4288
4289 /* If there's no Azalia in the system anyway, forget it. */
4290 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4291 if (!pdev)
4292 return;
4293 pci_dev_put(pdev);
4294
4295 /* System Management Registers. Might be hidden, in which case
4296 we can't do the sanity check. But that's OK, because the
4297 known-broken BIOSes _don't_ actually hide it, so far. */
4298 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4299 if (!pdev)
4300 return;
4301
4302 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4303 pci_dev_put(pdev);
4304 return;
4305 }
4306
4307 pci_dev_put(pdev);
4308
4309 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4310 if (vtisochctrl & 1)
4311 return;
4312
4313 /* Drop all bits other than the number of TLB entries */
4314 vtisochctrl &= 0x1c;
4315
4316 /* If we have the recommended number of TLB entries (16), fine. */
4317 if (vtisochctrl == 0x10)
4318 return;
4319
4320 /* Zero TLB entries? You get to ride the short bus to school. */
4321 if (!vtisochctrl) {
4322 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4323 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4324 dmi_get_system_info(DMI_BIOS_VENDOR),
4325 dmi_get_system_info(DMI_BIOS_VERSION),
4326 dmi_get_system_info(DMI_PRODUCT_VERSION));
4327 iommu_identity_mapping |= IDENTMAP_AZALIA;
4328 return;
4329 }
4330
4331 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4332 vtisochctrl);
4333}