blob: 17119247ac4c40ba1f340dbc6af3220088f0cf24 [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);
David Woodhouseb026fd22009-06-28 10:37:25 +0100781 BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700782 parent = domain->pgd;
783
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700784 while (level > 0) {
785 void *tmp_page;
786
David Woodhouseb026fd22009-06-28 10:37:25 +0100787 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700788 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700789 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100790 break;
791 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700792 break;
793
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000794 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100795 uint64_t pteval;
796
Suresh Siddha4c923d42009-10-02 11:01:24 -0700797 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700798
David Woodhouse206a73c2009-07-01 19:30:28 +0100799 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700800 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100801
David Woodhousec85994e2009-07-01 19:21:24 +0100802 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400803 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 +0100804 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
805 /* Someone else set it while we were thinking; use theirs. */
806 free_pgtable_page(tmp_page);
807 } else {
808 dma_pte_addr(pte);
809 domain_flush_cache(domain, pte, sizeof(*pte));
810 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700811 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000812 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700813 level--;
814 }
815
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700816 return pte;
817}
818
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100819
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700820/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100821static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
822 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100823 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700824{
825 struct dma_pte *parent, *pte = NULL;
826 int total = agaw_to_level(domain->agaw);
827 int offset;
828
829 parent = domain->pgd;
830 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100831 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700832 pte = &parent[offset];
833 if (level == total)
834 return pte;
835
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100836 if (!dma_pte_present(pte)) {
837 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700838 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100839 }
840
841 if (pte->val & DMA_PTE_LARGE_PAGE) {
842 *large_page = total;
843 return pte;
844 }
845
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000846 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700847 total--;
848 }
849 return NULL;
850}
851
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700852/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700853static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100854 unsigned long start_pfn,
855 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700856{
David Woodhouse04b18e62009-06-27 19:15:01 +0100857 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100858 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100859 struct dma_pte *first_pte, *pte;
Allen Kay292827c2011-10-14 12:31:54 -0700860 int order;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700861
David Woodhouse04b18e62009-06-27 19:15:01 +0100862 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100863 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700864 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100865
David Woodhouse04b18e62009-06-27 19:15:01 +0100866 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700867 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100868 large_page = 1;
869 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100870 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100871 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100872 continue;
873 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100874 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100875 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100876 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100877 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100878 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
879
David Woodhouse310a5ab2009-06-28 18:52:20 +0100880 domain_flush_cache(domain, first_pte,
881 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700882
883 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700884
885 order = (large_page - 1) * 9;
886 return order;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700887}
888
889/* free page table pages. last level pte should already be cleared */
890static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100891 unsigned long start_pfn,
892 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700893{
David Woodhouse6660c632009-06-27 22:41:00 +0100894 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhousef3a0a522009-06-30 03:40:07 +0100895 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700896 int total = agaw_to_level(domain->agaw);
897 int level;
David Woodhouse6660c632009-06-27 22:41:00 +0100898 unsigned long tmp;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100899 int large_page = 2;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700900
David Woodhouse6660c632009-06-27 22:41:00 +0100901 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
902 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700903 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700904
David Woodhousef3a0a522009-06-30 03:40:07 +0100905 /* We don't need lock here; nobody else touches the iova range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700906 level = 2;
907 while (level <= total) {
David Woodhouse6660c632009-06-27 22:41:00 +0100908 tmp = align_to_level(start_pfn, level);
909
David Woodhousef3a0a522009-06-30 03:40:07 +0100910 /* If we can't even clear one PTE at this level, we're done */
David Woodhouse6660c632009-06-27 22:41:00 +0100911 if (tmp + level_size(level) - 1 > last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700912 return;
913
David Woodhouse59c36282009-09-19 07:36:28 -0700914 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100915 large_page = level;
916 first_pte = pte = dma_pfn_level_pte(domain, tmp, level, &large_page);
917 if (large_page > level)
918 level = large_page + 1;
David Woodhousef3a0a522009-06-30 03:40:07 +0100919 if (!pte) {
920 tmp = align_to_level(tmp + 1, level + 1);
921 continue;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700922 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100923 do {
David Woodhouse6a43e572009-07-02 12:02:34 +0100924 if (dma_pte_present(pte)) {
925 free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
926 dma_clear_pte(pte);
927 }
David Woodhousef3a0a522009-06-30 03:40:07 +0100928 pte++;
929 tmp += level_size(level);
David Woodhouse75e6bf92009-07-02 11:21:16 +0100930 } while (!first_pte_in_page(pte) &&
931 tmp + level_size(level) - 1 <= last_pfn);
932
David Woodhousef3a0a522009-06-30 03:40:07 +0100933 domain_flush_cache(domain, first_pte,
934 (void *)pte - (void *)first_pte);
935
David Woodhouse59c36282009-09-19 07:36:28 -0700936 } while (tmp && tmp + level_size(level) - 1 <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700937 level++;
938 }
939 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100940 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700941 free_pgtable_page(domain->pgd);
942 domain->pgd = NULL;
943 }
944}
945
946/* iommu handling */
947static int iommu_alloc_root_entry(struct intel_iommu *iommu)
948{
949 struct root_entry *root;
950 unsigned long flags;
951
Suresh Siddha4c923d42009-10-02 11:01:24 -0700952 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700953 if (!root)
954 return -ENOMEM;
955
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700956 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700957
958 spin_lock_irqsave(&iommu->lock, flags);
959 iommu->root_entry = root;
960 spin_unlock_irqrestore(&iommu->lock, flags);
961
962 return 0;
963}
964
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700965static void iommu_set_root_entry(struct intel_iommu *iommu)
966{
967 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100968 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700969 unsigned long flag;
970
971 addr = iommu->root_entry;
972
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200973 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700974 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
975
David Woodhousec416daa2009-05-10 20:30:58 +0100976 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700977
978 /* Make sure hardware complete it */
979 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100980 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700981
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200982 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700983}
984
985static void iommu_flush_write_buffer(struct intel_iommu *iommu)
986{
987 u32 val;
988 unsigned long flag;
989
David Woodhouse9af88142009-02-13 23:18:03 +0000990 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700991 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700992
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200993 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100994 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700995
996 /* Make sure hardware complete it */
997 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100998 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700999
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001000 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001001}
1002
1003/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001004static void __iommu_flush_context(struct intel_iommu *iommu,
1005 u16 did, u16 source_id, u8 function_mask,
1006 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001007{
1008 u64 val = 0;
1009 unsigned long flag;
1010
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001011 switch (type) {
1012 case DMA_CCMD_GLOBAL_INVL:
1013 val = DMA_CCMD_GLOBAL_INVL;
1014 break;
1015 case DMA_CCMD_DOMAIN_INVL:
1016 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1017 break;
1018 case DMA_CCMD_DEVICE_INVL:
1019 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1020 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1021 break;
1022 default:
1023 BUG();
1024 }
1025 val |= DMA_CCMD_ICC;
1026
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001027 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001028 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1029
1030 /* Make sure hardware complete it */
1031 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1032 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1033
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001034 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001035}
1036
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001037/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001038static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1039 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001040{
1041 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1042 u64 val = 0, val_iva = 0;
1043 unsigned long flag;
1044
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001045 switch (type) {
1046 case DMA_TLB_GLOBAL_FLUSH:
1047 /* global flush doesn't need set IVA_REG */
1048 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1049 break;
1050 case DMA_TLB_DSI_FLUSH:
1051 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1052 break;
1053 case DMA_TLB_PSI_FLUSH:
1054 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1055 /* Note: always flush non-leaf currently */
1056 val_iva = size_order | addr;
1057 break;
1058 default:
1059 BUG();
1060 }
1061 /* Note: set drain read/write */
1062#if 0
1063 /*
1064 * This is probably to be super secure.. Looks like we can
1065 * ignore it without any impact.
1066 */
1067 if (cap_read_drain(iommu->cap))
1068 val |= DMA_TLB_READ_DRAIN;
1069#endif
1070 if (cap_write_drain(iommu->cap))
1071 val |= DMA_TLB_WRITE_DRAIN;
1072
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001073 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001074 /* Note: Only uses first TLB reg currently */
1075 if (val_iva)
1076 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1077 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1078
1079 /* Make sure hardware complete it */
1080 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1081 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1082
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001083 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001084
1085 /* check IOTLB invalidation granularity */
1086 if (DMA_TLB_IAIG(val) == 0)
1087 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1088 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1089 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001090 (unsigned long long)DMA_TLB_IIRG(type),
1091 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001092}
1093
Yu Zhao93a23a72009-05-18 13:51:37 +08001094static struct device_domain_info *iommu_support_dev_iotlb(
1095 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001096{
Yu Zhao93a23a72009-05-18 13:51:37 +08001097 int found = 0;
1098 unsigned long flags;
1099 struct device_domain_info *info;
1100 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1101
1102 if (!ecap_dev_iotlb_support(iommu->ecap))
1103 return NULL;
1104
1105 if (!iommu->qi)
1106 return NULL;
1107
1108 spin_lock_irqsave(&device_domain_lock, flags);
1109 list_for_each_entry(info, &domain->devices, link)
1110 if (info->bus == bus && info->devfn == devfn) {
1111 found = 1;
1112 break;
1113 }
1114 spin_unlock_irqrestore(&device_domain_lock, flags);
1115
1116 if (!found || !info->dev)
1117 return NULL;
1118
1119 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1120 return NULL;
1121
1122 if (!dmar_find_matched_atsr_unit(info->dev))
1123 return NULL;
1124
1125 info->iommu = iommu;
1126
1127 return info;
1128}
1129
1130static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1131{
1132 if (!info)
1133 return;
1134
1135 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1136}
1137
1138static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1139{
1140 if (!info->dev || !pci_ats_enabled(info->dev))
1141 return;
1142
1143 pci_disable_ats(info->dev);
1144}
1145
1146static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1147 u64 addr, unsigned mask)
1148{
1149 u16 sid, qdep;
1150 unsigned long flags;
1151 struct device_domain_info *info;
1152
1153 spin_lock_irqsave(&device_domain_lock, flags);
1154 list_for_each_entry(info, &domain->devices, link) {
1155 if (!info->dev || !pci_ats_enabled(info->dev))
1156 continue;
1157
1158 sid = info->bus << 8 | info->devfn;
1159 qdep = pci_ats_queue_depth(info->dev);
1160 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1161 }
1162 spin_unlock_irqrestore(&device_domain_lock, flags);
1163}
1164
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001165static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001166 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001167{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001168 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001169 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001170
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001171 BUG_ON(pages == 0);
1172
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001173 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001174 * Fallback to domain selective flush if no PSI support or the size is
1175 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001176 * PSI requires page size to be 2 ^ x, and the base address is naturally
1177 * aligned to the size
1178 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001179 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1180 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001181 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001182 else
1183 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1184 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001185
1186 /*
Nadav Amit82653632010-04-01 13:24:40 +03001187 * In caching mode, changes of pages from non-present to present require
1188 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001189 */
Nadav Amit82653632010-04-01 13:24:40 +03001190 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001191 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001192}
1193
mark grossf8bab732008-02-08 04:18:38 -08001194static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1195{
1196 u32 pmen;
1197 unsigned long flags;
1198
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001199 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001200 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1201 pmen &= ~DMA_PMEN_EPM;
1202 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1203
1204 /* wait for the protected region status bit to clear */
1205 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1206 readl, !(pmen & DMA_PMEN_PRS), pmen);
1207
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001208 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001209}
1210
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001211static int iommu_enable_translation(struct intel_iommu *iommu)
1212{
1213 u32 sts;
1214 unsigned long flags;
1215
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001216 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001217 iommu->gcmd |= DMA_GCMD_TE;
1218 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001219
1220 /* Make sure hardware complete it */
1221 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001222 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001223
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001224 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001225 return 0;
1226}
1227
1228static int iommu_disable_translation(struct intel_iommu *iommu)
1229{
1230 u32 sts;
1231 unsigned long flag;
1232
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001233 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001234 iommu->gcmd &= ~DMA_GCMD_TE;
1235 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1236
1237 /* Make sure hardware complete it */
1238 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001239 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001240
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001241 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001242 return 0;
1243}
1244
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001245
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001246static int iommu_init_domains(struct intel_iommu *iommu)
1247{
1248 unsigned long ndomains;
1249 unsigned long nlongs;
1250
1251 ndomains = cap_ndoms(iommu->cap);
Masanari Iida68aeb962012-01-25 00:25:52 +09001252 pr_debug("IOMMU %d: Number of Domains supported <%ld>\n", iommu->seq_id,
Yinghai Lu680a7522010-04-08 19:58:23 +01001253 ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001254 nlongs = BITS_TO_LONGS(ndomains);
1255
Donald Dutile94a91b52009-08-20 16:51:34 -04001256 spin_lock_init(&iommu->lock);
1257
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001258 /* TBD: there might be 64K domains,
1259 * consider other allocation for future chip
1260 */
1261 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1262 if (!iommu->domain_ids) {
1263 printk(KERN_ERR "Allocating domain id array failed\n");
1264 return -ENOMEM;
1265 }
1266 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1267 GFP_KERNEL);
1268 if (!iommu->domains) {
1269 printk(KERN_ERR "Allocating domain array failed\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001270 return -ENOMEM;
1271 }
1272
1273 /*
1274 * if Caching mode is set, then invalid translations are tagged
1275 * with domainid 0. Hence we need to pre-allocate it.
1276 */
1277 if (cap_caching_mode(iommu->cap))
1278 set_bit(0, iommu->domain_ids);
1279 return 0;
1280}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001281
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001282
1283static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001284static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001285
1286void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001287{
1288 struct dmar_domain *domain;
1289 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001290 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001291
Donald Dutile94a91b52009-08-20 16:51:34 -04001292 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001293 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001294 domain = iommu->domains[i];
1295 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001296
Donald Dutile94a91b52009-08-20 16:51:34 -04001297 spin_lock_irqsave(&domain->iommu_lock, flags);
1298 if (--domain->iommu_count == 0) {
1299 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1300 vm_domain_exit(domain);
1301 else
1302 domain_exit(domain);
1303 }
1304 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001305 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001306 }
1307
1308 if (iommu->gcmd & DMA_GCMD_TE)
1309 iommu_disable_translation(iommu);
1310
1311 if (iommu->irq) {
Thomas Gleixnerdced35a2011-03-28 17:49:12 +02001312 irq_set_handler_data(iommu->irq, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001313 /* This will mask the irq */
1314 free_irq(iommu->irq, iommu);
1315 destroy_irq(iommu->irq);
1316 }
1317
1318 kfree(iommu->domains);
1319 kfree(iommu->domain_ids);
1320
Weidong Hand9630fe2008-12-08 11:06:32 +08001321 g_iommus[iommu->seq_id] = NULL;
1322
1323 /* if all iommus are freed, free g_iommus */
1324 for (i = 0; i < g_num_of_iommus; i++) {
1325 if (g_iommus[i])
1326 break;
1327 }
1328
1329 if (i == g_num_of_iommus)
1330 kfree(g_iommus);
1331
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001332 /* free context mapping */
1333 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001334}
1335
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001336static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001337{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001338 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001339
1340 domain = alloc_domain_mem();
1341 if (!domain)
1342 return NULL;
1343
Suresh Siddha4c923d42009-10-02 11:01:24 -07001344 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08001345 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001346 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001347
1348 return domain;
1349}
1350
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001351static int iommu_attach_domain(struct dmar_domain *domain,
1352 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001353{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001354 int num;
1355 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001356 unsigned long flags;
1357
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001358 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001359
1360 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001361
1362 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1363 if (num >= ndomains) {
1364 spin_unlock_irqrestore(&iommu->lock, flags);
1365 printk(KERN_ERR "IOMMU: no free domain ids\n");
1366 return -ENOMEM;
1367 }
1368
1369 domain->id = num;
1370 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001371 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001372 iommu->domains[num] = domain;
1373 spin_unlock_irqrestore(&iommu->lock, flags);
1374
1375 return 0;
1376}
1377
1378static void iommu_detach_domain(struct dmar_domain *domain,
1379 struct intel_iommu *iommu)
1380{
1381 unsigned long flags;
1382 int num, ndomains;
1383 int found = 0;
1384
1385 spin_lock_irqsave(&iommu->lock, flags);
1386 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001387 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001388 if (iommu->domains[num] == domain) {
1389 found = 1;
1390 break;
1391 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001392 }
1393
1394 if (found) {
1395 clear_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001396 clear_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001397 iommu->domains[num] = NULL;
1398 }
Weidong Han8c11e792008-12-08 15:29:22 +08001399 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001400}
1401
1402static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001403static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001404
Joseph Cihula51a63e62011-03-21 11:04:24 -07001405static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001406{
1407 struct pci_dev *pdev = NULL;
1408 struct iova *iova;
1409 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001410
David Millerf6611972008-02-06 01:36:23 -08001411 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001412
Mark Gross8a443df2008-03-04 14:59:31 -08001413 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1414 &reserved_rbtree_key);
1415
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001416 /* IOAPIC ranges shouldn't be accessed by DMA */
1417 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1418 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001419 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001420 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001421 return -ENODEV;
1422 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001423
1424 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1425 for_each_pci_dev(pdev) {
1426 struct resource *r;
1427
1428 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1429 r = &pdev->resource[i];
1430 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1431 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001432 iova = reserve_iova(&reserved_iova_list,
1433 IOVA_PFN(r->start),
1434 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001435 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001436 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001437 return -ENODEV;
1438 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001439 }
1440 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001441 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001442}
1443
1444static void domain_reserve_special_ranges(struct dmar_domain *domain)
1445{
1446 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1447}
1448
1449static inline int guestwidth_to_adjustwidth(int gaw)
1450{
1451 int agaw;
1452 int r = (gaw - 12) % 9;
1453
1454 if (r == 0)
1455 agaw = gaw;
1456 else
1457 agaw = gaw + 9 - r;
1458 if (agaw > 64)
1459 agaw = 64;
1460 return agaw;
1461}
1462
1463static int domain_init(struct dmar_domain *domain, int guest_width)
1464{
1465 struct intel_iommu *iommu;
1466 int adjust_width, agaw;
1467 unsigned long sagaw;
1468
David Millerf6611972008-02-06 01:36:23 -08001469 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001470 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001471
1472 domain_reserve_special_ranges(domain);
1473
1474 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001475 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001476 if (guest_width > cap_mgaw(iommu->cap))
1477 guest_width = cap_mgaw(iommu->cap);
1478 domain->gaw = guest_width;
1479 adjust_width = guestwidth_to_adjustwidth(guest_width);
1480 agaw = width_to_agaw(adjust_width);
1481 sagaw = cap_sagaw(iommu->cap);
1482 if (!test_bit(agaw, &sagaw)) {
1483 /* hardware doesn't support it, choose a bigger one */
1484 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1485 agaw = find_next_bit(&sagaw, 5, agaw);
1486 if (agaw >= 5)
1487 return -ENODEV;
1488 }
1489 domain->agaw = agaw;
1490 INIT_LIST_HEAD(&domain->devices);
1491
Weidong Han8e604092008-12-08 15:49:06 +08001492 if (ecap_coherent(iommu->ecap))
1493 domain->iommu_coherency = 1;
1494 else
1495 domain->iommu_coherency = 0;
1496
Sheng Yang58c610b2009-03-18 15:33:05 +08001497 if (ecap_sc_support(iommu->ecap))
1498 domain->iommu_snooping = 1;
1499 else
1500 domain->iommu_snooping = 0;
1501
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001502 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Weidong Hanc7151a82008-12-08 22:51:37 +08001503 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001504 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001505
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001506 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001507 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001508 if (!domain->pgd)
1509 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001510 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001511 return 0;
1512}
1513
1514static void domain_exit(struct dmar_domain *domain)
1515{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001516 struct dmar_drhd_unit *drhd;
1517 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001518
1519 /* Domain 0 is reserved, so dont process it */
1520 if (!domain)
1521 return;
1522
Alex Williamson7b668352011-05-24 12:02:41 +01001523 /* Flush any lazy unmaps that may reference this domain */
1524 if (!intel_iommu_strict)
1525 flush_unmaps_timeout(0);
1526
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001527 domain_remove_dev_info(domain);
1528 /* destroy iovas */
1529 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001530
1531 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001532 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001533
1534 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001535 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001536
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001537 for_each_active_iommu(iommu, drhd)
Mike Travis1b198bb2012-03-05 15:05:16 -08001538 if (test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001539 iommu_detach_domain(domain, iommu);
1540
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001541 free_domain_mem(domain);
1542}
1543
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001544static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1545 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001546{
1547 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001548 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001549 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001550 struct dma_pte *pgd;
1551 unsigned long num;
1552 unsigned long ndomains;
1553 int id;
1554 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001555 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001556
1557 pr_debug("Set context mapping for %02x:%02x.%d\n",
1558 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001559
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001560 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001561 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1562 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001563
David Woodhouse276dbf92009-04-04 01:45:37 +01001564 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001565 if (!iommu)
1566 return -ENODEV;
1567
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001568 context = device_to_context_entry(iommu, bus, devfn);
1569 if (!context)
1570 return -ENOMEM;
1571 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001572 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001573 spin_unlock_irqrestore(&iommu->lock, flags);
1574 return 0;
1575 }
1576
Weidong Hanea6606b2008-12-08 23:08:15 +08001577 id = domain->id;
1578 pgd = domain->pgd;
1579
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001580 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1581 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001582 int found = 0;
1583
1584 /* find an available domain id for this device in iommu */
1585 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001586 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001587 if (iommu->domains[num] == domain) {
1588 id = num;
1589 found = 1;
1590 break;
1591 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001592 }
1593
1594 if (found == 0) {
1595 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1596 if (num >= ndomains) {
1597 spin_unlock_irqrestore(&iommu->lock, flags);
1598 printk(KERN_ERR "IOMMU: no free domain ids\n");
1599 return -EFAULT;
1600 }
1601
1602 set_bit(num, iommu->domain_ids);
1603 iommu->domains[num] = domain;
1604 id = num;
1605 }
1606
1607 /* Skip top levels of page tables for
1608 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001609 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001610 */
Chris Wright1672af12009-12-02 12:06:34 -08001611 if (translation != CONTEXT_TT_PASS_THROUGH) {
1612 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1613 pgd = phys_to_virt(dma_pte_addr(pgd));
1614 if (!dma_pte_present(pgd)) {
1615 spin_unlock_irqrestore(&iommu->lock, flags);
1616 return -ENOMEM;
1617 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001618 }
1619 }
1620 }
1621
1622 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001623
Yu Zhao93a23a72009-05-18 13:51:37 +08001624 if (translation != CONTEXT_TT_PASS_THROUGH) {
1625 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1626 translation = info ? CONTEXT_TT_DEV_IOTLB :
1627 CONTEXT_TT_MULTI_LEVEL;
1628 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001629 /*
1630 * In pass through mode, AW must be programmed to indicate the largest
1631 * AGAW value supported by hardware. And ASR is ignored by hardware.
1632 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001633 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001634 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001635 else {
1636 context_set_address_root(context, virt_to_phys(pgd));
1637 context_set_address_width(context, iommu->agaw);
1638 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001639
1640 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001641 context_set_fault_enable(context);
1642 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001643 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001644
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001645 /*
1646 * It's a non-present to present mapping. If hardware doesn't cache
1647 * non-present entry we only need to flush the write-buffer. If the
1648 * _does_ cache non-present entries, then it does so in the special
1649 * domain #0, which we have to flush:
1650 */
1651 if (cap_caching_mode(iommu->cap)) {
1652 iommu->flush.flush_context(iommu, 0,
1653 (((u16)bus) << 8) | devfn,
1654 DMA_CCMD_MASK_NOBIT,
1655 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001656 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001657 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001658 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001659 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001660 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001661 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001662
1663 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001664 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001665 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001666 if (domain->iommu_count == 1)
1667 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001668 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001669 }
1670 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001671 return 0;
1672}
1673
1674static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001675domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1676 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001677{
1678 int ret;
1679 struct pci_dev *tmp, *parent;
1680
David Woodhouse276dbf92009-04-04 01:45:37 +01001681 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001682 pdev->bus->number, pdev->devfn,
1683 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001684 if (ret)
1685 return ret;
1686
1687 /* dependent device mapping */
1688 tmp = pci_find_upstream_pcie_bridge(pdev);
1689 if (!tmp)
1690 return 0;
1691 /* Secondary interface's bus number and devfn 0 */
1692 parent = pdev->bus->self;
1693 while (parent != tmp) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001694 ret = domain_context_mapping_one(domain,
1695 pci_domain_nr(parent->bus),
1696 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001697 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001698 if (ret)
1699 return ret;
1700 parent = parent->bus->self;
1701 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001702 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001703 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001704 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001705 tmp->subordinate->number, 0,
1706 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001707 else /* this is a legacy PCI bridge */
1708 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001709 pci_domain_nr(tmp->bus),
1710 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001711 tmp->devfn,
1712 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001713}
1714
Weidong Han5331fe62008-12-08 23:00:00 +08001715static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001716{
1717 int ret;
1718 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001719 struct intel_iommu *iommu;
1720
David Woodhouse276dbf92009-04-04 01:45:37 +01001721 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1722 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001723 if (!iommu)
1724 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001725
David Woodhouse276dbf92009-04-04 01:45:37 +01001726 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001727 if (!ret)
1728 return ret;
1729 /* dependent device mapping */
1730 tmp = pci_find_upstream_pcie_bridge(pdev);
1731 if (!tmp)
1732 return ret;
1733 /* Secondary interface's bus number and devfn 0 */
1734 parent = pdev->bus->self;
1735 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001736 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01001737 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001738 if (!ret)
1739 return ret;
1740 parent = parent->bus->self;
1741 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001742 if (pci_is_pcie(tmp))
David Woodhouse276dbf92009-04-04 01:45:37 +01001743 return device_context_mapped(iommu, tmp->subordinate->number,
1744 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001745 else
David Woodhouse276dbf92009-04-04 01:45:37 +01001746 return device_context_mapped(iommu, tmp->bus->number,
1747 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001748}
1749
Fenghua Yuf5329592009-08-04 15:09:37 -07001750/* Returns a number of VTD pages, but aligned to MM page size */
1751static inline unsigned long aligned_nrpages(unsigned long host_addr,
1752 size_t size)
1753{
1754 host_addr &= ~PAGE_MASK;
1755 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1756}
1757
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001758/* Return largest possible superpage level for a given mapping */
1759static inline int hardware_largepage_caps(struct dmar_domain *domain,
1760 unsigned long iov_pfn,
1761 unsigned long phy_pfn,
1762 unsigned long pages)
1763{
1764 int support, level = 1;
1765 unsigned long pfnmerge;
1766
1767 support = domain->iommu_superpage;
1768
1769 /* To use a large page, the virtual *and* physical addresses
1770 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1771 of them will mean we have to use smaller pages. So just
1772 merge them and check both at once. */
1773 pfnmerge = iov_pfn | phy_pfn;
1774
1775 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1776 pages >>= VTD_STRIDE_SHIFT;
1777 if (!pages)
1778 break;
1779 pfnmerge >>= VTD_STRIDE_SHIFT;
1780 level++;
1781 support--;
1782 }
1783 return level;
1784}
1785
David Woodhouse9051aa02009-06-29 12:30:54 +01001786static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1787 struct scatterlist *sg, unsigned long phys_pfn,
1788 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001789{
1790 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001791 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001792 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001793 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001794 unsigned int largepage_lvl = 0;
1795 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001796
1797 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1798
1799 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1800 return -EINVAL;
1801
1802 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1803
David Woodhouse9051aa02009-06-29 12:30:54 +01001804 if (sg)
1805 sg_res = 0;
1806 else {
1807 sg_res = nr_pages + 1;
1808 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1809 }
1810
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001811 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001812 uint64_t tmp;
1813
David Woodhousee1605492009-06-29 11:17:38 +01001814 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001815 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001816 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1817 sg->dma_length = sg->length;
1818 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001819 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001820 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001821
David Woodhousee1605492009-06-29 11:17:38 +01001822 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001823 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1824
1825 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001826 if (!pte)
1827 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001828 /* It is large page*/
Woodhouse, David16639bc2012-12-19 13:25:35 +00001829 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001830 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David16639bc2012-12-19 13:25:35 +00001831 /* Ensure that old small page tables are removed to make room
1832 for superpage, if they exist. */
1833 dma_pte_clear_range(domain, iov_pfn,
1834 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1835 dma_pte_free_pagetable(domain, iov_pfn,
1836 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1837 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001838 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David16639bc2012-12-19 13:25:35 +00001839 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001840
David Woodhousee1605492009-06-29 11:17:38 +01001841 }
1842 /* We don't need lock here, nobody else
1843 * touches the iova range
1844 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001845 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001846 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001847 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001848 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1849 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001850 if (dumps) {
1851 dumps--;
1852 debug_dma_dump_mappings(NULL);
1853 }
1854 WARN_ON(1);
1855 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001856
1857 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1858
1859 BUG_ON(nr_pages < lvl_pages);
1860 BUG_ON(sg_res < lvl_pages);
1861
1862 nr_pages -= lvl_pages;
1863 iov_pfn += lvl_pages;
1864 phys_pfn += lvl_pages;
1865 pteval += lvl_pages * VTD_PAGE_SIZE;
1866 sg_res -= lvl_pages;
1867
1868 /* If the next PTE would be the first in a new page, then we
1869 need to flush the cache on the entries we've just written.
1870 And then we'll need to recalculate 'pte', so clear it and
1871 let it get set again in the if (!pte) block above.
1872
1873 If we're done (!nr_pages) we need to flush the cache too.
1874
1875 Also if we've been setting superpages, we may need to
1876 recalculate 'pte' and switch back to smaller pages for the
1877 end of the mapping, if the trailing size is not enough to
1878 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001879 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001880 if (!nr_pages || first_pte_in_page(pte) ||
1881 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001882 domain_flush_cache(domain, first_pte,
1883 (void *)pte - (void *)first_pte);
1884 pte = NULL;
1885 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001886
1887 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001888 sg = sg_next(sg);
1889 }
1890 return 0;
1891}
1892
David Woodhouse9051aa02009-06-29 12:30:54 +01001893static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1894 struct scatterlist *sg, unsigned long nr_pages,
1895 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001896{
David Woodhouse9051aa02009-06-29 12:30:54 +01001897 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1898}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001899
David Woodhouse9051aa02009-06-29 12:30:54 +01001900static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1901 unsigned long phys_pfn, unsigned long nr_pages,
1902 int prot)
1903{
1904 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001905}
1906
Weidong Hanc7151a82008-12-08 22:51:37 +08001907static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001908{
Weidong Hanc7151a82008-12-08 22:51:37 +08001909 if (!iommu)
1910 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001911
1912 clear_context_table(iommu, bus, devfn);
1913 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001914 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001915 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001916}
1917
1918static void domain_remove_dev_info(struct dmar_domain *domain)
1919{
1920 struct device_domain_info *info;
1921 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001922 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001923
1924 spin_lock_irqsave(&device_domain_lock, flags);
1925 while (!list_empty(&domain->devices)) {
1926 info = list_entry(domain->devices.next,
1927 struct device_domain_info, link);
1928 list_del(&info->link);
1929 list_del(&info->global);
1930 if (info->dev)
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001931 info->dev->dev.archdata.iommu = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001932 spin_unlock_irqrestore(&device_domain_lock, flags);
1933
Yu Zhao93a23a72009-05-18 13:51:37 +08001934 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01001935 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001936 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001937 free_devinfo_mem(info);
1938
1939 spin_lock_irqsave(&device_domain_lock, flags);
1940 }
1941 spin_unlock_irqrestore(&device_domain_lock, flags);
1942}
1943
1944/*
1945 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001946 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001947 */
Kay, Allen M38717942008-09-09 18:37:29 +03001948static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001949find_domain(struct pci_dev *pdev)
1950{
1951 struct device_domain_info *info;
1952
1953 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001954 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001955 if (info)
1956 return info->domain;
1957 return NULL;
1958}
1959
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001960/* domain is initialized */
1961static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1962{
1963 struct dmar_domain *domain, *found = NULL;
1964 struct intel_iommu *iommu;
1965 struct dmar_drhd_unit *drhd;
1966 struct device_domain_info *info, *tmp;
1967 struct pci_dev *dev_tmp;
1968 unsigned long flags;
1969 int bus = 0, devfn = 0;
David Woodhouse276dbf92009-04-04 01:45:37 +01001970 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001971 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001972
1973 domain = find_domain(pdev);
1974 if (domain)
1975 return domain;
1976
David Woodhouse276dbf92009-04-04 01:45:37 +01001977 segment = pci_domain_nr(pdev->bus);
1978
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001979 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1980 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001981 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001982 bus = dev_tmp->subordinate->number;
1983 devfn = 0;
1984 } else {
1985 bus = dev_tmp->bus->number;
1986 devfn = dev_tmp->devfn;
1987 }
1988 spin_lock_irqsave(&device_domain_lock, flags);
1989 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001990 if (info->segment == segment &&
1991 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001992 found = info->domain;
1993 break;
1994 }
1995 }
1996 spin_unlock_irqrestore(&device_domain_lock, flags);
1997 /* pcie-pci bridge already has a domain, uses it */
1998 if (found) {
1999 domain = found;
2000 goto found_domain;
2001 }
2002 }
2003
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002004 domain = alloc_domain();
2005 if (!domain)
2006 goto error;
2007
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002008 /* Allocate new domain for the device */
2009 drhd = dmar_find_matched_drhd_unit(pdev);
2010 if (!drhd) {
2011 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2012 pci_name(pdev));
2013 return NULL;
2014 }
2015 iommu = drhd->iommu;
2016
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002017 ret = iommu_attach_domain(domain, iommu);
2018 if (ret) {
Alex Williamson2fe97232011-03-04 14:52:30 -07002019 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002020 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002021 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002022
2023 if (domain_init(domain, gaw)) {
2024 domain_exit(domain);
2025 goto error;
2026 }
2027
2028 /* register pcie-to-pci device */
2029 if (dev_tmp) {
2030 info = alloc_devinfo_mem();
2031 if (!info) {
2032 domain_exit(domain);
2033 goto error;
2034 }
David Woodhouse276dbf92009-04-04 01:45:37 +01002035 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002036 info->bus = bus;
2037 info->devfn = devfn;
2038 info->dev = NULL;
2039 info->domain = domain;
2040 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08002041 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002042
2043 /* pcie-to-pci bridge already has a domain, uses it */
2044 found = NULL;
2045 spin_lock_irqsave(&device_domain_lock, flags);
2046 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01002047 if (tmp->segment == segment &&
2048 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002049 found = tmp->domain;
2050 break;
2051 }
2052 }
2053 if (found) {
Jiri Slaby00dfff72010-06-14 17:17:32 +02002054 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002055 free_devinfo_mem(info);
2056 domain_exit(domain);
2057 domain = found;
2058 } else {
2059 list_add(&info->link, &domain->devices);
2060 list_add(&info->global, &device_domain_list);
Jiri Slaby00dfff72010-06-14 17:17:32 +02002061 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002062 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002063 }
2064
2065found_domain:
2066 info = alloc_devinfo_mem();
2067 if (!info)
2068 goto error;
David Woodhouse276dbf92009-04-04 01:45:37 +01002069 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002070 info->bus = pdev->bus->number;
2071 info->devfn = pdev->devfn;
2072 info->dev = pdev;
2073 info->domain = domain;
2074 spin_lock_irqsave(&device_domain_lock, flags);
2075 /* somebody is fast */
2076 found = find_domain(pdev);
2077 if (found != NULL) {
2078 spin_unlock_irqrestore(&device_domain_lock, flags);
2079 if (found != domain) {
2080 domain_exit(domain);
2081 domain = found;
2082 }
2083 free_devinfo_mem(info);
2084 return domain;
2085 }
2086 list_add(&info->link, &domain->devices);
2087 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002088 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002089 spin_unlock_irqrestore(&device_domain_lock, flags);
2090 return domain;
2091error:
2092 /* recheck it here, maybe others set it */
2093 return find_domain(pdev);
2094}
2095
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002096static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002097#define IDENTMAP_ALL 1
2098#define IDENTMAP_GFX 2
2099#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002100
David Woodhouseb2132032009-06-26 18:50:28 +01002101static int iommu_domain_identity_map(struct dmar_domain *domain,
2102 unsigned long long start,
2103 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002104{
David Woodhousec5395d52009-06-28 16:35:56 +01002105 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2106 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002107
David Woodhousec5395d52009-06-28 16:35:56 +01002108 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2109 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002110 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002111 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002112 }
2113
David Woodhousec5395d52009-06-28 16:35:56 +01002114 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2115 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002116 /*
2117 * RMRR range might have overlap with physical memory range,
2118 * clear it first
2119 */
David Woodhousec5395d52009-06-28 16:35:56 +01002120 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002121
David Woodhousec5395d52009-06-28 16:35:56 +01002122 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2123 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002124 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002125}
2126
2127static int iommu_prepare_identity_map(struct pci_dev *pdev,
2128 unsigned long long start,
2129 unsigned long long end)
2130{
2131 struct dmar_domain *domain;
2132 int ret;
2133
David Woodhousec7ab48d2009-06-26 19:10:36 +01002134 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002135 if (!domain)
2136 return -ENOMEM;
2137
David Woodhouse19943b02009-08-04 16:19:20 +01002138 /* For _hardware_ passthrough, don't bother. But for software
2139 passthrough, we do it anyway -- it may indicate a memory
2140 range which is reserved in E820, so which didn't get set
2141 up to start with in si_domain */
2142 if (domain == si_domain && hw_pass_through) {
2143 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2144 pci_name(pdev), start, end);
2145 return 0;
2146 }
2147
2148 printk(KERN_INFO
2149 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2150 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002151
David Woodhouse5595b522009-12-02 09:21:55 +00002152 if (end < start) {
2153 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2154 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2155 dmi_get_system_info(DMI_BIOS_VENDOR),
2156 dmi_get_system_info(DMI_BIOS_VERSION),
2157 dmi_get_system_info(DMI_PRODUCT_VERSION));
2158 ret = -EIO;
2159 goto error;
2160 }
2161
David Woodhouse2ff729f2009-08-26 14:25:41 +01002162 if (end >> agaw_to_width(domain->agaw)) {
2163 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2164 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2165 agaw_to_width(domain->agaw),
2166 dmi_get_system_info(DMI_BIOS_VENDOR),
2167 dmi_get_system_info(DMI_BIOS_VERSION),
2168 dmi_get_system_info(DMI_PRODUCT_VERSION));
2169 ret = -EIO;
2170 goto error;
2171 }
David Woodhouse19943b02009-08-04 16:19:20 +01002172
David Woodhouseb2132032009-06-26 18:50:28 +01002173 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002174 if (ret)
2175 goto error;
2176
2177 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002178 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002179 if (ret)
2180 goto error;
2181
2182 return 0;
2183
2184 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002185 domain_exit(domain);
2186 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002187}
2188
2189static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2190 struct pci_dev *pdev)
2191{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002192 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002193 return 0;
2194 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002195 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002196}
2197
Suresh Siddhad3f13812011-08-23 17:05:25 -07002198#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002199static inline void iommu_prepare_isa(void)
2200{
2201 struct pci_dev *pdev;
2202 int ret;
2203
2204 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2205 if (!pdev)
2206 return;
2207
David Woodhousec7ab48d2009-06-26 19:10:36 +01002208 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002209 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002210
2211 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002212 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2213 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002214
2215}
2216#else
2217static inline void iommu_prepare_isa(void)
2218{
2219 return;
2220}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002221#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002222
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002223static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002224
Matt Kraai071e1372009-08-23 22:30:22 -07002225static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002226{
2227 struct dmar_drhd_unit *drhd;
2228 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002229 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002230
2231 si_domain = alloc_domain();
2232 if (!si_domain)
2233 return -EFAULT;
2234
David Woodhousec7ab48d2009-06-26 19:10:36 +01002235 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002236
2237 for_each_active_iommu(iommu, drhd) {
2238 ret = iommu_attach_domain(si_domain, iommu);
2239 if (ret) {
2240 domain_exit(si_domain);
2241 return -EFAULT;
2242 }
2243 }
2244
2245 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2246 domain_exit(si_domain);
2247 return -EFAULT;
2248 }
2249
2250 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2251
David Woodhouse19943b02009-08-04 16:19:20 +01002252 if (hw)
2253 return 0;
2254
David Woodhousec7ab48d2009-06-26 19:10:36 +01002255 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002256 unsigned long start_pfn, end_pfn;
2257 int i;
2258
2259 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2260 ret = iommu_domain_identity_map(si_domain,
2261 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2262 if (ret)
2263 return ret;
2264 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002265 }
2266
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002267 return 0;
2268}
2269
2270static void domain_remove_one_dev_info(struct dmar_domain *domain,
2271 struct pci_dev *pdev);
2272static int identity_mapping(struct pci_dev *pdev)
2273{
2274 struct device_domain_info *info;
2275
2276 if (likely(!iommu_identity_mapping))
2277 return 0;
2278
Mike Traviscb452a42011-05-28 13:15:03 -05002279 info = pdev->dev.archdata.iommu;
2280 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2281 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002282
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002283 return 0;
2284}
2285
2286static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002287 struct pci_dev *pdev,
2288 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002289{
2290 struct device_domain_info *info;
2291 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002292 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002293
2294 info = alloc_devinfo_mem();
2295 if (!info)
2296 return -ENOMEM;
2297
2298 info->segment = pci_domain_nr(pdev->bus);
2299 info->bus = pdev->bus->number;
2300 info->devfn = pdev->devfn;
2301 info->dev = pdev;
2302 info->domain = domain;
2303
2304 spin_lock_irqsave(&device_domain_lock, flags);
2305 list_add(&info->link, &domain->devices);
2306 list_add(&info->global, &device_domain_list);
2307 pdev->dev.archdata.iommu = info;
2308 spin_unlock_irqrestore(&device_domain_lock, flags);
2309
David Woodhousee568e5e2012-05-25 17:42:54 +01002310 ret = domain_context_mapping(domain, pdev, translation);
2311 if (ret) {
2312 spin_lock_irqsave(&device_domain_lock, flags);
2313 list_del(&info->link);
2314 list_del(&info->global);
2315 pdev->dev.archdata.iommu = NULL;
2316 spin_unlock_irqrestore(&device_domain_lock, flags);
2317 free_devinfo_mem(info);
2318 return ret;
2319 }
2320
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002321 return 0;
2322}
2323
Tom Mingarelli5ad78132012-11-20 19:43:17 +00002324static bool device_has_rmrr(struct pci_dev *dev)
2325{
2326 struct dmar_rmrr_unit *rmrr;
2327 int i;
2328
2329 for_each_rmrr_units(rmrr) {
2330 for (i = 0; i < rmrr->devices_cnt; i++) {
2331 /*
2332 * Return TRUE if this RMRR contains the device that
2333 * is passed in.
2334 */
2335 if (rmrr->devices[i] == dev)
2336 return true;
2337 }
2338 }
2339 return false;
2340}
2341
David Woodhouse6941af22009-07-04 18:24:27 +01002342static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2343{
Tom Mingarelli5ad78132012-11-20 19:43:17 +00002344
2345 /*
2346 * We want to prevent any device associated with an RMRR from
2347 * getting placed into the SI Domain. This is done because
2348 * problems exist when devices are moved in and out of domains
2349 * and their respective RMRR info is lost. We exempt USB devices
2350 * from this process due to their usage of RMRRs that are known
2351 * to not be needed after BIOS hand-off to OS.
2352 */
2353 if (device_has_rmrr(pdev) &&
2354 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2355 return 0;
2356
David Woodhousee0fc7e02009-09-30 09:12:17 -07002357 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2358 return 1;
2359
2360 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2361 return 1;
2362
2363 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2364 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002365
David Woodhouse3dfc8132009-07-04 19:11:08 +01002366 /*
2367 * We want to start off with all devices in the 1:1 domain, and
2368 * take them out later if we find they can't access all of memory.
2369 *
2370 * However, we can't do this for PCI devices behind bridges,
2371 * because all PCI devices behind the same bridge will end up
2372 * with the same source-id on their transactions.
2373 *
2374 * Practically speaking, we can't change things around for these
2375 * devices at run-time, because we can't be sure there'll be no
2376 * DMA transactions in flight for any of their siblings.
2377 *
2378 * So PCI devices (unless they're on the root bus) as well as
2379 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2380 * the 1:1 domain, just in _case_ one of their siblings turns out
2381 * not to be able to map all of memory.
2382 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002383 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002384 if (!pci_is_root_bus(pdev->bus))
2385 return 0;
2386 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2387 return 0;
2388 } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
2389 return 0;
2390
2391 /*
2392 * At boot time, we don't yet know if devices will be 64-bit capable.
2393 * Assume that they will -- if they turn out not to be, then we can
2394 * take them out of the 1:1 domain later.
2395 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002396 if (!startup) {
2397 /*
2398 * If the device's dma_mask is less than the system's memory
2399 * size then this is not a candidate for identity mapping.
2400 */
2401 u64 dma_mask = pdev->dma_mask;
2402
2403 if (pdev->dev.coherent_dma_mask &&
2404 pdev->dev.coherent_dma_mask < dma_mask)
2405 dma_mask = pdev->dev.coherent_dma_mask;
2406
2407 return dma_mask >= dma_get_required_mask(&pdev->dev);
2408 }
David Woodhouse6941af22009-07-04 18:24:27 +01002409
2410 return 1;
2411}
2412
Matt Kraai071e1372009-08-23 22:30:22 -07002413static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002414{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002415 struct pci_dev *pdev = NULL;
2416 int ret;
2417
David Woodhouse19943b02009-08-04 16:19:20 +01002418 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002419 if (ret)
2420 return -EFAULT;
2421
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002422 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002423 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002424 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002425 hw ? CONTEXT_TT_PASS_THROUGH :
2426 CONTEXT_TT_MULTI_LEVEL);
2427 if (ret) {
2428 /* device not associated with an iommu */
2429 if (ret == -ENODEV)
2430 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002431 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002432 }
2433 pr_info("IOMMU: %s identity mapping for device %s\n",
2434 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002435 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002436 }
2437
2438 return 0;
2439}
2440
Joseph Cihulab7792602011-05-03 00:08:37 -07002441static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002442{
2443 struct dmar_drhd_unit *drhd;
2444 struct dmar_rmrr_unit *rmrr;
2445 struct pci_dev *pdev;
2446 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002447 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002448
2449 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002450 * for each drhd
2451 * allocate root
2452 * initialize and program root entry to not present
2453 * endfor
2454 */
2455 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002456 /*
2457 * lock not needed as this is only incremented in the single
2458 * threaded kernel __init code path all other access are read
2459 * only
2460 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002461 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2462 g_num_of_iommus++;
2463 continue;
2464 }
2465 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2466 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002467 }
2468
Weidong Hand9630fe2008-12-08 11:06:32 +08002469 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2470 GFP_KERNEL);
2471 if (!g_iommus) {
2472 printk(KERN_ERR "Allocating global iommu array failed\n");
2473 ret = -ENOMEM;
2474 goto error;
2475 }
2476
mark gross80b20dd2008-04-18 13:53:58 -07002477 deferred_flush = kzalloc(g_num_of_iommus *
2478 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2479 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002480 ret = -ENOMEM;
2481 goto error;
2482 }
2483
mark gross5e0d2a62008-03-04 15:22:08 -08002484 for_each_drhd_unit(drhd) {
2485 if (drhd->ignored)
2486 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002487
2488 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002489 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002490
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002491 ret = iommu_init_domains(iommu);
2492 if (ret)
2493 goto error;
2494
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002495 /*
2496 * TBD:
2497 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002498 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002499 */
2500 ret = iommu_alloc_root_entry(iommu);
2501 if (ret) {
2502 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2503 goto error;
2504 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002505 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002506 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002507 }
2508
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002509 /*
2510 * Start from the sane iommu hardware state.
2511 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002512 for_each_drhd_unit(drhd) {
2513 if (drhd->ignored)
2514 continue;
2515
2516 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002517
2518 /*
2519 * If the queued invalidation is already initialized by us
2520 * (for example, while enabling interrupt-remapping) then
2521 * we got the things already rolling from a sane state.
2522 */
2523 if (iommu->qi)
2524 continue;
2525
2526 /*
2527 * Clear any previous faults.
2528 */
2529 dmar_fault(-1, iommu);
2530 /*
2531 * Disable queued invalidation if supported and already enabled
2532 * before OS handover.
2533 */
2534 dmar_disable_qi(iommu);
2535 }
2536
2537 for_each_drhd_unit(drhd) {
2538 if (drhd->ignored)
2539 continue;
2540
2541 iommu = drhd->iommu;
2542
Youquan Songa77b67d2008-10-16 16:31:56 -07002543 if (dmar_enable_qi(iommu)) {
2544 /*
2545 * Queued Invalidate not enabled, use Register Based
2546 * Invalidate
2547 */
2548 iommu->flush.flush_context = __iommu_flush_context;
2549 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002550 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002551 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002552 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002553 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002554 } else {
2555 iommu->flush.flush_context = qi_flush_context;
2556 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002557 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002558 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002559 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002560 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002561 }
2562 }
2563
David Woodhouse19943b02009-08-04 16:19:20 +01002564 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002565 iommu_identity_mapping |= IDENTMAP_ALL;
2566
Suresh Siddhad3f13812011-08-23 17:05:25 -07002567#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002568 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002569#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002570
2571 check_tylersburg_isoch();
2572
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002573 /*
2574 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002575 * identity mappings for rmrr, gfx, and isa and may fall back to static
2576 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002577 */
David Woodhouse19943b02009-08-04 16:19:20 +01002578 if (iommu_identity_mapping) {
2579 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2580 if (ret) {
2581 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2582 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002583 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002584 }
David Woodhouse19943b02009-08-04 16:19:20 +01002585 /*
2586 * For each rmrr
2587 * for each dev attached to rmrr
2588 * do
2589 * locate drhd for dev, alloc domain for dev
2590 * allocate free domain
2591 * allocate page table entries for rmrr
2592 * if context not allocated for bus
2593 * allocate and init context
2594 * set present in root table for this bus
2595 * init context with domain, translation etc
2596 * endfor
2597 * endfor
2598 */
2599 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2600 for_each_rmrr_units(rmrr) {
2601 for (i = 0; i < rmrr->devices_cnt; i++) {
2602 pdev = rmrr->devices[i];
2603 /*
2604 * some BIOS lists non-exist devices in DMAR
2605 * table.
2606 */
2607 if (!pdev)
2608 continue;
2609 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2610 if (ret)
2611 printk(KERN_ERR
2612 "IOMMU: mapping reserved region failed\n");
2613 }
2614 }
2615
2616 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002617
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002618 /*
2619 * for each drhd
2620 * enable fault log
2621 * global invalidate context cache
2622 * global invalidate iotlb
2623 * enable translation
2624 */
2625 for_each_drhd_unit(drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002626 if (drhd->ignored) {
2627 /*
2628 * we always have to disable PMRs or DMA may fail on
2629 * this device
2630 */
2631 if (force_on)
2632 iommu_disable_protect_mem_regions(drhd->iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002633 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002634 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002635 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002636
2637 iommu_flush_write_buffer(iommu);
2638
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002639 ret = dmar_set_interrupt(iommu);
2640 if (ret)
2641 goto error;
2642
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002643 iommu_set_root_entry(iommu);
2644
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002645 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002646 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002647
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002648 ret = iommu_enable_translation(iommu);
2649 if (ret)
2650 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002651
2652 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002653 }
2654
2655 return 0;
2656error:
2657 for_each_drhd_unit(drhd) {
2658 if (drhd->ignored)
2659 continue;
2660 iommu = drhd->iommu;
2661 free_iommu(iommu);
2662 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002663 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002664 return ret;
2665}
2666
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002667/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002668static struct iova *intel_alloc_iova(struct device *dev,
2669 struct dmar_domain *domain,
2670 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002671{
2672 struct pci_dev *pdev = to_pci_dev(dev);
2673 struct iova *iova = NULL;
2674
David Woodhouse875764d2009-06-28 21:20:51 +01002675 /* Restrict dma_mask to the width that the iommu can handle */
2676 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2677
2678 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002679 /*
2680 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002681 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002682 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002683 */
David Woodhouse875764d2009-06-28 21:20:51 +01002684 iova = alloc_iova(&domain->iovad, nrpages,
2685 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2686 if (iova)
2687 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002688 }
David Woodhouse875764d2009-06-28 21:20:51 +01002689 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2690 if (unlikely(!iova)) {
2691 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2692 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002693 return NULL;
2694 }
2695
2696 return iova;
2697}
2698
David Woodhouse147202a2009-07-07 19:43:20 +01002699static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002700{
2701 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002702 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002703
2704 domain = get_domain_for_dev(pdev,
2705 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2706 if (!domain) {
2707 printk(KERN_ERR
2708 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002709 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002710 }
2711
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002712 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002713 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002714 ret = domain_context_mapping(domain, pdev,
2715 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002716 if (ret) {
2717 printk(KERN_ERR
2718 "Domain context map for %s failed",
2719 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002720 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002721 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002722 }
2723
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002724 return domain;
2725}
2726
David Woodhouse147202a2009-07-07 19:43:20 +01002727static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2728{
2729 struct device_domain_info *info;
2730
2731 /* No lock here, assumes no domain exit in normal case */
2732 info = dev->dev.archdata.iommu;
2733 if (likely(info))
2734 return info->domain;
2735
2736 return __get_valid_domain_for_dev(dev);
2737}
2738
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002739static int iommu_dummy(struct pci_dev *pdev)
2740{
2741 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2742}
2743
2744/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002745static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002746{
David Woodhouse73676832009-07-04 14:08:36 +01002747 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002748 int found;
2749
David Woodhouse73676832009-07-04 14:08:36 +01002750 if (unlikely(dev->bus != &pci_bus_type))
2751 return 1;
2752
2753 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002754 if (iommu_dummy(pdev))
2755 return 1;
2756
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002757 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002758 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002759
2760 found = identity_mapping(pdev);
2761 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002762 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002763 return 1;
2764 else {
2765 /*
2766 * 32 bit DMA is removed from si_domain and fall back
2767 * to non-identity mapping.
2768 */
2769 domain_remove_one_dev_info(si_domain, pdev);
2770 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2771 pci_name(pdev));
2772 return 0;
2773 }
2774 } else {
2775 /*
2776 * In case of a detached 64 bit DMA device from vm, the device
2777 * is put into si_domain for identity mapping.
2778 */
David Woodhouse6941af22009-07-04 18:24:27 +01002779 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002780 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002781 ret = domain_add_dev_info(si_domain, pdev,
2782 hw_pass_through ?
2783 CONTEXT_TT_PASS_THROUGH :
2784 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002785 if (!ret) {
2786 printk(KERN_INFO "64bit %s uses identity mapping\n",
2787 pci_name(pdev));
2788 return 1;
2789 }
2790 }
2791 }
2792
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002793 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002794}
2795
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002796static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2797 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002798{
2799 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002800 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002801 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002802 struct iova *iova;
2803 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002804 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002805 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002806 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002807
2808 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002809
David Woodhouse73676832009-07-04 14:08:36 +01002810 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002811 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002812
2813 domain = get_valid_domain_for_dev(pdev);
2814 if (!domain)
2815 return 0;
2816
Weidong Han8c11e792008-12-08 15:29:22 +08002817 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002818 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002819
Mike Travisc681d0b2011-05-28 13:15:05 -05002820 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002821 if (!iova)
2822 goto error;
2823
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002824 /*
2825 * Check if DMAR supports zero-length reads on write only
2826 * mappings..
2827 */
2828 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002829 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002830 prot |= DMA_PTE_READ;
2831 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2832 prot |= DMA_PTE_WRITE;
2833 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002834 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002835 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002836 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002837 * is not a big problem
2838 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002839 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002840 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002841 if (ret)
2842 goto error;
2843
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002844 /* it's a non-present to present mapping. Only flush if caching mode */
2845 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002846 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002847 else
Weidong Han8c11e792008-12-08 15:29:22 +08002848 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002849
David Woodhouse03d6a242009-06-28 15:33:46 +01002850 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2851 start_paddr += paddr & ~PAGE_MASK;
2852 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002853
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002854error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002855 if (iova)
2856 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002857 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002858 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002859 return 0;
2860}
2861
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002862static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2863 unsigned long offset, size_t size,
2864 enum dma_data_direction dir,
2865 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002866{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002867 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2868 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002869}
2870
mark gross5e0d2a62008-03-04 15:22:08 -08002871static void flush_unmaps(void)
2872{
mark gross80b20dd2008-04-18 13:53:58 -07002873 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002874
mark gross5e0d2a62008-03-04 15:22:08 -08002875 timer_on = 0;
2876
2877 /* just flush them all */
2878 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002879 struct intel_iommu *iommu = g_iommus[i];
2880 if (!iommu)
2881 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002882
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002883 if (!deferred_flush[i].next)
2884 continue;
2885
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002886 /* In caching mode, global flushes turn emulation expensive */
2887 if (!cap_caching_mode(iommu->cap))
2888 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002889 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002890 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002891 unsigned long mask;
2892 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002893 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002894
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002895 /* On real hardware multiple invalidations are expensive */
2896 if (cap_caching_mode(iommu->cap))
2897 iommu_flush_iotlb_psi(iommu, domain->id,
2898 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2899 else {
2900 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2901 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2902 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2903 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002904 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002905 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002906 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002907 }
2908
mark gross5e0d2a62008-03-04 15:22:08 -08002909 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002910}
2911
2912static void flush_unmaps_timeout(unsigned long data)
2913{
mark gross80b20dd2008-04-18 13:53:58 -07002914 unsigned long flags;
2915
2916 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002917 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002918 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002919}
2920
2921static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2922{
2923 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002924 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002925 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002926
2927 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002928 if (list_size == HIGH_WATER_MARK)
2929 flush_unmaps();
2930
Weidong Han8c11e792008-12-08 15:29:22 +08002931 iommu = domain_get_iommu(dom);
2932 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002933
mark gross80b20dd2008-04-18 13:53:58 -07002934 next = deferred_flush[iommu_id].next;
2935 deferred_flush[iommu_id].domain[next] = dom;
2936 deferred_flush[iommu_id].iova[next] = iova;
2937 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002938
2939 if (!timer_on) {
2940 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2941 timer_on = 1;
2942 }
2943 list_size++;
2944 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2945}
2946
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002947static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2948 size_t size, enum dma_data_direction dir,
2949 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002950{
2951 struct pci_dev *pdev = to_pci_dev(dev);
2952 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002953 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002954 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002955 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002956
David Woodhouse73676832009-07-04 14:08:36 +01002957 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002958 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002959
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002960 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002961 BUG_ON(!domain);
2962
Weidong Han8c11e792008-12-08 15:29:22 +08002963 iommu = domain_get_iommu(domain);
2964
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002965 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002966 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2967 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002968 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002969
David Woodhoused794dc92009-06-28 00:27:49 +01002970 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2971 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002972
David Woodhoused794dc92009-06-28 00:27:49 +01002973 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2974 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002975
2976 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002977 dma_pte_clear_range(domain, start_pfn, last_pfn);
2978
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002979 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002980 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2981
mark gross5e0d2a62008-03-04 15:22:08 -08002982 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002983 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002984 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002985 /* free iova */
2986 __free_iova(&domain->iovad, iova);
2987 } else {
2988 add_unmap(domain, iova);
2989 /*
2990 * queue up the release of the unmap to save the 1/6th of the
2991 * cpu used up by the iotlb flush operation...
2992 */
mark gross5e0d2a62008-03-04 15:22:08 -08002993 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002994}
2995
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002996static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02002997 dma_addr_t *dma_handle, gfp_t flags,
2998 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002999{
3000 void *vaddr;
3001 int order;
3002
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003003 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003004 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07003005
3006 if (!iommu_no_mapping(hwdev))
3007 flags &= ~(GFP_DMA | GFP_DMA32);
3008 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
3009 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
3010 flags |= GFP_DMA;
3011 else
3012 flags |= GFP_DMA32;
3013 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003014
3015 vaddr = (void *)__get_free_pages(flags, order);
3016 if (!vaddr)
3017 return NULL;
3018 memset(vaddr, 0, size);
3019
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003020 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
3021 DMA_BIDIRECTIONAL,
3022 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003023 if (*dma_handle)
3024 return vaddr;
3025 free_pages((unsigned long)vaddr, order);
3026 return NULL;
3027}
3028
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003029static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003030 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003031{
3032 int order;
3033
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003034 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003035 order = get_order(size);
3036
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003037 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003038 free_pages((unsigned long)vaddr, order);
3039}
3040
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003041static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3042 int nelems, enum dma_data_direction dir,
3043 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003044{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003045 struct pci_dev *pdev = to_pci_dev(hwdev);
3046 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003047 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003048 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003049 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003050
David Woodhouse73676832009-07-04 14:08:36 +01003051 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003052 return;
3053
3054 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003055 BUG_ON(!domain);
3056
3057 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003058
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003059 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003060 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3061 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003062 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003063
David Woodhoused794dc92009-06-28 00:27:49 +01003064 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3065 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003066
3067 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003068 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003069
David Woodhoused794dc92009-06-28 00:27:49 +01003070 /* free page tables */
3071 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3072
David Woodhouseacea0012009-07-14 01:55:11 +01003073 if (intel_iommu_strict) {
3074 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003075 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003076 /* free iova */
3077 __free_iova(&domain->iovad, iova);
3078 } else {
3079 add_unmap(domain, iova);
3080 /*
3081 * queue up the release of the unmap to save the 1/6th of the
3082 * cpu used up by the iotlb flush operation...
3083 */
3084 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003085}
3086
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003087static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003088 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003089{
3090 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003091 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003092
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003093 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003094 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003095 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003096 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003097 }
3098 return nelems;
3099}
3100
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003101static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3102 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003103{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003104 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003105 struct pci_dev *pdev = to_pci_dev(hwdev);
3106 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003107 size_t size = 0;
3108 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003109 struct iova *iova = NULL;
3110 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003111 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003112 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003113 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003114
3115 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003116 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003117 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003118
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003119 domain = get_valid_domain_for_dev(pdev);
3120 if (!domain)
3121 return 0;
3122
Weidong Han8c11e792008-12-08 15:29:22 +08003123 iommu = domain_get_iommu(domain);
3124
David Woodhouseb536d242009-06-28 14:49:31 +01003125 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003126 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003127
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003128 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3129 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003130 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003131 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003132 return 0;
3133 }
3134
3135 /*
3136 * Check if DMAR supports zero-length reads on write only
3137 * mappings..
3138 */
3139 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003140 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003141 prot |= DMA_PTE_READ;
3142 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3143 prot |= DMA_PTE_WRITE;
3144
David Woodhouseb536d242009-06-28 14:49:31 +01003145 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003146
Fenghua Yuf5329592009-08-04 15:09:37 -07003147 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003148 if (unlikely(ret)) {
3149 /* clear the page */
3150 dma_pte_clear_range(domain, start_vpfn,
3151 start_vpfn + size - 1);
3152 /* free page tables */
3153 dma_pte_free_pagetable(domain, start_vpfn,
3154 start_vpfn + size - 1);
3155 /* free iova */
3156 __free_iova(&domain->iovad, iova);
3157 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003158 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003159
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003160 /* it's a non-present to present mapping. Only flush if caching mode */
3161 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003162 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003163 else
Weidong Han8c11e792008-12-08 15:29:22 +08003164 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003165
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003166 return nelems;
3167}
3168
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003169static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3170{
3171 return !dma_addr;
3172}
3173
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003174struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003175 .alloc = intel_alloc_coherent,
3176 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003177 .map_sg = intel_map_sg,
3178 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003179 .map_page = intel_map_page,
3180 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003181 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003182};
3183
3184static inline int iommu_domain_cache_init(void)
3185{
3186 int ret = 0;
3187
3188 iommu_domain_cache = kmem_cache_create("iommu_domain",
3189 sizeof(struct dmar_domain),
3190 0,
3191 SLAB_HWCACHE_ALIGN,
3192
3193 NULL);
3194 if (!iommu_domain_cache) {
3195 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3196 ret = -ENOMEM;
3197 }
3198
3199 return ret;
3200}
3201
3202static inline int iommu_devinfo_cache_init(void)
3203{
3204 int ret = 0;
3205
3206 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3207 sizeof(struct device_domain_info),
3208 0,
3209 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003210 NULL);
3211 if (!iommu_devinfo_cache) {
3212 printk(KERN_ERR "Couldn't create devinfo cache\n");
3213 ret = -ENOMEM;
3214 }
3215
3216 return ret;
3217}
3218
3219static inline int iommu_iova_cache_init(void)
3220{
3221 int ret = 0;
3222
3223 iommu_iova_cache = kmem_cache_create("iommu_iova",
3224 sizeof(struct iova),
3225 0,
3226 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003227 NULL);
3228 if (!iommu_iova_cache) {
3229 printk(KERN_ERR "Couldn't create iova cache\n");
3230 ret = -ENOMEM;
3231 }
3232
3233 return ret;
3234}
3235
3236static int __init iommu_init_mempool(void)
3237{
3238 int ret;
3239 ret = iommu_iova_cache_init();
3240 if (ret)
3241 return ret;
3242
3243 ret = iommu_domain_cache_init();
3244 if (ret)
3245 goto domain_error;
3246
3247 ret = iommu_devinfo_cache_init();
3248 if (!ret)
3249 return ret;
3250
3251 kmem_cache_destroy(iommu_domain_cache);
3252domain_error:
3253 kmem_cache_destroy(iommu_iova_cache);
3254
3255 return -ENOMEM;
3256}
3257
3258static void __init iommu_exit_mempool(void)
3259{
3260 kmem_cache_destroy(iommu_devinfo_cache);
3261 kmem_cache_destroy(iommu_domain_cache);
3262 kmem_cache_destroy(iommu_iova_cache);
3263
3264}
3265
Dan Williams556ab452010-07-23 15:47:56 -07003266static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3267{
3268 struct dmar_drhd_unit *drhd;
3269 u32 vtbar;
3270 int rc;
3271
3272 /* We know that this device on this chipset has its own IOMMU.
3273 * If we find it under a different IOMMU, then the BIOS is lying
3274 * to us. Hope that the IOMMU for this device is actually
3275 * disabled, and it needs no translation...
3276 */
3277 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3278 if (rc) {
3279 /* "can't" happen */
3280 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3281 return;
3282 }
3283 vtbar &= 0xffff0000;
3284
3285 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3286 drhd = dmar_find_matched_drhd_unit(pdev);
3287 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3288 TAINT_FIRMWARE_WORKAROUND,
3289 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3290 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3291}
3292DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3293
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003294static void __init init_no_remapping_devices(void)
3295{
3296 struct dmar_drhd_unit *drhd;
3297
3298 for_each_drhd_unit(drhd) {
3299 if (!drhd->include_all) {
3300 int i;
3301 for (i = 0; i < drhd->devices_cnt; i++)
3302 if (drhd->devices[i] != NULL)
3303 break;
3304 /* ignore DMAR unit if no pci devices exist */
3305 if (i == drhd->devices_cnt)
3306 drhd->ignored = 1;
3307 }
3308 }
3309
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003310 for_each_drhd_unit(drhd) {
3311 int i;
3312 if (drhd->ignored || drhd->include_all)
3313 continue;
3314
3315 for (i = 0; i < drhd->devices_cnt; i++)
3316 if (drhd->devices[i] &&
David Woodhousec0771df2011-10-14 20:59:46 +01003317 !IS_GFX_DEVICE(drhd->devices[i]))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003318 break;
3319
3320 if (i < drhd->devices_cnt)
3321 continue;
3322
David Woodhousec0771df2011-10-14 20:59:46 +01003323 /* This IOMMU has *only* gfx devices. Either bypass it or
3324 set the gfx_mapped flag, as appropriate */
3325 if (dmar_map_gfx) {
3326 intel_iommu_gfx_mapped = 1;
3327 } else {
3328 drhd->ignored = 1;
3329 for (i = 0; i < drhd->devices_cnt; i++) {
3330 if (!drhd->devices[i])
3331 continue;
3332 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3333 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003334 }
3335 }
3336}
3337
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003338#ifdef CONFIG_SUSPEND
3339static int init_iommu_hw(void)
3340{
3341 struct dmar_drhd_unit *drhd;
3342 struct intel_iommu *iommu = NULL;
3343
3344 for_each_active_iommu(iommu, drhd)
3345 if (iommu->qi)
3346 dmar_reenable_qi(iommu);
3347
Joseph Cihulab7792602011-05-03 00:08:37 -07003348 for_each_iommu(iommu, drhd) {
3349 if (drhd->ignored) {
3350 /*
3351 * we always have to disable PMRs or DMA may fail on
3352 * this device
3353 */
3354 if (force_on)
3355 iommu_disable_protect_mem_regions(iommu);
3356 continue;
3357 }
3358
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003359 iommu_flush_write_buffer(iommu);
3360
3361 iommu_set_root_entry(iommu);
3362
3363 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003364 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003365 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003366 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003367 if (iommu_enable_translation(iommu))
3368 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003369 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003370 }
3371
3372 return 0;
3373}
3374
3375static void iommu_flush_all(void)
3376{
3377 struct dmar_drhd_unit *drhd;
3378 struct intel_iommu *iommu;
3379
3380 for_each_active_iommu(iommu, drhd) {
3381 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003382 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003383 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003384 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003385 }
3386}
3387
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003388static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003389{
3390 struct dmar_drhd_unit *drhd;
3391 struct intel_iommu *iommu = NULL;
3392 unsigned long flag;
3393
3394 for_each_active_iommu(iommu, drhd) {
3395 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3396 GFP_ATOMIC);
3397 if (!iommu->iommu_state)
3398 goto nomem;
3399 }
3400
3401 iommu_flush_all();
3402
3403 for_each_active_iommu(iommu, drhd) {
3404 iommu_disable_translation(iommu);
3405
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003406 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003407
3408 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3409 readl(iommu->reg + DMAR_FECTL_REG);
3410 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3411 readl(iommu->reg + DMAR_FEDATA_REG);
3412 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3413 readl(iommu->reg + DMAR_FEADDR_REG);
3414 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3415 readl(iommu->reg + DMAR_FEUADDR_REG);
3416
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003417 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003418 }
3419 return 0;
3420
3421nomem:
3422 for_each_active_iommu(iommu, drhd)
3423 kfree(iommu->iommu_state);
3424
3425 return -ENOMEM;
3426}
3427
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003428static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003429{
3430 struct dmar_drhd_unit *drhd;
3431 struct intel_iommu *iommu = NULL;
3432 unsigned long flag;
3433
3434 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003435 if (force_on)
3436 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3437 else
3438 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003439 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003440 }
3441
3442 for_each_active_iommu(iommu, drhd) {
3443
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003444 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003445
3446 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3447 iommu->reg + DMAR_FECTL_REG);
3448 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3449 iommu->reg + DMAR_FEDATA_REG);
3450 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3451 iommu->reg + DMAR_FEADDR_REG);
3452 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3453 iommu->reg + DMAR_FEUADDR_REG);
3454
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003455 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003456 }
3457
3458 for_each_active_iommu(iommu, drhd)
3459 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003460}
3461
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003462static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003463 .resume = iommu_resume,
3464 .suspend = iommu_suspend,
3465};
3466
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003467static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003468{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003469 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003470}
3471
3472#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003473static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003474#endif /* CONFIG_PM */
3475
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003476LIST_HEAD(dmar_rmrr_units);
3477
3478static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3479{
3480 list_add(&rmrr->list, &dmar_rmrr_units);
3481}
3482
3483
3484int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3485{
3486 struct acpi_dmar_reserved_memory *rmrr;
3487 struct dmar_rmrr_unit *rmrru;
3488
3489 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3490 if (!rmrru)
3491 return -ENOMEM;
3492
3493 rmrru->hdr = header;
3494 rmrr = (struct acpi_dmar_reserved_memory *)header;
3495 rmrru->base_address = rmrr->base_address;
3496 rmrru->end_address = rmrr->end_address;
3497
3498 dmar_register_rmrr_unit(rmrru);
3499 return 0;
3500}
3501
3502static int __init
3503rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3504{
3505 struct acpi_dmar_reserved_memory *rmrr;
3506 int ret;
3507
3508 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
3509 ret = dmar_parse_dev_scope((void *)(rmrr + 1),
3510 ((void *)rmrr) + rmrr->header.length,
3511 &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
3512
3513 if (ret || (rmrru->devices_cnt == 0)) {
3514 list_del(&rmrru->list);
3515 kfree(rmrru);
3516 }
3517 return ret;
3518}
3519
3520static LIST_HEAD(dmar_atsr_units);
3521
3522int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3523{
3524 struct acpi_dmar_atsr *atsr;
3525 struct dmar_atsr_unit *atsru;
3526
3527 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3528 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3529 if (!atsru)
3530 return -ENOMEM;
3531
3532 atsru->hdr = hdr;
3533 atsru->include_all = atsr->flags & 0x1;
3534
3535 list_add(&atsru->list, &dmar_atsr_units);
3536
3537 return 0;
3538}
3539
3540static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3541{
3542 int rc;
3543 struct acpi_dmar_atsr *atsr;
3544
3545 if (atsru->include_all)
3546 return 0;
3547
3548 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3549 rc = dmar_parse_dev_scope((void *)(atsr + 1),
3550 (void *)atsr + atsr->header.length,
3551 &atsru->devices_cnt, &atsru->devices,
3552 atsr->segment);
3553 if (rc || !atsru->devices_cnt) {
3554 list_del(&atsru->list);
3555 kfree(atsru);
3556 }
3557
3558 return rc;
3559}
3560
3561int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3562{
3563 int i;
3564 struct pci_bus *bus;
3565 struct acpi_dmar_atsr *atsr;
3566 struct dmar_atsr_unit *atsru;
3567
3568 dev = pci_physfn(dev);
3569
3570 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3571 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3572 if (atsr->segment == pci_domain_nr(dev->bus))
3573 goto found;
3574 }
3575
3576 return 0;
3577
3578found:
3579 for (bus = dev->bus; bus; bus = bus->parent) {
3580 struct pci_dev *bridge = bus->self;
3581
3582 if (!bridge || !pci_is_pcie(bridge) ||
3583 bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
3584 return 0;
3585
3586 if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
3587 for (i = 0; i < atsru->devices_cnt; i++)
3588 if (atsru->devices[i] == bridge)
3589 return 1;
3590 break;
3591 }
3592 }
3593
3594 if (atsru->include_all)
3595 return 1;
3596
3597 return 0;
3598}
3599
Sergey Senozhatskyc8f369a2011-10-26 18:45:39 +03003600int __init dmar_parse_rmrr_atsr_dev(void)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003601{
3602 struct dmar_rmrr_unit *rmrr, *rmrr_n;
3603 struct dmar_atsr_unit *atsr, *atsr_n;
3604 int ret = 0;
3605
3606 list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
3607 ret = rmrr_parse_dev(rmrr);
3608 if (ret)
3609 return ret;
3610 }
3611
3612 list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
3613 ret = atsr_parse_dev(atsr);
3614 if (ret)
3615 return ret;
3616 }
3617
3618 return ret;
3619}
3620
Fenghua Yu99dcade2009-11-11 07:23:06 -08003621/*
3622 * Here we only respond to action of unbound device from driver.
3623 *
3624 * Added device is not attached to its DMAR domain here yet. That will happen
3625 * when mapping the device to iova.
3626 */
3627static int device_notifier(struct notifier_block *nb,
3628 unsigned long action, void *data)
3629{
3630 struct device *dev = data;
3631 struct pci_dev *pdev = to_pci_dev(dev);
3632 struct dmar_domain *domain;
3633
David Woodhouse44cd6132009-12-02 10:18:30 +00003634 if (iommu_no_mapping(dev))
3635 return 0;
3636
Fenghua Yu99dcade2009-11-11 07:23:06 -08003637 domain = find_domain(pdev);
3638 if (!domain)
3639 return 0;
3640
Alex Williamsona97590e2011-03-04 14:52:16 -07003641 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
Fenghua Yu99dcade2009-11-11 07:23:06 -08003642 domain_remove_one_dev_info(domain, pdev);
3643
Alex Williamsona97590e2011-03-04 14:52:16 -07003644 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3645 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3646 list_empty(&domain->devices))
3647 domain_exit(domain);
3648 }
3649
Fenghua Yu99dcade2009-11-11 07:23:06 -08003650 return 0;
3651}
3652
3653static struct notifier_block device_nb = {
3654 .notifier_call = device_notifier,
3655};
3656
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003657int __init intel_iommu_init(void)
3658{
3659 int ret = 0;
3660
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003661 /* VT-d is required for a TXT/tboot launch, so enforce that */
3662 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003663
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003664 if (dmar_table_init()) {
3665 if (force_on)
3666 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003667 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003668 }
3669
Suresh Siddhac2c72862011-08-23 17:05:19 -07003670 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003671 if (force_on)
3672 panic("tboot: Failed to initialize DMAR device scope\n");
3673 return -ENODEV;
3674 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003675
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003676 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003677 return -ENODEV;
3678
Joseph Cihula51a63e62011-03-21 11:04:24 -07003679 if (iommu_init_mempool()) {
3680 if (force_on)
3681 panic("tboot: Failed to initialize iommu memory\n");
3682 return -ENODEV;
3683 }
3684
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003685 if (list_empty(&dmar_rmrr_units))
3686 printk(KERN_INFO "DMAR: No RMRR found\n");
3687
3688 if (list_empty(&dmar_atsr_units))
3689 printk(KERN_INFO "DMAR: No ATSR found\n");
3690
Joseph Cihula51a63e62011-03-21 11:04:24 -07003691 if (dmar_init_reserved_ranges()) {
3692 if (force_on)
3693 panic("tboot: Failed to reserve iommu ranges\n");
3694 return -ENODEV;
3695 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003696
3697 init_no_remapping_devices();
3698
Joseph Cihulab7792602011-05-03 00:08:37 -07003699 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003700 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003701 if (force_on)
3702 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003703 printk(KERN_ERR "IOMMU: dmar init failed\n");
3704 put_iova_domain(&reserved_iova_list);
3705 iommu_exit_mempool();
3706 return ret;
3707 }
3708 printk(KERN_INFO
3709 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3710
mark gross5e0d2a62008-03-04 15:22:08 -08003711 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003712#ifdef CONFIG_SWIOTLB
3713 swiotlb = 0;
3714#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003715 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003716
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003717 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003718
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003719 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003720
Fenghua Yu99dcade2009-11-11 07:23:06 -08003721 bus_register_notifier(&pci_bus_type, &device_nb);
3722
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003723 intel_iommu_enabled = 1;
3724
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003725 return 0;
3726}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003727
Han, Weidong3199aa62009-02-26 17:31:12 +08003728static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3729 struct pci_dev *pdev)
3730{
3731 struct pci_dev *tmp, *parent;
3732
3733 if (!iommu || !pdev)
3734 return;
3735
3736 /* dependent device detach */
3737 tmp = pci_find_upstream_pcie_bridge(pdev);
3738 /* Secondary interface's bus number and devfn 0 */
3739 if (tmp) {
3740 parent = pdev->bus->self;
3741 while (parent != tmp) {
3742 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01003743 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003744 parent = parent->bus->self;
3745 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003746 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003747 iommu_detach_dev(iommu,
3748 tmp->subordinate->number, 0);
3749 else /* this is a legacy PCI bridge */
David Woodhouse276dbf92009-04-04 01:45:37 +01003750 iommu_detach_dev(iommu, tmp->bus->number,
3751 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003752 }
3753}
3754
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003755static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003756 struct pci_dev *pdev)
3757{
3758 struct device_domain_info *info;
3759 struct intel_iommu *iommu;
3760 unsigned long flags;
3761 int found = 0;
3762 struct list_head *entry, *tmp;
3763
David Woodhouse276dbf92009-04-04 01:45:37 +01003764 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3765 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003766 if (!iommu)
3767 return;
3768
3769 spin_lock_irqsave(&device_domain_lock, flags);
3770 list_for_each_safe(entry, tmp, &domain->devices) {
3771 info = list_entry(entry, struct device_domain_info, link);
Mike Habeck8519dc42011-05-28 13:15:07 -05003772 if (info->segment == pci_domain_nr(pdev->bus) &&
3773 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003774 info->devfn == pdev->devfn) {
3775 list_del(&info->link);
3776 list_del(&info->global);
3777 if (info->dev)
3778 info->dev->dev.archdata.iommu = NULL;
3779 spin_unlock_irqrestore(&device_domain_lock, flags);
3780
Yu Zhao93a23a72009-05-18 13:51:37 +08003781 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003782 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003783 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003784 free_devinfo_mem(info);
3785
3786 spin_lock_irqsave(&device_domain_lock, flags);
3787
3788 if (found)
3789 break;
3790 else
3791 continue;
3792 }
3793
3794 /* if there is no other devices under the same iommu
3795 * owned by this domain, clear this iommu in iommu_bmp
3796 * update iommu count and coherency
3797 */
David Woodhouse276dbf92009-04-04 01:45:37 +01003798 if (iommu == device_to_iommu(info->segment, info->bus,
3799 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003800 found = 1;
3801 }
3802
Roland Dreier3e7abe22011-07-20 06:22:21 -07003803 spin_unlock_irqrestore(&device_domain_lock, flags);
3804
Weidong Hanc7151a82008-12-08 22:51:37 +08003805 if (found == 0) {
3806 unsigned long tmp_flags;
3807 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003808 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003809 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003810 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003811 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003812
Alex Williamson9b4554b2011-05-24 12:19:04 -04003813 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3814 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3815 spin_lock_irqsave(&iommu->lock, tmp_flags);
3816 clear_bit(domain->id, iommu->domain_ids);
3817 iommu->domains[domain->id] = NULL;
3818 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3819 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003820 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003821}
3822
3823static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3824{
3825 struct device_domain_info *info;
3826 struct intel_iommu *iommu;
3827 unsigned long flags1, flags2;
3828
3829 spin_lock_irqsave(&device_domain_lock, flags1);
3830 while (!list_empty(&domain->devices)) {
3831 info = list_entry(domain->devices.next,
3832 struct device_domain_info, link);
3833 list_del(&info->link);
3834 list_del(&info->global);
3835 if (info->dev)
3836 info->dev->dev.archdata.iommu = NULL;
3837
3838 spin_unlock_irqrestore(&device_domain_lock, flags1);
3839
Yu Zhao93a23a72009-05-18 13:51:37 +08003840 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01003841 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003842 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003843 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003844
3845 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003846 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003847 */
3848 spin_lock_irqsave(&domain->iommu_lock, flags2);
3849 if (test_and_clear_bit(iommu->seq_id,
Mike Travis1b198bb2012-03-05 15:05:16 -08003850 domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08003851 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003852 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003853 }
3854 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3855
3856 free_devinfo_mem(info);
3857 spin_lock_irqsave(&device_domain_lock, flags1);
3858 }
3859 spin_unlock_irqrestore(&device_domain_lock, flags1);
3860}
3861
Weidong Han5e98c4b2008-12-08 23:03:27 +08003862/* domain id for virtual machine, it won't be set in context */
3863static unsigned long vm_domid;
3864
3865static struct dmar_domain *iommu_alloc_vm_domain(void)
3866{
3867 struct dmar_domain *domain;
3868
3869 domain = alloc_domain_mem();
3870 if (!domain)
3871 return NULL;
3872
3873 domain->id = vm_domid++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003874 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08003875 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003876 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3877
3878 return domain;
3879}
3880
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003881static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003882{
3883 int adjust_width;
3884
3885 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003886 spin_lock_init(&domain->iommu_lock);
3887
3888 domain_reserve_special_ranges(domain);
3889
3890 /* calculate AGAW */
3891 domain->gaw = guest_width;
3892 adjust_width = guestwidth_to_adjustwidth(guest_width);
3893 domain->agaw = width_to_agaw(adjust_width);
3894
3895 INIT_LIST_HEAD(&domain->devices);
3896
3897 domain->iommu_count = 0;
3898 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003899 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003900 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003901 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003902 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003903
3904 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003905 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003906 if (!domain->pgd)
3907 return -ENOMEM;
3908 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3909 return 0;
3910}
3911
3912static void iommu_free_vm_domain(struct dmar_domain *domain)
3913{
3914 unsigned long flags;
3915 struct dmar_drhd_unit *drhd;
3916 struct intel_iommu *iommu;
3917 unsigned long i;
3918 unsigned long ndomains;
3919
3920 for_each_drhd_unit(drhd) {
3921 if (drhd->ignored)
3922 continue;
3923 iommu = drhd->iommu;
3924
3925 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08003926 for_each_set_bit(i, iommu->domain_ids, ndomains) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003927 if (iommu->domains[i] == domain) {
3928 spin_lock_irqsave(&iommu->lock, flags);
3929 clear_bit(i, iommu->domain_ids);
3930 iommu->domains[i] = NULL;
3931 spin_unlock_irqrestore(&iommu->lock, flags);
3932 break;
3933 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08003934 }
3935 }
3936}
3937
3938static void vm_domain_exit(struct dmar_domain *domain)
3939{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003940 /* Domain 0 is reserved, so dont process it */
3941 if (!domain)
3942 return;
3943
3944 vm_domain_remove_all_dev_info(domain);
3945 /* destroy iovas */
3946 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003947
3948 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003949 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003950
3951 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003952 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003953
3954 iommu_free_vm_domain(domain);
3955 free_domain_mem(domain);
3956}
3957
Joerg Roedel5d450802008-12-03 14:52:32 +01003958static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003959{
Joerg Roedel5d450802008-12-03 14:52:32 +01003960 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003961
Joerg Roedel5d450802008-12-03 14:52:32 +01003962 dmar_domain = iommu_alloc_vm_domain();
3963 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003964 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003965 "intel_iommu_domain_init: dmar_domain == NULL\n");
3966 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003967 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003968 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003969 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003970 "intel_iommu_domain_init() failed\n");
3971 vm_domain_exit(dmar_domain);
3972 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003973 }
Allen Kay8140a952011-10-14 12:32:17 -07003974 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003975 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003976
Joerg Roedel5d450802008-12-03 14:52:32 +01003977 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003978}
Kay, Allen M38717942008-09-09 18:37:29 +03003979
Joerg Roedel5d450802008-12-03 14:52:32 +01003980static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003981{
Joerg Roedel5d450802008-12-03 14:52:32 +01003982 struct dmar_domain *dmar_domain = domain->priv;
3983
3984 domain->priv = NULL;
3985 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003986}
Kay, Allen M38717942008-09-09 18:37:29 +03003987
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003988static int intel_iommu_attach_device(struct iommu_domain *domain,
3989 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003990{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003991 struct dmar_domain *dmar_domain = domain->priv;
3992 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003993 struct intel_iommu *iommu;
3994 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03003995
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003996 /* normally pdev is not mapped */
3997 if (unlikely(domain_context_mapped(pdev))) {
3998 struct dmar_domain *old_domain;
3999
4000 old_domain = find_domain(pdev);
4001 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004002 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
4003 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
4004 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004005 else
4006 domain_remove_dev_info(old_domain);
4007 }
4008 }
4009
David Woodhouse276dbf92009-04-04 01:45:37 +01004010 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
4011 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004012 if (!iommu)
4013 return -ENODEV;
4014
4015 /* check if this iommu agaw is sufficient for max mapped address */
4016 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01004017 if (addr_width > cap_mgaw(iommu->cap))
4018 addr_width = cap_mgaw(iommu->cap);
4019
4020 if (dmar_domain->max_addr > (1LL << addr_width)) {
4021 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004022 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01004023 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004024 return -EFAULT;
4025 }
Tom Lyona99c47a2010-05-17 08:20:45 +01004026 dmar_domain->gaw = addr_width;
4027
4028 /*
4029 * Knock out extra levels of page tables if necessary
4030 */
4031 while (iommu->agaw < dmar_domain->agaw) {
4032 struct dma_pte *pte;
4033
4034 pte = dmar_domain->pgd;
4035 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08004036 dmar_domain->pgd = (struct dma_pte *)
4037 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01004038 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01004039 }
4040 dmar_domain->agaw--;
4041 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004042
David Woodhouse5fe60f42009-08-09 10:53:41 +01004043 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004044}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004045
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004046static void intel_iommu_detach_device(struct iommu_domain *domain,
4047 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004048{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004049 struct dmar_domain *dmar_domain = domain->priv;
4050 struct pci_dev *pdev = to_pci_dev(dev);
4051
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004052 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03004053}
Kay, Allen M38717942008-09-09 18:37:29 +03004054
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004055static int intel_iommu_map(struct iommu_domain *domain,
4056 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004057 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03004058{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004059 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004060 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004061 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004062 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004063
Joerg Roedeldde57a22008-12-03 15:04:09 +01004064 if (iommu_prot & IOMMU_READ)
4065 prot |= DMA_PTE_READ;
4066 if (iommu_prot & IOMMU_WRITE)
4067 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08004068 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4069 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004070
David Woodhouse163cc522009-06-28 00:51:17 +01004071 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004072 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004073 u64 end;
4074
4075 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01004076 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004077 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004078 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004079 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004080 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004081 return -EFAULT;
4082 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004083 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004084 }
David Woodhousead051222009-06-28 14:22:28 +01004085 /* Round up size to next multiple of PAGE_SIZE, if it and
4086 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004087 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004088 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4089 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004090 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004091}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004092
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004093static size_t intel_iommu_unmap(struct iommu_domain *domain,
4094 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004095{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004096 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07004097 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01004098
Allen Kay292827c2011-10-14 12:31:54 -07004099 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004100 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004101
David Woodhouse163cc522009-06-28 00:51:17 +01004102 if (dmar_domain->max_addr == iova + size)
4103 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004104
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004105 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004106}
Kay, Allen M38717942008-09-09 18:37:29 +03004107
Joerg Roedeld14d6572008-12-03 15:06:57 +01004108static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
4109 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004110{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004111 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004112 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004113 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004114
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004115 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004116 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004117 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004118
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004119 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004120}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004121
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004122static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4123 unsigned long cap)
4124{
4125 struct dmar_domain *dmar_domain = domain->priv;
4126
4127 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4128 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004129 if (cap == IOMMU_CAP_INTR_REMAP)
4130 return intr_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004131
4132 return 0;
4133}
4134
Alex Williamson70ae6f02011-10-21 15:56:11 -04004135/*
4136 * Group numbers are arbitrary. Device with the same group number
4137 * indicate the iommu cannot differentiate between them. To avoid
4138 * tracking used groups we just use the seg|bus|devfn of the lowest
4139 * level we're able to differentiate devices
4140 */
4141static int intel_iommu_device_group(struct device *dev, unsigned int *groupid)
4142{
4143 struct pci_dev *pdev = to_pci_dev(dev);
4144 struct pci_dev *bridge;
4145 union {
4146 struct {
4147 u8 devfn;
4148 u8 bus;
4149 u16 segment;
4150 } pci;
4151 u32 group;
4152 } id;
4153
4154 if (iommu_no_mapping(dev))
4155 return -ENODEV;
4156
4157 id.pci.segment = pci_domain_nr(pdev->bus);
4158 id.pci.bus = pdev->bus->number;
4159 id.pci.devfn = pdev->devfn;
4160
4161 if (!device_to_iommu(id.pci.segment, id.pci.bus, id.pci.devfn))
4162 return -ENODEV;
4163
4164 bridge = pci_find_upstream_pcie_bridge(pdev);
4165 if (bridge) {
4166 if (pci_is_pcie(bridge)) {
4167 id.pci.bus = bridge->subordinate->number;
4168 id.pci.devfn = 0;
4169 } else {
4170 id.pci.bus = bridge->bus->number;
4171 id.pci.devfn = bridge->devfn;
4172 }
4173 }
4174
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004175 if (!pdev->is_virtfn && iommu_group_mf)
4176 id.pci.devfn = PCI_DEVFN(PCI_SLOT(id.pci.devfn), 0);
4177
Alex Williamson70ae6f02011-10-21 15:56:11 -04004178 *groupid = id.group;
4179
4180 return 0;
4181}
4182
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004183static struct iommu_ops intel_iommu_ops = {
4184 .domain_init = intel_iommu_domain_init,
4185 .domain_destroy = intel_iommu_domain_destroy,
4186 .attach_dev = intel_iommu_attach_device,
4187 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004188 .map = intel_iommu_map,
4189 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004190 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004191 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamson70ae6f02011-10-21 15:56:11 -04004192 .device_group = intel_iommu_device_group,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004193 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004194};
David Woodhouse9af88142009-02-13 23:18:03 +00004195
Daniel Vetter4b56ffb2013-01-20 23:50:13 +01004196static void __devinit quirk_iommu_g4x_gfx(struct pci_dev *dev)
4197{
4198 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4199 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4200 dmar_map_gfx = 0;
4201}
4202
4203DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4204DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4205DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4206DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4207DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4208DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4209DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4210
David Woodhouse9af88142009-02-13 23:18:03 +00004211static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
4212{
4213 /*
4214 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetterdf87bd32013-01-21 19:48:59 +01004215 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004216 */
4217 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4218 rwbf_quirk = 1;
4219}
4220
4221DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetterdf87bd32013-01-21 19:48:59 +01004222DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4223DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4224DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4225DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4226DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4227DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004228
Adam Jacksoneecfd572010-08-25 21:17:34 +01004229#define GGC 0x52
4230#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4231#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4232#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4233#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4234#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4235#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4236#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4237#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4238
David Woodhouse9eecabc2010-09-21 22:28:23 +01004239static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
4240{
4241 unsigned short ggc;
4242
Adam Jacksoneecfd572010-08-25 21:17:34 +01004243 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004244 return;
4245
Adam Jacksoneecfd572010-08-25 21:17:34 +01004246 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004247 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4248 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004249 } else if (dmar_map_gfx) {
4250 /* we have to ensure the gfx device is idle before we flush */
4251 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4252 intel_iommu_strict = 1;
4253 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004254}
4255DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4256DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4257DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4258DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4259
David Woodhousee0fc7e02009-09-30 09:12:17 -07004260/* On Tylersburg chipsets, some BIOSes have been known to enable the
4261 ISOCH DMAR unit for the Azalia sound device, but not give it any
4262 TLB entries, which causes it to deadlock. Check for that. We do
4263 this in a function called from init_dmars(), instead of in a PCI
4264 quirk, because we don't want to print the obnoxious "BIOS broken"
4265 message if VT-d is actually disabled.
4266*/
4267static void __init check_tylersburg_isoch(void)
4268{
4269 struct pci_dev *pdev;
4270 uint32_t vtisochctrl;
4271
4272 /* If there's no Azalia in the system anyway, forget it. */
4273 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4274 if (!pdev)
4275 return;
4276 pci_dev_put(pdev);
4277
4278 /* System Management Registers. Might be hidden, in which case
4279 we can't do the sanity check. But that's OK, because the
4280 known-broken BIOSes _don't_ actually hide it, so far. */
4281 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4282 if (!pdev)
4283 return;
4284
4285 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4286 pci_dev_put(pdev);
4287 return;
4288 }
4289
4290 pci_dev_put(pdev);
4291
4292 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4293 if (vtisochctrl & 1)
4294 return;
4295
4296 /* Drop all bits other than the number of TLB entries */
4297 vtisochctrl &= 0x1c;
4298
4299 /* If we have the recommended number of TLB entries (16), fine. */
4300 if (vtisochctrl == 0x10)
4301 return;
4302
4303 /* Zero TLB entries? You get to ride the short bus to school. */
4304 if (!vtisochctrl) {
4305 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4306 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4307 dmi_get_system_info(DMI_BIOS_VENDOR),
4308 dmi_get_system_info(DMI_BIOS_VERSION),
4309 dmi_get_system_info(DMI_PRODUCT_VERSION));
4310 iommu_identity_mapping |= IDENTMAP_AZALIA;
4311 return;
4312 }
4313
4314 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4315 vtisochctrl);
4316}