blob: 7bddb9b32da8dfd9403686145a06367f05607d57 [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>
Suresh Siddha8a8f4222012-03-30 11:47:08 -070045#include <asm/irq_remapping.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070046#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090047#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070048
Joerg Roedel078e1ee2012-09-26 12:44:43 +020049#include "irq_remapping.h"
Varun Sethi61e015a2013-04-23 10:05:24 +053050#include "pci.h"
Joerg Roedel078e1ee2012-09-26 12:44:43 +020051
Fenghua Yu5b6985c2008-10-16 18:02:32 -070052#define ROOT_SIZE VTD_PAGE_SIZE
53#define CONTEXT_SIZE VTD_PAGE_SIZE
54
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070055#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
56#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070057#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070058
59#define IOAPIC_RANGE_START (0xfee00000)
60#define IOAPIC_RANGE_END (0xfeefffff)
61#define IOVA_START_ADDR (0x1000)
62
63#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
64
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070065#define MAX_AGAW_WIDTH 64
Jiang Liu5c645b32014-01-06 14:18:12 +080066#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070067
David Woodhouse2ebe3152009-09-19 07:34:04 -070068#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
69#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
70
71/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
72 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
73#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
74 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
75#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070076
Mark McLoughlinf27be032008-11-20 15:49:43 +000077#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a92009-04-06 19:01:15 -070078#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070079#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080080
Andrew Mortondf08cdc2010-09-22 13:05:11 -070081/* page table handling */
82#define LEVEL_STRIDE (9)
83#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
84
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +020085/*
86 * This bitmap is used to advertise the page sizes our hardware support
87 * to the IOMMU core, which will then use this information to split
88 * physically contiguous memory regions it is mapping into page sizes
89 * that we support.
90 *
91 * Traditionally the IOMMU core just handed us the mappings directly,
92 * after making sure the size is an order of a 4KiB page and that the
93 * mapping has natural alignment.
94 *
95 * To retain this behavior, we currently advertise that we support
96 * all page sizes that are an order of 4KiB.
97 *
98 * If at some point we'd like to utilize the IOMMU core's new behavior,
99 * we could change this to advertise the real page sizes we support.
100 */
101#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
102
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700103static inline int agaw_to_level(int agaw)
104{
105 return agaw + 2;
106}
107
108static inline int agaw_to_width(int agaw)
109{
Jiang Liu5c645b32014-01-06 14:18:12 +0800110 return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700111}
112
113static inline int width_to_agaw(int width)
114{
Jiang Liu5c645b32014-01-06 14:18:12 +0800115 return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700116}
117
118static inline unsigned int level_to_offset_bits(int level)
119{
120 return (level - 1) * LEVEL_STRIDE;
121}
122
123static inline int pfn_level_offset(unsigned long pfn, int level)
124{
125 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
126}
127
128static inline unsigned long level_mask(int level)
129{
130 return -1UL << level_to_offset_bits(level);
131}
132
133static inline unsigned long level_size(int level)
134{
135 return 1UL << level_to_offset_bits(level);
136}
137
138static inline unsigned long align_to_level(unsigned long pfn, int level)
139{
140 return (pfn + level_size(level) - 1) & level_mask(level);
141}
David Woodhousefd18de52009-05-10 23:57:41 +0100142
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100143static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
144{
Jiang Liu5c645b32014-01-06 14:18:12 +0800145 return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100146}
147
David Woodhousedd4e8312009-06-27 16:21:20 +0100148/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
149 are never going to work. */
150static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
151{
152 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
153}
154
155static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
156{
157 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
158}
159static inline unsigned long page_to_dma_pfn(struct page *pg)
160{
161 return mm_to_dma_pfn(page_to_pfn(pg));
162}
163static inline unsigned long virt_to_dma_pfn(void *p)
164{
165 return page_to_dma_pfn(virt_to_page(p));
166}
167
Weidong Hand9630fe2008-12-08 11:06:32 +0800168/* global iommu list, set NULL for ignored DMAR units */
169static struct intel_iommu **g_iommus;
170
David Woodhousee0fc7e02009-09-30 09:12:17 -0700171static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000172static int rwbf_quirk;
173
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000174/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700175 * set to 1 to panic kernel if can't successfully enable VT-d
176 * (used when kernel is launched w/ TXT)
177 */
178static int force_on = 0;
179
180/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000181 * 0: Present
182 * 1-11: Reserved
183 * 12-63: Context Ptr (12 - (haw-1))
184 * 64-127: Reserved
185 */
186struct root_entry {
187 u64 val;
188 u64 rsvd1;
189};
190#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
191static inline bool root_present(struct root_entry *root)
192{
193 return (root->val & 1);
194}
195static inline void set_root_present(struct root_entry *root)
196{
197 root->val |= 1;
198}
199static inline void set_root_value(struct root_entry *root, unsigned long value)
200{
201 root->val |= value & VTD_PAGE_MASK;
202}
203
204static inline struct context_entry *
205get_context_addr_from_root(struct root_entry *root)
206{
207 return (struct context_entry *)
208 (root_present(root)?phys_to_virt(
209 root->val & VTD_PAGE_MASK) :
210 NULL);
211}
212
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000213/*
214 * low 64 bits:
215 * 0: present
216 * 1: fault processing disable
217 * 2-3: translation type
218 * 12-63: address space root
219 * high 64 bits:
220 * 0-2: address width
221 * 3-6: aval
222 * 8-23: domain id
223 */
224struct context_entry {
225 u64 lo;
226 u64 hi;
227};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000228
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000229static inline bool context_present(struct context_entry *context)
230{
231 return (context->lo & 1);
232}
233static inline void context_set_present(struct context_entry *context)
234{
235 context->lo |= 1;
236}
237
238static inline void context_set_fault_enable(struct context_entry *context)
239{
240 context->lo &= (((u64)-1) << 2) | 1;
241}
242
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000243static inline void context_set_translation_type(struct context_entry *context,
244 unsigned long value)
245{
246 context->lo &= (((u64)-1) << 4) | 3;
247 context->lo |= (value & 3) << 2;
248}
249
250static inline void context_set_address_root(struct context_entry *context,
251 unsigned long value)
252{
253 context->lo |= value & VTD_PAGE_MASK;
254}
255
256static inline void context_set_address_width(struct context_entry *context,
257 unsigned long value)
258{
259 context->hi |= value & 7;
260}
261
262static inline void context_set_domain_id(struct context_entry *context,
263 unsigned long value)
264{
265 context->hi |= (value & ((1 << 16) - 1)) << 8;
266}
267
268static inline void context_clear_entry(struct context_entry *context)
269{
270 context->lo = 0;
271 context->hi = 0;
272}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000273
Mark McLoughlin622ba122008-11-20 15:49:46 +0000274/*
275 * 0: readable
276 * 1: writable
277 * 2-6: reserved
278 * 7: super page
Sheng Yang9cf06692009-03-18 15:33:07 +0800279 * 8-10: available
280 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000281 * 12-63: Host physcial address
282 */
283struct dma_pte {
284 u64 val;
285};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000286
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000287static inline void dma_clear_pte(struct dma_pte *pte)
288{
289 pte->val = 0;
290}
291
292static inline void dma_set_pte_readable(struct dma_pte *pte)
293{
294 pte->val |= DMA_PTE_READ;
295}
296
297static inline void dma_set_pte_writable(struct dma_pte *pte)
298{
299 pte->val |= DMA_PTE_WRITE;
300}
301
Sheng Yang9cf06692009-03-18 15:33:07 +0800302static inline void dma_set_pte_snp(struct dma_pte *pte)
303{
304 pte->val |= DMA_PTE_SNP;
305}
306
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000307static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
308{
309 pte->val = (pte->val & ~3) | (prot & 3);
310}
311
312static inline u64 dma_pte_addr(struct dma_pte *pte)
313{
David Woodhousec85994e2009-07-01 19:21:24 +0100314#ifdef CONFIG_64BIT
315 return pte->val & VTD_PAGE_MASK;
316#else
317 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100318 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100319#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000320}
321
David Woodhousedd4e8312009-06-27 16:21:20 +0100322static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000323{
David Woodhousedd4e8312009-06-27 16:21:20 +0100324 pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000325}
326
327static inline bool dma_pte_present(struct dma_pte *pte)
328{
329 return (pte->val & 3) != 0;
330}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000331
Allen Kay4399c8b2011-10-14 12:32:46 -0700332static inline bool dma_pte_superpage(struct dma_pte *pte)
333{
334 return (pte->val & (1 << 7));
335}
336
David Woodhouse75e6bf92009-07-02 11:21:16 +0100337static inline int first_pte_in_page(struct dma_pte *pte)
338{
339 return !((unsigned long)pte & ~VTD_PAGE_MASK);
340}
341
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700342/*
343 * This domain is a statically identity mapping domain.
344 * 1. This domain creats a static 1:1 mapping to all usable memory.
345 * 2. It maps to each iommu if successful.
346 * 3. Each iommu mapps to this domain if successful.
347 */
David Woodhouse19943b02009-08-04 16:19:20 +0100348static struct dmar_domain *si_domain;
349static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700350
Weidong Han3b5410e2008-12-08 09:17:15 +0800351/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100352#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800353
Weidong Han1ce28fe2008-12-08 16:35:39 +0800354/* domain represents a virtual machine, more than one devices
355 * across iommus may be owned in one domain, e.g. kvm guest.
356 */
357#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
358
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700359/* si_domain contains mulitple devices */
360#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
361
Mike Travis1b198bb2012-03-05 15:05:16 -0800362/* define the limit of IOMMUs supported in each domain */
363#ifdef CONFIG_X86
364# define IOMMU_UNITS_SUPPORTED MAX_IO_APICS
365#else
366# define IOMMU_UNITS_SUPPORTED 64
367#endif
368
Mark McLoughlin99126f72008-11-20 15:49:47 +0000369struct dmar_domain {
370 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700371 int nid; /* node id */
Mike Travis1b198bb2012-03-05 15:05:16 -0800372 DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
373 /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000374
375 struct list_head devices; /* all devices' list */
376 struct iova_domain iovad; /* iova's that belong to this domain */
377
378 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000379 int gaw; /* max guest address width */
380
381 /* adjusted guest address width, 0 is level 2 30-bit */
382 int agaw;
383
Weidong Han3b5410e2008-12-08 09:17:15 +0800384 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800385
386 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800387 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800388 int iommu_count; /* reference count of iommu */
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100389 int iommu_superpage;/* Level of superpages supported:
390 0 == 4KiB (no superpages), 1 == 2MiB,
391 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
Weidong Hanc7151a82008-12-08 22:51:37 +0800392 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800393 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000394};
395
Mark McLoughlina647dac2008-11-20 15:49:48 +0000396/* PCI domain-device relationship */
397struct device_domain_info {
398 struct list_head link; /* link to domain siblings */
399 struct list_head global; /* link to global list */
David Woodhouse276dbf92009-04-04 01:45:37 +0100400 int segment; /* PCI domain */
401 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000402 u8 devfn; /* PCI devfn number */
Stefan Assmann45e829e2009-12-03 06:49:24 -0500403 struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800404 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000405 struct dmar_domain *domain; /* pointer to domain */
406};
407
mark gross5e0d2a62008-03-04 15:22:08 -0800408static void flush_unmaps_timeout(unsigned long data);
409
410DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
411
mark gross80b20dd2008-04-18 13:53:58 -0700412#define HIGH_WATER_MARK 250
413struct deferred_flush_tables {
414 int next;
415 struct iova *iova[HIGH_WATER_MARK];
416 struct dmar_domain *domain[HIGH_WATER_MARK];
417};
418
419static struct deferred_flush_tables *deferred_flush;
420
mark gross5e0d2a62008-03-04 15:22:08 -0800421/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800422static int g_num_of_iommus;
423
424static DEFINE_SPINLOCK(async_umap_flush_lock);
425static LIST_HEAD(unmaps_to_do);
426
427static int timer_on;
428static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800429
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700430static void domain_remove_dev_info(struct dmar_domain *domain);
431
Suresh Siddhad3f13812011-08-23 17:05:25 -0700432#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800433int dmar_disabled = 0;
434#else
435int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700436#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800437
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200438int intel_iommu_enabled = 0;
439EXPORT_SYMBOL_GPL(intel_iommu_enabled);
440
David Woodhouse2d9e6672010-06-15 10:57:57 +0100441static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700442static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800443static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100444static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700445
David Woodhousec0771df2011-10-14 20:59:46 +0100446int intel_iommu_gfx_mapped;
447EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
448
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700449#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
450static DEFINE_SPINLOCK(device_domain_lock);
451static LIST_HEAD(device_domain_list);
452
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100453static struct iommu_ops intel_iommu_ops;
454
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700455static int __init intel_iommu_setup(char *str)
456{
457 if (!str)
458 return -EINVAL;
459 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800460 if (!strncmp(str, "on", 2)) {
461 dmar_disabled = 0;
462 printk(KERN_INFO "Intel-IOMMU: enabled\n");
463 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700464 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800465 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700466 } else if (!strncmp(str, "igfx_off", 8)) {
467 dmar_map_gfx = 0;
468 printk(KERN_INFO
469 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700470 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800471 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700472 "Intel-IOMMU: Forcing DAC for PCI devices\n");
473 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800474 } else if (!strncmp(str, "strict", 6)) {
475 printk(KERN_INFO
476 "Intel-IOMMU: disable batched IOTLB flush\n");
477 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100478 } else if (!strncmp(str, "sp_off", 6)) {
479 printk(KERN_INFO
480 "Intel-IOMMU: disable supported super page\n");
481 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700482 }
483
484 str += strcspn(str, ",");
485 while (*str == ',')
486 str++;
487 }
488 return 0;
489}
490__setup("intel_iommu=", intel_iommu_setup);
491
492static struct kmem_cache *iommu_domain_cache;
493static struct kmem_cache *iommu_devinfo_cache;
494static struct kmem_cache *iommu_iova_cache;
495
Suresh Siddha4c923d42009-10-02 11:01:24 -0700496static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700497{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700498 struct page *page;
499 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700500
Suresh Siddha4c923d42009-10-02 11:01:24 -0700501 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
502 if (page)
503 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700504 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700505}
506
507static inline void free_pgtable_page(void *vaddr)
508{
509 free_page((unsigned long)vaddr);
510}
511
512static inline void *alloc_domain_mem(void)
513{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900514 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700515}
516
Kay, Allen M38717942008-09-09 18:37:29 +0300517static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700518{
519 kmem_cache_free(iommu_domain_cache, vaddr);
520}
521
522static inline void * alloc_devinfo_mem(void)
523{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900524 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700525}
526
527static inline void free_devinfo_mem(void *vaddr)
528{
529 kmem_cache_free(iommu_devinfo_cache, vaddr);
530}
531
532struct iova *alloc_iova_mem(void)
533{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900534 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700535}
536
537void free_iova_mem(struct iova *iova)
538{
539 kmem_cache_free(iommu_iova_cache, iova);
540}
541
Weidong Han1b573682008-12-08 15:34:06 +0800542
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700543static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800544{
545 unsigned long sagaw;
546 int agaw = -1;
547
548 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700549 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800550 agaw >= 0; agaw--) {
551 if (test_bit(agaw, &sagaw))
552 break;
553 }
554
555 return agaw;
556}
557
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700558/*
559 * Calculate max SAGAW for each iommu.
560 */
561int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
562{
563 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
564}
565
566/*
567 * calculate agaw for each iommu.
568 * "SAGAW" may be different across iommus, use a default agaw, and
569 * get a supported less agaw for iommus that don't support the default agaw.
570 */
571int iommu_calculate_agaw(struct intel_iommu *iommu)
572{
573 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
574}
575
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700576/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800577static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
578{
579 int iommu_id;
580
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700581 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800582 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700583 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800584
Mike Travis1b198bb2012-03-05 15:05:16 -0800585 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800586 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
587 return NULL;
588
589 return g_iommus[iommu_id];
590}
591
Weidong Han8e6040972008-12-08 15:49:06 +0800592static void domain_update_iommu_coherency(struct dmar_domain *domain)
593{
594 int i;
595
Alex Williamson2e12bc22011-11-11 17:26:44 -0700596 i = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
597
598 domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0;
Weidong Han8e6040972008-12-08 15:49:06 +0800599
Mike Travis1b198bb2012-03-05 15:05:16 -0800600 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e6040972008-12-08 15:49:06 +0800601 if (!ecap_coherent(g_iommus[i]->ecap)) {
602 domain->iommu_coherency = 0;
603 break;
604 }
Weidong Han8e6040972008-12-08 15:49:06 +0800605 }
606}
607
Sheng Yang58c610b2009-03-18 15:33:05 +0800608static void domain_update_iommu_snooping(struct dmar_domain *domain)
609{
610 int i;
611
612 domain->iommu_snooping = 1;
613
Mike Travis1b198bb2012-03-05 15:05:16 -0800614 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800615 if (!ecap_sc_support(g_iommus[i]->ecap)) {
616 domain->iommu_snooping = 0;
617 break;
618 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800619 }
620}
621
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100622static void domain_update_iommu_superpage(struct dmar_domain *domain)
623{
Allen Kay8140a952011-10-14 12:32:17 -0700624 struct dmar_drhd_unit *drhd;
625 struct intel_iommu *iommu = NULL;
626 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100627
628 if (!intel_iommu_superpage) {
629 domain->iommu_superpage = 0;
630 return;
631 }
632
Allen Kay8140a952011-10-14 12:32:17 -0700633 /* set iommu_superpage to the smallest common denominator */
634 for_each_active_iommu(iommu, drhd) {
635 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100636 if (!mask) {
637 break;
638 }
639 }
640 domain->iommu_superpage = fls(mask);
641}
642
Sheng Yang58c610b2009-03-18 15:33:05 +0800643/* Some capabilities may be different across iommus */
644static void domain_update_iommu_cap(struct dmar_domain *domain)
645{
646 domain_update_iommu_coherency(domain);
647 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100648 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800649}
650
David Woodhouse276dbf92009-04-04 01:45:37 +0100651static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800652{
653 struct dmar_drhd_unit *drhd = NULL;
654 int i;
655
656 for_each_drhd_unit(drhd) {
657 if (drhd->ignored)
658 continue;
David Woodhouse276dbf92009-04-04 01:45:37 +0100659 if (segment != drhd->segment)
660 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800661
David Woodhouse924b6232009-04-04 00:39:25 +0100662 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000663 if (drhd->devices[i] &&
664 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800665 drhd->devices[i]->devfn == devfn)
666 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700667 if (drhd->devices[i] &&
668 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100669 drhd->devices[i]->subordinate->number <= bus &&
Yinghai Lub918c622012-05-17 18:51:11 -0700670 drhd->devices[i]->subordinate->busn_res.end >= bus)
David Woodhouse924b6232009-04-04 00:39:25 +0100671 return drhd->iommu;
672 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800673
674 if (drhd->include_all)
675 return drhd->iommu;
676 }
677
678 return NULL;
679}
680
Weidong Han5331fe62008-12-08 23:00:00 +0800681static void domain_flush_cache(struct dmar_domain *domain,
682 void *addr, int size)
683{
684 if (!domain->iommu_coherency)
685 clflush_cache_range(addr, size);
686}
687
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700688/* Gets context entry for a given bus and devfn */
689static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
690 u8 bus, u8 devfn)
691{
692 struct root_entry *root;
693 struct context_entry *context;
694 unsigned long phy_addr;
695 unsigned long flags;
696
697 spin_lock_irqsave(&iommu->lock, flags);
698 root = &iommu->root_entry[bus];
699 context = get_context_addr_from_root(root);
700 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700701 context = (struct context_entry *)
702 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700703 if (!context) {
704 spin_unlock_irqrestore(&iommu->lock, flags);
705 return NULL;
706 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700707 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700708 phy_addr = virt_to_phys((void *)context);
709 set_root_value(root, phy_addr);
710 set_root_present(root);
711 __iommu_flush_cache(iommu, root, sizeof(*root));
712 }
713 spin_unlock_irqrestore(&iommu->lock, flags);
714 return &context[devfn];
715}
716
717static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
718{
719 struct root_entry *root;
720 struct context_entry *context;
721 int ret;
722 unsigned long flags;
723
724 spin_lock_irqsave(&iommu->lock, flags);
725 root = &iommu->root_entry[bus];
726 context = get_context_addr_from_root(root);
727 if (!context) {
728 ret = 0;
729 goto out;
730 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000731 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700732out:
733 spin_unlock_irqrestore(&iommu->lock, flags);
734 return ret;
735}
736
737static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
738{
739 struct root_entry *root;
740 struct context_entry *context;
741 unsigned long flags;
742
743 spin_lock_irqsave(&iommu->lock, flags);
744 root = &iommu->root_entry[bus];
745 context = get_context_addr_from_root(root);
746 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000747 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700748 __iommu_flush_cache(iommu, &context[devfn], \
749 sizeof(*context));
750 }
751 spin_unlock_irqrestore(&iommu->lock, flags);
752}
753
754static void free_context_table(struct intel_iommu *iommu)
755{
756 struct root_entry *root;
757 int i;
758 unsigned long flags;
759 struct context_entry *context;
760
761 spin_lock_irqsave(&iommu->lock, flags);
762 if (!iommu->root_entry) {
763 goto out;
764 }
765 for (i = 0; i < ROOT_ENTRY_NR; i++) {
766 root = &iommu->root_entry[i];
767 context = get_context_addr_from_root(root);
768 if (context)
769 free_pgtable_page(context);
770 }
771 free_pgtable_page(iommu->root_entry);
772 iommu->root_entry = NULL;
773out:
774 spin_unlock_irqrestore(&iommu->lock, flags);
775}
776
David Woodhouseb026fd22009-06-28 10:37:25 +0100777static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
Allen Kay4399c8b2011-10-14 12:32:46 -0700778 unsigned long pfn, int target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700779{
David Woodhouseb026fd22009-06-28 10:37:25 +0100780 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700781 struct dma_pte *parent, *pte = NULL;
782 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700783 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700784
785 BUG_ON(!domain->pgd);
Julian Stecklinaf9423602013-10-09 10:03:52 +0200786
787 if (addr_width < BITS_PER_LONG && pfn >> addr_width)
788 /* Address beyond IOMMU's addressing capabilities. */
789 return NULL;
790
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700791 parent = domain->pgd;
792
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700793 while (level > 0) {
794 void *tmp_page;
795
David Woodhouseb026fd22009-06-28 10:37:25 +0100796 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700797 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700798 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100799 break;
800 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700801 break;
802
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000803 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100804 uint64_t pteval;
805
Suresh Siddha4c923d42009-10-02 11:01:24 -0700806 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700807
David Woodhouse206a73c12009-07-01 19:30:28 +0100808 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700809 return NULL;
David Woodhouse206a73c12009-07-01 19:30:28 +0100810
David Woodhousec85994e2009-07-01 19:21:24 +0100811 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400812 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 +0100813 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
814 /* Someone else set it while we were thinking; use theirs. */
815 free_pgtable_page(tmp_page);
816 } else {
817 dma_pte_addr(pte);
818 domain_flush_cache(domain, pte, sizeof(*pte));
819 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700820 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000821 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700822 level--;
823 }
824
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700825 return pte;
826}
827
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100828
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700829/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100830static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
831 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100832 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700833{
834 struct dma_pte *parent, *pte = NULL;
835 int total = agaw_to_level(domain->agaw);
836 int offset;
837
838 parent = domain->pgd;
839 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100840 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700841 pte = &parent[offset];
842 if (level == total)
843 return pte;
844
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100845 if (!dma_pte_present(pte)) {
846 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700847 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100848 }
849
850 if (pte->val & DMA_PTE_LARGE_PAGE) {
851 *large_page = total;
852 return pte;
853 }
854
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000855 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700856 total--;
857 }
858 return NULL;
859}
860
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700861/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700862static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100863 unsigned long start_pfn,
864 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700865{
David Woodhouse04b18e62009-06-27 19:15:01 +0100866 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100867 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100868 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700869
David Woodhouse04b18e62009-06-27 19:15:01 +0100870 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100871 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700872 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100873
David Woodhouse04b18e62009-06-27 19:15:01 +0100874 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700875 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100876 large_page = 1;
877 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100878 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100879 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100880 continue;
881 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100882 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100883 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100884 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100885 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100886 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
887
David Woodhouse310a5ab2009-06-28 18:52:20 +0100888 domain_flush_cache(domain, first_pte,
889 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700890
891 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700892
Jiang Liu5c645b32014-01-06 14:18:12 +0800893 return min_t(int, (large_page - 1) * 9, MAX_AGAW_PFN_WIDTH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700894}
895
Alex Williamson3269ee02013-06-15 10:27:19 -0600896static void dma_pte_free_level(struct dmar_domain *domain, int level,
897 struct dma_pte *pte, unsigned long pfn,
898 unsigned long start_pfn, unsigned long last_pfn)
899{
900 pfn = max(start_pfn, pfn);
901 pte = &pte[pfn_level_offset(pfn, level)];
902
903 do {
904 unsigned long level_pfn;
905 struct dma_pte *level_pte;
906
907 if (!dma_pte_present(pte) || dma_pte_superpage(pte))
908 goto next;
909
910 level_pfn = pfn & level_mask(level - 1);
911 level_pte = phys_to_virt(dma_pte_addr(pte));
912
913 if (level > 2)
914 dma_pte_free_level(domain, level - 1, level_pte,
915 level_pfn, start_pfn, last_pfn);
916
917 /* If range covers entire pagetable, free it */
918 if (!(start_pfn > level_pfn ||
919 last_pfn < level_pfn + level_size(level))) {
920 dma_clear_pte(pte);
921 domain_flush_cache(domain, pte, sizeof(*pte));
922 free_pgtable_page(level_pte);
923 }
924next:
925 pfn += level_size(level);
926 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
927}
928
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700929/* free page table pages. last level pte should already be cleared */
930static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100931 unsigned long start_pfn,
932 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700933{
David Woodhouse6660c632009-06-27 22:41:00 +0100934 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700935
David Woodhouse6660c632009-06-27 22:41:00 +0100936 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
937 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700938 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700939
David Woodhousef3a0a522009-06-30 03:40:07 +0100940 /* We don't need lock here; nobody else touches the iova range */
Alex Williamson3269ee02013-06-15 10:27:19 -0600941 dma_pte_free_level(domain, agaw_to_level(domain->agaw),
942 domain->pgd, 0, start_pfn, last_pfn);
David Woodhouse6660c632009-06-27 22:41:00 +0100943
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700944 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100945 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700946 free_pgtable_page(domain->pgd);
947 domain->pgd = NULL;
948 }
949}
950
951/* iommu handling */
952static int iommu_alloc_root_entry(struct intel_iommu *iommu)
953{
954 struct root_entry *root;
955 unsigned long flags;
956
Suresh Siddha4c923d42009-10-02 11:01:24 -0700957 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700958 if (!root)
959 return -ENOMEM;
960
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700961 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700962
963 spin_lock_irqsave(&iommu->lock, flags);
964 iommu->root_entry = root;
965 spin_unlock_irqrestore(&iommu->lock, flags);
966
967 return 0;
968}
969
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700970static void iommu_set_root_entry(struct intel_iommu *iommu)
971{
972 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100973 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700974 unsigned long flag;
975
976 addr = iommu->root_entry;
977
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200978 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700979 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
980
David Woodhousec416daa2009-05-10 20:30:58 +0100981 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700982
983 /* Make sure hardware complete it */
984 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100985 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700986
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200987 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700988}
989
990static void iommu_flush_write_buffer(struct intel_iommu *iommu)
991{
992 u32 val;
993 unsigned long flag;
994
David Woodhouse9af88142009-02-13 23:18:03 +0000995 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700996 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700997
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200998 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100999 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001000
1001 /* Make sure hardware complete it */
1002 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001003 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001004
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001005 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001006}
1007
1008/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001009static void __iommu_flush_context(struct intel_iommu *iommu,
1010 u16 did, u16 source_id, u8 function_mask,
1011 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001012{
1013 u64 val = 0;
1014 unsigned long flag;
1015
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001016 switch (type) {
1017 case DMA_CCMD_GLOBAL_INVL:
1018 val = DMA_CCMD_GLOBAL_INVL;
1019 break;
1020 case DMA_CCMD_DOMAIN_INVL:
1021 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1022 break;
1023 case DMA_CCMD_DEVICE_INVL:
1024 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1025 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1026 break;
1027 default:
1028 BUG();
1029 }
1030 val |= DMA_CCMD_ICC;
1031
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001032 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001033 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1034
1035 /* Make sure hardware complete it */
1036 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1037 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1038
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001039 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001040}
1041
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001042/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001043static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1044 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001045{
1046 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1047 u64 val = 0, val_iva = 0;
1048 unsigned long flag;
1049
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001050 switch (type) {
1051 case DMA_TLB_GLOBAL_FLUSH:
1052 /* global flush doesn't need set IVA_REG */
1053 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1054 break;
1055 case DMA_TLB_DSI_FLUSH:
1056 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1057 break;
1058 case DMA_TLB_PSI_FLUSH:
1059 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1060 /* Note: always flush non-leaf currently */
1061 val_iva = size_order | addr;
1062 break;
1063 default:
1064 BUG();
1065 }
1066 /* Note: set drain read/write */
1067#if 0
1068 /*
1069 * This is probably to be super secure.. Looks like we can
1070 * ignore it without any impact.
1071 */
1072 if (cap_read_drain(iommu->cap))
1073 val |= DMA_TLB_READ_DRAIN;
1074#endif
1075 if (cap_write_drain(iommu->cap))
1076 val |= DMA_TLB_WRITE_DRAIN;
1077
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001078 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001079 /* Note: Only uses first TLB reg currently */
1080 if (val_iva)
1081 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1082 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1083
1084 /* Make sure hardware complete it */
1085 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1086 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1087
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001088 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001089
1090 /* check IOTLB invalidation granularity */
1091 if (DMA_TLB_IAIG(val) == 0)
1092 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1093 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1094 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001095 (unsigned long long)DMA_TLB_IIRG(type),
1096 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001097}
1098
Yu Zhao93a23a72009-05-18 13:51:37 +08001099static struct device_domain_info *iommu_support_dev_iotlb(
1100 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001101{
Yu Zhao93a23a72009-05-18 13:51:37 +08001102 int found = 0;
1103 unsigned long flags;
1104 struct device_domain_info *info;
1105 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1106
1107 if (!ecap_dev_iotlb_support(iommu->ecap))
1108 return NULL;
1109
1110 if (!iommu->qi)
1111 return NULL;
1112
1113 spin_lock_irqsave(&device_domain_lock, flags);
1114 list_for_each_entry(info, &domain->devices, link)
1115 if (info->bus == bus && info->devfn == devfn) {
1116 found = 1;
1117 break;
1118 }
1119 spin_unlock_irqrestore(&device_domain_lock, flags);
1120
1121 if (!found || !info->dev)
1122 return NULL;
1123
1124 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1125 return NULL;
1126
1127 if (!dmar_find_matched_atsr_unit(info->dev))
1128 return NULL;
1129
1130 info->iommu = iommu;
1131
1132 return info;
1133}
1134
1135static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1136{
1137 if (!info)
1138 return;
1139
1140 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1141}
1142
1143static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1144{
1145 if (!info->dev || !pci_ats_enabled(info->dev))
1146 return;
1147
1148 pci_disable_ats(info->dev);
1149}
1150
1151static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1152 u64 addr, unsigned mask)
1153{
1154 u16 sid, qdep;
1155 unsigned long flags;
1156 struct device_domain_info *info;
1157
1158 spin_lock_irqsave(&device_domain_lock, flags);
1159 list_for_each_entry(info, &domain->devices, link) {
1160 if (!info->dev || !pci_ats_enabled(info->dev))
1161 continue;
1162
1163 sid = info->bus << 8 | info->devfn;
1164 qdep = pci_ats_queue_depth(info->dev);
1165 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1166 }
1167 spin_unlock_irqrestore(&device_domain_lock, flags);
1168}
1169
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001170static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001171 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001172{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001173 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001174 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001175
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001176 BUG_ON(pages == 0);
1177
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001178 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001179 * Fallback to domain selective flush if no PSI support or the size is
1180 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001181 * PSI requires page size to be 2 ^ x, and the base address is naturally
1182 * aligned to the size
1183 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001184 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1185 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001186 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001187 else
1188 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1189 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001190
1191 /*
Nadav Amit82653632010-04-01 13:24:40 +03001192 * In caching mode, changes of pages from non-present to present require
1193 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001194 */
Nadav Amit82653632010-04-01 13:24:40 +03001195 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001196 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001197}
1198
mark grossf8bab732008-02-08 04:18:38 -08001199static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1200{
1201 u32 pmen;
1202 unsigned long flags;
1203
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001204 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001205 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1206 pmen &= ~DMA_PMEN_EPM;
1207 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1208
1209 /* wait for the protected region status bit to clear */
1210 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1211 readl, !(pmen & DMA_PMEN_PRS), pmen);
1212
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001213 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001214}
1215
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001216static int iommu_enable_translation(struct intel_iommu *iommu)
1217{
1218 u32 sts;
1219 unsigned long flags;
1220
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001221 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001222 iommu->gcmd |= DMA_GCMD_TE;
1223 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001224
1225 /* Make sure hardware complete it */
1226 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001227 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001228
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001229 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001230 return 0;
1231}
1232
1233static int iommu_disable_translation(struct intel_iommu *iommu)
1234{
1235 u32 sts;
1236 unsigned long flag;
1237
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001238 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001239 iommu->gcmd &= ~DMA_GCMD_TE;
1240 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1241
1242 /* Make sure hardware complete it */
1243 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001244 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001245
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001246 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001247 return 0;
1248}
1249
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001250
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001251static int iommu_init_domains(struct intel_iommu *iommu)
1252{
1253 unsigned long ndomains;
1254 unsigned long nlongs;
1255
1256 ndomains = cap_ndoms(iommu->cap);
Jiang Liu852bdb02014-01-06 14:18:11 +08001257 pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
1258 iommu->seq_id, ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001259 nlongs = BITS_TO_LONGS(ndomains);
1260
Donald Dutile94a91b52009-08-20 16:51:34 -04001261 spin_lock_init(&iommu->lock);
1262
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001263 /* TBD: there might be 64K domains,
1264 * consider other allocation for future chip
1265 */
1266 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1267 if (!iommu->domain_ids) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001268 pr_err("IOMMU%d: allocating domain id array failed\n",
1269 iommu->seq_id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001270 return -ENOMEM;
1271 }
1272 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1273 GFP_KERNEL);
1274 if (!iommu->domains) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001275 pr_err("IOMMU%d: allocating domain array failed\n",
1276 iommu->seq_id);
1277 kfree(iommu->domain_ids);
1278 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001279 return -ENOMEM;
1280 }
1281
1282 /*
1283 * if Caching mode is set, then invalid translations are tagged
1284 * with domainid 0. Hence we need to pre-allocate it.
1285 */
1286 if (cap_caching_mode(iommu->cap))
1287 set_bit(0, iommu->domain_ids);
1288 return 0;
1289}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001290
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001291
1292static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001293static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001294
1295void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001296{
1297 struct dmar_domain *domain;
1298 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001299 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001300
Donald Dutile94a91b52009-08-20 16:51:34 -04001301 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001302 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001303 domain = iommu->domains[i];
1304 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001305
Donald Dutile94a91b52009-08-20 16:51:34 -04001306 spin_lock_irqsave(&domain->iommu_lock, flags);
1307 if (--domain->iommu_count == 0) {
1308 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1309 vm_domain_exit(domain);
1310 else
1311 domain_exit(domain);
1312 }
1313 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001314 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001315 }
1316
1317 if (iommu->gcmd & DMA_GCMD_TE)
1318 iommu_disable_translation(iommu);
1319
1320 if (iommu->irq) {
Thomas Gleixnerdced35a2011-03-28 17:49:12 +02001321 irq_set_handler_data(iommu->irq, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001322 /* This will mask the irq */
1323 free_irq(iommu->irq, iommu);
1324 destroy_irq(iommu->irq);
1325 }
1326
1327 kfree(iommu->domains);
1328 kfree(iommu->domain_ids);
1329
Weidong Hand9630fe2008-12-08 11:06:32 +08001330 g_iommus[iommu->seq_id] = NULL;
1331
1332 /* if all iommus are freed, free g_iommus */
1333 for (i = 0; i < g_num_of_iommus; i++) {
1334 if (g_iommus[i])
1335 break;
1336 }
1337
1338 if (i == g_num_of_iommus)
1339 kfree(g_iommus);
1340
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001341 /* free context mapping */
1342 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001343}
1344
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001345static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001346{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001347 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001348
1349 domain = alloc_domain_mem();
1350 if (!domain)
1351 return NULL;
1352
Suresh Siddha4c923d42009-10-02 11:01:24 -07001353 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08001354 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001355 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001356
1357 return domain;
1358}
1359
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001360static int iommu_attach_domain(struct dmar_domain *domain,
1361 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001362{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001363 int num;
1364 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001365 unsigned long flags;
1366
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001367 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001368
1369 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001370
1371 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1372 if (num >= ndomains) {
1373 spin_unlock_irqrestore(&iommu->lock, flags);
1374 printk(KERN_ERR "IOMMU: no free domain ids\n");
1375 return -ENOMEM;
1376 }
1377
1378 domain->id = num;
1379 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001380 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001381 iommu->domains[num] = domain;
1382 spin_unlock_irqrestore(&iommu->lock, flags);
1383
1384 return 0;
1385}
1386
1387static void iommu_detach_domain(struct dmar_domain *domain,
1388 struct intel_iommu *iommu)
1389{
1390 unsigned long flags;
1391 int num, ndomains;
1392 int found = 0;
1393
1394 spin_lock_irqsave(&iommu->lock, flags);
1395 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001396 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001397 if (iommu->domains[num] == domain) {
1398 found = 1;
1399 break;
1400 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001401 }
1402
1403 if (found) {
1404 clear_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001405 clear_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001406 iommu->domains[num] = NULL;
1407 }
Weidong Han8c11e792008-12-08 15:29:22 +08001408 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001409}
1410
1411static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001412static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001413
Joseph Cihula51a63e62011-03-21 11:04:24 -07001414static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001415{
1416 struct pci_dev *pdev = NULL;
1417 struct iova *iova;
1418 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001419
David Millerf6611972008-02-06 01:36:23 -08001420 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001421
Mark Gross8a443df2008-03-04 14:59:31 -08001422 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1423 &reserved_rbtree_key);
1424
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001425 /* IOAPIC ranges shouldn't be accessed by DMA */
1426 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1427 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001428 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001429 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001430 return -ENODEV;
1431 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001432
1433 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1434 for_each_pci_dev(pdev) {
1435 struct resource *r;
1436
1437 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1438 r = &pdev->resource[i];
1439 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1440 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001441 iova = reserve_iova(&reserved_iova_list,
1442 IOVA_PFN(r->start),
1443 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001444 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001445 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001446 return -ENODEV;
1447 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001448 }
1449 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001450 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001451}
1452
1453static void domain_reserve_special_ranges(struct dmar_domain *domain)
1454{
1455 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1456}
1457
1458static inline int guestwidth_to_adjustwidth(int gaw)
1459{
1460 int agaw;
1461 int r = (gaw - 12) % 9;
1462
1463 if (r == 0)
1464 agaw = gaw;
1465 else
1466 agaw = gaw + 9 - r;
1467 if (agaw > 64)
1468 agaw = 64;
1469 return agaw;
1470}
1471
1472static int domain_init(struct dmar_domain *domain, int guest_width)
1473{
1474 struct intel_iommu *iommu;
1475 int adjust_width, agaw;
1476 unsigned long sagaw;
1477
David Millerf6611972008-02-06 01:36:23 -08001478 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001479 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001480
1481 domain_reserve_special_ranges(domain);
1482
1483 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001484 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001485 if (guest_width > cap_mgaw(iommu->cap))
1486 guest_width = cap_mgaw(iommu->cap);
1487 domain->gaw = guest_width;
1488 adjust_width = guestwidth_to_adjustwidth(guest_width);
1489 agaw = width_to_agaw(adjust_width);
1490 sagaw = cap_sagaw(iommu->cap);
1491 if (!test_bit(agaw, &sagaw)) {
1492 /* hardware doesn't support it, choose a bigger one */
1493 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1494 agaw = find_next_bit(&sagaw, 5, agaw);
1495 if (agaw >= 5)
1496 return -ENODEV;
1497 }
1498 domain->agaw = agaw;
1499 INIT_LIST_HEAD(&domain->devices);
1500
Weidong Han8e6040972008-12-08 15:49:06 +08001501 if (ecap_coherent(iommu->ecap))
1502 domain->iommu_coherency = 1;
1503 else
1504 domain->iommu_coherency = 0;
1505
Sheng Yang58c610b2009-03-18 15:33:05 +08001506 if (ecap_sc_support(iommu->ecap))
1507 domain->iommu_snooping = 1;
1508 else
1509 domain->iommu_snooping = 0;
1510
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001511 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Weidong Hanc7151a82008-12-08 22:51:37 +08001512 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001513 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001514
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001515 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001516 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001517 if (!domain->pgd)
1518 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001519 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001520 return 0;
1521}
1522
1523static void domain_exit(struct dmar_domain *domain)
1524{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001525 struct dmar_drhd_unit *drhd;
1526 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001527
1528 /* Domain 0 is reserved, so dont process it */
1529 if (!domain)
1530 return;
1531
Alex Williamson7b668352011-05-24 12:02:41 +01001532 /* Flush any lazy unmaps that may reference this domain */
1533 if (!intel_iommu_strict)
1534 flush_unmaps_timeout(0);
1535
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001536 domain_remove_dev_info(domain);
1537 /* destroy iovas */
1538 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001539
1540 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001541 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001542
1543 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001544 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001545
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001546 for_each_active_iommu(iommu, drhd)
Mike Travis1b198bb2012-03-05 15:05:16 -08001547 if (test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001548 iommu_detach_domain(domain, iommu);
1549
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001550 free_domain_mem(domain);
1551}
1552
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001553static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1554 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001555{
1556 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001557 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001558 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001559 struct dma_pte *pgd;
1560 unsigned long num;
1561 unsigned long ndomains;
1562 int id;
1563 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001564 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001565
1566 pr_debug("Set context mapping for %02x:%02x.%d\n",
1567 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001568
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001569 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001570 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1571 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001572
David Woodhouse276dbf92009-04-04 01:45:37 +01001573 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001574 if (!iommu)
1575 return -ENODEV;
1576
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001577 context = device_to_context_entry(iommu, bus, devfn);
1578 if (!context)
1579 return -ENOMEM;
1580 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001581 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001582 spin_unlock_irqrestore(&iommu->lock, flags);
1583 return 0;
1584 }
1585
Weidong Hanea6606b2008-12-08 23:08:15 +08001586 id = domain->id;
1587 pgd = domain->pgd;
1588
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001589 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1590 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001591 int found = 0;
1592
1593 /* find an available domain id for this device in iommu */
1594 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001595 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001596 if (iommu->domains[num] == domain) {
1597 id = num;
1598 found = 1;
1599 break;
1600 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001601 }
1602
1603 if (found == 0) {
1604 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1605 if (num >= ndomains) {
1606 spin_unlock_irqrestore(&iommu->lock, flags);
1607 printk(KERN_ERR "IOMMU: no free domain ids\n");
1608 return -EFAULT;
1609 }
1610
1611 set_bit(num, iommu->domain_ids);
1612 iommu->domains[num] = domain;
1613 id = num;
1614 }
1615
1616 /* Skip top levels of page tables for
1617 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001618 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001619 */
Chris Wright1672af12009-12-02 12:06:34 -08001620 if (translation != CONTEXT_TT_PASS_THROUGH) {
1621 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1622 pgd = phys_to_virt(dma_pte_addr(pgd));
1623 if (!dma_pte_present(pgd)) {
1624 spin_unlock_irqrestore(&iommu->lock, flags);
1625 return -ENOMEM;
1626 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001627 }
1628 }
1629 }
1630
1631 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001632
Yu Zhao93a23a72009-05-18 13:51:37 +08001633 if (translation != CONTEXT_TT_PASS_THROUGH) {
1634 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1635 translation = info ? CONTEXT_TT_DEV_IOTLB :
1636 CONTEXT_TT_MULTI_LEVEL;
1637 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001638 /*
1639 * In pass through mode, AW must be programmed to indicate the largest
1640 * AGAW value supported by hardware. And ASR is ignored by hardware.
1641 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001642 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001643 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001644 else {
1645 context_set_address_root(context, virt_to_phys(pgd));
1646 context_set_address_width(context, iommu->agaw);
1647 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001648
1649 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001650 context_set_fault_enable(context);
1651 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001652 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001653
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001654 /*
1655 * It's a non-present to present mapping. If hardware doesn't cache
1656 * non-present entry we only need to flush the write-buffer. If the
1657 * _does_ cache non-present entries, then it does so in the special
1658 * domain #0, which we have to flush:
1659 */
1660 if (cap_caching_mode(iommu->cap)) {
1661 iommu->flush.flush_context(iommu, 0,
1662 (((u16)bus) << 8) | devfn,
1663 DMA_CCMD_MASK_NOBIT,
1664 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001665 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001666 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001667 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001668 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001669 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001670 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001671
1672 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001673 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001674 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001675 if (domain->iommu_count == 1)
1676 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001677 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001678 }
1679 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001680 return 0;
1681}
1682
1683static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001684domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1685 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001686{
1687 int ret;
1688 struct pci_dev *tmp, *parent;
1689
David Woodhouse276dbf92009-04-04 01:45:37 +01001690 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001691 pdev->bus->number, pdev->devfn,
1692 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001693 if (ret)
1694 return ret;
1695
1696 /* dependent device mapping */
1697 tmp = pci_find_upstream_pcie_bridge(pdev);
1698 if (!tmp)
1699 return 0;
1700 /* Secondary interface's bus number and devfn 0 */
1701 parent = pdev->bus->self;
1702 while (parent != tmp) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001703 ret = domain_context_mapping_one(domain,
1704 pci_domain_nr(parent->bus),
1705 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001706 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001707 if (ret)
1708 return ret;
1709 parent = parent->bus->self;
1710 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001711 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001712 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001713 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001714 tmp->subordinate->number, 0,
1715 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001716 else /* this is a legacy PCI bridge */
1717 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001718 pci_domain_nr(tmp->bus),
1719 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001720 tmp->devfn,
1721 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001722}
1723
Weidong Han5331fe62008-12-08 23:00:00 +08001724static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001725{
1726 int ret;
1727 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001728 struct intel_iommu *iommu;
1729
David Woodhouse276dbf92009-04-04 01:45:37 +01001730 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1731 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001732 if (!iommu)
1733 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001734
David Woodhouse276dbf92009-04-04 01:45:37 +01001735 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001736 if (!ret)
1737 return ret;
1738 /* dependent device mapping */
1739 tmp = pci_find_upstream_pcie_bridge(pdev);
1740 if (!tmp)
1741 return ret;
1742 /* Secondary interface's bus number and devfn 0 */
1743 parent = pdev->bus->self;
1744 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001745 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01001746 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001747 if (!ret)
1748 return ret;
1749 parent = parent->bus->self;
1750 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001751 if (pci_is_pcie(tmp))
David Woodhouse276dbf92009-04-04 01:45:37 +01001752 return device_context_mapped(iommu, tmp->subordinate->number,
1753 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001754 else
David Woodhouse276dbf92009-04-04 01:45:37 +01001755 return device_context_mapped(iommu, tmp->bus->number,
1756 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001757}
1758
Fenghua Yuf5329592009-08-04 15:09:37 -07001759/* Returns a number of VTD pages, but aligned to MM page size */
1760static inline unsigned long aligned_nrpages(unsigned long host_addr,
1761 size_t size)
1762{
1763 host_addr &= ~PAGE_MASK;
1764 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1765}
1766
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001767/* Return largest possible superpage level for a given mapping */
1768static inline int hardware_largepage_caps(struct dmar_domain *domain,
1769 unsigned long iov_pfn,
1770 unsigned long phy_pfn,
1771 unsigned long pages)
1772{
1773 int support, level = 1;
1774 unsigned long pfnmerge;
1775
1776 support = domain->iommu_superpage;
1777
1778 /* To use a large page, the virtual *and* physical addresses
1779 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1780 of them will mean we have to use smaller pages. So just
1781 merge them and check both at once. */
1782 pfnmerge = iov_pfn | phy_pfn;
1783
1784 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1785 pages >>= VTD_STRIDE_SHIFT;
1786 if (!pages)
1787 break;
1788 pfnmerge >>= VTD_STRIDE_SHIFT;
1789 level++;
1790 support--;
1791 }
1792 return level;
1793}
1794
David Woodhouse9051aa02009-06-29 12:30:54 +01001795static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1796 struct scatterlist *sg, unsigned long phys_pfn,
1797 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001798{
1799 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001800 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001801 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001802 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001803 unsigned int largepage_lvl = 0;
1804 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001805
1806 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1807
1808 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1809 return -EINVAL;
1810
1811 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1812
David Woodhouse9051aa02009-06-29 12:30:54 +01001813 if (sg)
1814 sg_res = 0;
1815 else {
1816 sg_res = nr_pages + 1;
1817 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1818 }
1819
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001820 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001821 uint64_t tmp;
1822
David Woodhousee1605492009-06-29 11:17:38 +01001823 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001824 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001825 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1826 sg->dma_length = sg->length;
1827 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001828 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001829 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001830
David Woodhousee1605492009-06-29 11:17:38 +01001831 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001832 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1833
1834 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001835 if (!pte)
1836 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001837 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001838 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001839 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001840 /* Ensure that old small page tables are removed to make room
1841 for superpage, if they exist. */
1842 dma_pte_clear_range(domain, iov_pfn,
1843 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1844 dma_pte_free_pagetable(domain, iov_pfn,
1845 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1846 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001847 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001848 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001849
David Woodhousee1605492009-06-29 11:17:38 +01001850 }
1851 /* We don't need lock here, nobody else
1852 * touches the iova range
1853 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001854 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001855 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001856 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001857 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1858 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001859 if (dumps) {
1860 dumps--;
1861 debug_dma_dump_mappings(NULL);
1862 }
1863 WARN_ON(1);
1864 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001865
1866 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1867
1868 BUG_ON(nr_pages < lvl_pages);
1869 BUG_ON(sg_res < lvl_pages);
1870
1871 nr_pages -= lvl_pages;
1872 iov_pfn += lvl_pages;
1873 phys_pfn += lvl_pages;
1874 pteval += lvl_pages * VTD_PAGE_SIZE;
1875 sg_res -= lvl_pages;
1876
1877 /* If the next PTE would be the first in a new page, then we
1878 need to flush the cache on the entries we've just written.
1879 And then we'll need to recalculate 'pte', so clear it and
1880 let it get set again in the if (!pte) block above.
1881
1882 If we're done (!nr_pages) we need to flush the cache too.
1883
1884 Also if we've been setting superpages, we may need to
1885 recalculate 'pte' and switch back to smaller pages for the
1886 end of the mapping, if the trailing size is not enough to
1887 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001888 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001889 if (!nr_pages || first_pte_in_page(pte) ||
1890 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001891 domain_flush_cache(domain, first_pte,
1892 (void *)pte - (void *)first_pte);
1893 pte = NULL;
1894 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001895
1896 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001897 sg = sg_next(sg);
1898 }
1899 return 0;
1900}
1901
David Woodhouse9051aa02009-06-29 12:30:54 +01001902static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1903 struct scatterlist *sg, unsigned long nr_pages,
1904 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001905{
David Woodhouse9051aa02009-06-29 12:30:54 +01001906 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1907}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001908
David Woodhouse9051aa02009-06-29 12:30:54 +01001909static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1910 unsigned long phys_pfn, unsigned long nr_pages,
1911 int prot)
1912{
1913 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001914}
1915
Weidong Hanc7151a82008-12-08 22:51:37 +08001916static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001917{
Weidong Hanc7151a82008-12-08 22:51:37 +08001918 if (!iommu)
1919 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001920
1921 clear_context_table(iommu, bus, devfn);
1922 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001923 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001924 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001925}
1926
David Woodhouse109b9b02012-05-25 17:43:02 +01001927static inline void unlink_domain_info(struct device_domain_info *info)
1928{
1929 assert_spin_locked(&device_domain_lock);
1930 list_del(&info->link);
1931 list_del(&info->global);
1932 if (info->dev)
1933 info->dev->dev.archdata.iommu = NULL;
1934}
1935
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001936static void domain_remove_dev_info(struct dmar_domain *domain)
1937{
1938 struct device_domain_info *info;
1939 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001940 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001941
1942 spin_lock_irqsave(&device_domain_lock, flags);
1943 while (!list_empty(&domain->devices)) {
1944 info = list_entry(domain->devices.next,
1945 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01001946 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001947 spin_unlock_irqrestore(&device_domain_lock, flags);
1948
Yu Zhao93a23a72009-05-18 13:51:37 +08001949 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01001950 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001951 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001952 free_devinfo_mem(info);
1953
1954 spin_lock_irqsave(&device_domain_lock, flags);
1955 }
1956 spin_unlock_irqrestore(&device_domain_lock, flags);
1957}
1958
1959/*
1960 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001961 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001962 */
Kay, Allen M38717942008-09-09 18:37:29 +03001963static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001964find_domain(struct pci_dev *pdev)
1965{
1966 struct device_domain_info *info;
1967
1968 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001969 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001970 if (info)
1971 return info->domain;
1972 return NULL;
1973}
1974
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001975/* domain is initialized */
1976static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1977{
1978 struct dmar_domain *domain, *found = NULL;
1979 struct intel_iommu *iommu;
1980 struct dmar_drhd_unit *drhd;
1981 struct device_domain_info *info, *tmp;
1982 struct pci_dev *dev_tmp;
1983 unsigned long flags;
1984 int bus = 0, devfn = 0;
David Woodhouse276dbf92009-04-04 01:45:37 +01001985 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001986 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001987
1988 domain = find_domain(pdev);
1989 if (domain)
1990 return domain;
1991
David Woodhouse276dbf92009-04-04 01:45:37 +01001992 segment = pci_domain_nr(pdev->bus);
1993
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001994 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1995 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001996 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001997 bus = dev_tmp->subordinate->number;
1998 devfn = 0;
1999 } else {
2000 bus = dev_tmp->bus->number;
2001 devfn = dev_tmp->devfn;
2002 }
2003 spin_lock_irqsave(&device_domain_lock, flags);
2004 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01002005 if (info->segment == segment &&
2006 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002007 found = info->domain;
2008 break;
2009 }
2010 }
2011 spin_unlock_irqrestore(&device_domain_lock, flags);
2012 /* pcie-pci bridge already has a domain, uses it */
2013 if (found) {
2014 domain = found;
2015 goto found_domain;
2016 }
2017 }
2018
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002019 domain = alloc_domain();
2020 if (!domain)
2021 goto error;
2022
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002023 /* Allocate new domain for the device */
2024 drhd = dmar_find_matched_drhd_unit(pdev);
2025 if (!drhd) {
2026 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2027 pci_name(pdev));
Julia Lawalld2900bd2012-07-24 16:18:14 +02002028 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002029 return NULL;
2030 }
2031 iommu = drhd->iommu;
2032
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002033 ret = iommu_attach_domain(domain, iommu);
2034 if (ret) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002035 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002036 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002037 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002038
2039 if (domain_init(domain, gaw)) {
2040 domain_exit(domain);
2041 goto error;
2042 }
2043
2044 /* register pcie-to-pci device */
2045 if (dev_tmp) {
2046 info = alloc_devinfo_mem();
2047 if (!info) {
2048 domain_exit(domain);
2049 goto error;
2050 }
David Woodhouse276dbf92009-04-04 01:45:37 +01002051 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002052 info->bus = bus;
2053 info->devfn = devfn;
2054 info->dev = NULL;
2055 info->domain = domain;
2056 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08002057 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002058
2059 /* pcie-to-pci bridge already has a domain, uses it */
2060 found = NULL;
2061 spin_lock_irqsave(&device_domain_lock, flags);
2062 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf92009-04-04 01:45:37 +01002063 if (tmp->segment == segment &&
2064 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002065 found = tmp->domain;
2066 break;
2067 }
2068 }
2069 if (found) {
Jiri Slaby00dfff72010-06-14 17:17:32 +02002070 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002071 free_devinfo_mem(info);
2072 domain_exit(domain);
2073 domain = found;
2074 } else {
2075 list_add(&info->link, &domain->devices);
2076 list_add(&info->global, &device_domain_list);
Jiri Slaby00dfff72010-06-14 17:17:32 +02002077 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002078 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002079 }
2080
2081found_domain:
2082 info = alloc_devinfo_mem();
2083 if (!info)
2084 goto error;
David Woodhouse276dbf92009-04-04 01:45:37 +01002085 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002086 info->bus = pdev->bus->number;
2087 info->devfn = pdev->devfn;
2088 info->dev = pdev;
2089 info->domain = domain;
2090 spin_lock_irqsave(&device_domain_lock, flags);
2091 /* somebody is fast */
2092 found = find_domain(pdev);
2093 if (found != NULL) {
2094 spin_unlock_irqrestore(&device_domain_lock, flags);
2095 if (found != domain) {
2096 domain_exit(domain);
2097 domain = found;
2098 }
2099 free_devinfo_mem(info);
2100 return domain;
2101 }
2102 list_add(&info->link, &domain->devices);
2103 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002104 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002105 spin_unlock_irqrestore(&device_domain_lock, flags);
2106 return domain;
2107error:
2108 /* recheck it here, maybe others set it */
2109 return find_domain(pdev);
2110}
2111
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002112static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002113#define IDENTMAP_ALL 1
2114#define IDENTMAP_GFX 2
2115#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002116
David Woodhouseb2132032009-06-26 18:50:28 +01002117static int iommu_domain_identity_map(struct dmar_domain *domain,
2118 unsigned long long start,
2119 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002120{
David Woodhousec5395d52009-06-28 16:35:56 +01002121 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2122 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002123
David Woodhousec5395d52009-06-28 16:35:56 +01002124 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2125 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002126 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002127 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002128 }
2129
David Woodhousec5395d52009-06-28 16:35:56 +01002130 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2131 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002132 /*
2133 * RMRR range might have overlap with physical memory range,
2134 * clear it first
2135 */
David Woodhousec5395d52009-06-28 16:35:56 +01002136 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002137
David Woodhousec5395d52009-06-28 16:35:56 +01002138 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2139 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002140 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002141}
2142
2143static int iommu_prepare_identity_map(struct pci_dev *pdev,
2144 unsigned long long start,
2145 unsigned long long end)
2146{
2147 struct dmar_domain *domain;
2148 int ret;
2149
David Woodhousec7ab48d2009-06-26 19:10:36 +01002150 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002151 if (!domain)
2152 return -ENOMEM;
2153
David Woodhouse19943b02009-08-04 16:19:20 +01002154 /* For _hardware_ passthrough, don't bother. But for software
2155 passthrough, we do it anyway -- it may indicate a memory
2156 range which is reserved in E820, so which didn't get set
2157 up to start with in si_domain */
2158 if (domain == si_domain && hw_pass_through) {
2159 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2160 pci_name(pdev), start, end);
2161 return 0;
2162 }
2163
2164 printk(KERN_INFO
2165 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2166 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002167
David Woodhouse5595b522009-12-02 09:21:55 +00002168 if (end < start) {
2169 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2170 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2171 dmi_get_system_info(DMI_BIOS_VENDOR),
2172 dmi_get_system_info(DMI_BIOS_VERSION),
2173 dmi_get_system_info(DMI_PRODUCT_VERSION));
2174 ret = -EIO;
2175 goto error;
2176 }
2177
David Woodhouse2ff729f2009-08-26 14:25:41 +01002178 if (end >> agaw_to_width(domain->agaw)) {
2179 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2180 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2181 agaw_to_width(domain->agaw),
2182 dmi_get_system_info(DMI_BIOS_VENDOR),
2183 dmi_get_system_info(DMI_BIOS_VERSION),
2184 dmi_get_system_info(DMI_PRODUCT_VERSION));
2185 ret = -EIO;
2186 goto error;
2187 }
David Woodhouse19943b02009-08-04 16:19:20 +01002188
David Woodhouseb2132032009-06-26 18:50:28 +01002189 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002190 if (ret)
2191 goto error;
2192
2193 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002194 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002195 if (ret)
2196 goto error;
2197
2198 return 0;
2199
2200 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002201 domain_exit(domain);
2202 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002203}
2204
2205static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2206 struct pci_dev *pdev)
2207{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002208 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002209 return 0;
2210 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002211 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002212}
2213
Suresh Siddhad3f13812011-08-23 17:05:25 -07002214#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002215static inline void iommu_prepare_isa(void)
2216{
2217 struct pci_dev *pdev;
2218 int ret;
2219
2220 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2221 if (!pdev)
2222 return;
2223
David Woodhousec7ab48d2009-06-26 19:10:36 +01002224 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002225 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002226
2227 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002228 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2229 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002230
2231}
2232#else
2233static inline void iommu_prepare_isa(void)
2234{
2235 return;
2236}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002237#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002238
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002239static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002240
Matt Kraai071e1372009-08-23 22:30:22 -07002241static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002242{
2243 struct dmar_drhd_unit *drhd;
2244 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002245 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002246
2247 si_domain = alloc_domain();
2248 if (!si_domain)
2249 return -EFAULT;
2250
David Woodhousec7ab48d2009-06-26 19:10:36 +01002251 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002252
2253 for_each_active_iommu(iommu, drhd) {
2254 ret = iommu_attach_domain(si_domain, iommu);
2255 if (ret) {
2256 domain_exit(si_domain);
2257 return -EFAULT;
2258 }
2259 }
2260
2261 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2262 domain_exit(si_domain);
2263 return -EFAULT;
2264 }
2265
2266 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2267
David Woodhouse19943b02009-08-04 16:19:20 +01002268 if (hw)
2269 return 0;
2270
David Woodhousec7ab48d2009-06-26 19:10:36 +01002271 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002272 unsigned long start_pfn, end_pfn;
2273 int i;
2274
2275 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2276 ret = iommu_domain_identity_map(si_domain,
2277 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2278 if (ret)
2279 return ret;
2280 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002281 }
2282
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002283 return 0;
2284}
2285
2286static void domain_remove_one_dev_info(struct dmar_domain *domain,
2287 struct pci_dev *pdev);
2288static int identity_mapping(struct pci_dev *pdev)
2289{
2290 struct device_domain_info *info;
2291
2292 if (likely(!iommu_identity_mapping))
2293 return 0;
2294
Mike Traviscb452a42011-05-28 13:15:03 -05002295 info = pdev->dev.archdata.iommu;
2296 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2297 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002298
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002299 return 0;
2300}
2301
2302static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002303 struct pci_dev *pdev,
2304 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002305{
2306 struct device_domain_info *info;
2307 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002308 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002309
2310 info = alloc_devinfo_mem();
2311 if (!info)
2312 return -ENOMEM;
2313
2314 info->segment = pci_domain_nr(pdev->bus);
2315 info->bus = pdev->bus->number;
2316 info->devfn = pdev->devfn;
2317 info->dev = pdev;
2318 info->domain = domain;
2319
2320 spin_lock_irqsave(&device_domain_lock, flags);
2321 list_add(&info->link, &domain->devices);
2322 list_add(&info->global, &device_domain_list);
2323 pdev->dev.archdata.iommu = info;
2324 spin_unlock_irqrestore(&device_domain_lock, flags);
2325
David Woodhousee2ad23d2012-05-25 17:42:54 +01002326 ret = domain_context_mapping(domain, pdev, translation);
2327 if (ret) {
2328 spin_lock_irqsave(&device_domain_lock, flags);
David Woodhouse109b9b02012-05-25 17:43:02 +01002329 unlink_domain_info(info);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002330 spin_unlock_irqrestore(&device_domain_lock, flags);
2331 free_devinfo_mem(info);
2332 return ret;
2333 }
2334
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002335 return 0;
2336}
2337
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002338static bool device_has_rmrr(struct pci_dev *dev)
2339{
2340 struct dmar_rmrr_unit *rmrr;
2341 int i;
2342
2343 for_each_rmrr_units(rmrr) {
2344 for (i = 0; i < rmrr->devices_cnt; i++) {
2345 /*
2346 * Return TRUE if this RMRR contains the device that
2347 * is passed in.
2348 */
2349 if (rmrr->devices[i] == dev)
2350 return true;
2351 }
2352 }
2353 return false;
2354}
2355
David Woodhouse6941af22009-07-04 18:24:27 +01002356static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2357{
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002358
2359 /*
2360 * We want to prevent any device associated with an RMRR from
2361 * getting placed into the SI Domain. This is done because
2362 * problems exist when devices are moved in and out of domains
2363 * and their respective RMRR info is lost. We exempt USB devices
2364 * from this process due to their usage of RMRRs that are known
2365 * to not be needed after BIOS hand-off to OS.
2366 */
2367 if (device_has_rmrr(pdev) &&
2368 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2369 return 0;
2370
David Woodhousee0fc7e02009-09-30 09:12:17 -07002371 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2372 return 1;
2373
2374 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2375 return 1;
2376
2377 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2378 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002379
David Woodhouse3dfc8132009-07-04 19:11:08 +01002380 /*
2381 * We want to start off with all devices in the 1:1 domain, and
2382 * take them out later if we find they can't access all of memory.
2383 *
2384 * However, we can't do this for PCI devices behind bridges,
2385 * because all PCI devices behind the same bridge will end up
2386 * with the same source-id on their transactions.
2387 *
2388 * Practically speaking, we can't change things around for these
2389 * devices at run-time, because we can't be sure there'll be no
2390 * DMA transactions in flight for any of their siblings.
2391 *
2392 * So PCI devices (unless they're on the root bus) as well as
2393 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2394 * the 1:1 domain, just in _case_ one of their siblings turns out
2395 * not to be able to map all of memory.
2396 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002397 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002398 if (!pci_is_root_bus(pdev->bus))
2399 return 0;
2400 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2401 return 0;
Yijing Wang62f87c02012-07-24 17:20:03 +08002402 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
David Woodhouse3dfc8132009-07-04 19:11:08 +01002403 return 0;
2404
2405 /*
2406 * At boot time, we don't yet know if devices will be 64-bit capable.
2407 * Assume that they will -- if they turn out not to be, then we can
2408 * take them out of the 1:1 domain later.
2409 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002410 if (!startup) {
2411 /*
2412 * If the device's dma_mask is less than the system's memory
2413 * size then this is not a candidate for identity mapping.
2414 */
2415 u64 dma_mask = pdev->dma_mask;
2416
2417 if (pdev->dev.coherent_dma_mask &&
2418 pdev->dev.coherent_dma_mask < dma_mask)
2419 dma_mask = pdev->dev.coherent_dma_mask;
2420
2421 return dma_mask >= dma_get_required_mask(&pdev->dev);
2422 }
David Woodhouse6941af22009-07-04 18:24:27 +01002423
2424 return 1;
2425}
2426
Matt Kraai071e1372009-08-23 22:30:22 -07002427static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002428{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002429 struct pci_dev *pdev = NULL;
2430 int ret;
2431
David Woodhouse19943b02009-08-04 16:19:20 +01002432 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002433 if (ret)
2434 return -EFAULT;
2435
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002436 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002437 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002438 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002439 hw ? CONTEXT_TT_PASS_THROUGH :
2440 CONTEXT_TT_MULTI_LEVEL);
2441 if (ret) {
2442 /* device not associated with an iommu */
2443 if (ret == -ENODEV)
2444 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002445 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002446 }
2447 pr_info("IOMMU: %s identity mapping for device %s\n",
2448 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002449 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002450 }
2451
2452 return 0;
2453}
2454
Joseph Cihulab7792602011-05-03 00:08:37 -07002455static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002456{
2457 struct dmar_drhd_unit *drhd;
2458 struct dmar_rmrr_unit *rmrr;
2459 struct pci_dev *pdev;
2460 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002461 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002462
2463 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002464 * for each drhd
2465 * allocate root
2466 * initialize and program root entry to not present
2467 * endfor
2468 */
2469 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002470 /*
2471 * lock not needed as this is only incremented in the single
2472 * threaded kernel __init code path all other access are read
2473 * only
2474 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002475 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2476 g_num_of_iommus++;
2477 continue;
2478 }
2479 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2480 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002481 }
2482
Weidong Hand9630fe2008-12-08 11:06:32 +08002483 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2484 GFP_KERNEL);
2485 if (!g_iommus) {
2486 printk(KERN_ERR "Allocating global iommu array failed\n");
2487 ret = -ENOMEM;
2488 goto error;
2489 }
2490
mark gross80b20dd2008-04-18 13:53:58 -07002491 deferred_flush = kzalloc(g_num_of_iommus *
2492 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2493 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002494 ret = -ENOMEM;
2495 goto error;
2496 }
2497
mark gross5e0d2a62008-03-04 15:22:08 -08002498 for_each_drhd_unit(drhd) {
2499 if (drhd->ignored)
2500 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002501
2502 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002503 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002504
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002505 ret = iommu_init_domains(iommu);
2506 if (ret)
2507 goto error;
2508
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002509 /*
2510 * TBD:
2511 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002512 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002513 */
2514 ret = iommu_alloc_root_entry(iommu);
2515 if (ret) {
2516 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2517 goto error;
2518 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002519 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002520 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002521 }
2522
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002523 /*
2524 * Start from the sane iommu hardware state.
2525 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002526 for_each_drhd_unit(drhd) {
2527 if (drhd->ignored)
2528 continue;
2529
2530 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002531
2532 /*
2533 * If the queued invalidation is already initialized by us
2534 * (for example, while enabling interrupt-remapping) then
2535 * we got the things already rolling from a sane state.
2536 */
2537 if (iommu->qi)
2538 continue;
2539
2540 /*
2541 * Clear any previous faults.
2542 */
2543 dmar_fault(-1, iommu);
2544 /*
2545 * Disable queued invalidation if supported and already enabled
2546 * before OS handover.
2547 */
2548 dmar_disable_qi(iommu);
2549 }
2550
2551 for_each_drhd_unit(drhd) {
2552 if (drhd->ignored)
2553 continue;
2554
2555 iommu = drhd->iommu;
2556
Youquan Songa77b67d2008-10-16 16:31:56 -07002557 if (dmar_enable_qi(iommu)) {
2558 /*
2559 * Queued Invalidate not enabled, use Register Based
2560 * Invalidate
2561 */
2562 iommu->flush.flush_context = __iommu_flush_context;
2563 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002564 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002565 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002566 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002567 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002568 } else {
2569 iommu->flush.flush_context = qi_flush_context;
2570 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002571 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002572 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002573 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002574 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002575 }
2576 }
2577
David Woodhouse19943b02009-08-04 16:19:20 +01002578 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002579 iommu_identity_mapping |= IDENTMAP_ALL;
2580
Suresh Siddhad3f13812011-08-23 17:05:25 -07002581#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002582 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002583#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002584
2585 check_tylersburg_isoch();
2586
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002587 /*
2588 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002589 * identity mappings for rmrr, gfx, and isa and may fall back to static
2590 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002591 */
David Woodhouse19943b02009-08-04 16:19:20 +01002592 if (iommu_identity_mapping) {
2593 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2594 if (ret) {
2595 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2596 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002597 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002598 }
David Woodhouse19943b02009-08-04 16:19:20 +01002599 /*
2600 * For each rmrr
2601 * for each dev attached to rmrr
2602 * do
2603 * locate drhd for dev, alloc domain for dev
2604 * allocate free domain
2605 * allocate page table entries for rmrr
2606 * if context not allocated for bus
2607 * allocate and init context
2608 * set present in root table for this bus
2609 * init context with domain, translation etc
2610 * endfor
2611 * endfor
2612 */
2613 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2614 for_each_rmrr_units(rmrr) {
2615 for (i = 0; i < rmrr->devices_cnt; i++) {
2616 pdev = rmrr->devices[i];
2617 /*
2618 * some BIOS lists non-exist devices in DMAR
2619 * table.
2620 */
2621 if (!pdev)
2622 continue;
2623 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2624 if (ret)
2625 printk(KERN_ERR
2626 "IOMMU: mapping reserved region failed\n");
2627 }
2628 }
2629
2630 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002631
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002632 /*
2633 * for each drhd
2634 * enable fault log
2635 * global invalidate context cache
2636 * global invalidate iotlb
2637 * enable translation
2638 */
2639 for_each_drhd_unit(drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002640 if (drhd->ignored) {
2641 /*
2642 * we always have to disable PMRs or DMA may fail on
2643 * this device
2644 */
2645 if (force_on)
2646 iommu_disable_protect_mem_regions(drhd->iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002647 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002648 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002649 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002650
2651 iommu_flush_write_buffer(iommu);
2652
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002653 ret = dmar_set_interrupt(iommu);
2654 if (ret)
2655 goto error;
2656
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002657 iommu_set_root_entry(iommu);
2658
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002659 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002660 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002661
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002662 ret = iommu_enable_translation(iommu);
2663 if (ret)
2664 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002665
2666 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002667 }
2668
2669 return 0;
2670error:
2671 for_each_drhd_unit(drhd) {
2672 if (drhd->ignored)
2673 continue;
2674 iommu = drhd->iommu;
2675 free_iommu(iommu);
2676 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002677 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002678 return ret;
2679}
2680
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002681/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002682static struct iova *intel_alloc_iova(struct device *dev,
2683 struct dmar_domain *domain,
2684 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002685{
2686 struct pci_dev *pdev = to_pci_dev(dev);
2687 struct iova *iova = NULL;
2688
David Woodhouse875764d2009-06-28 21:20:51 +01002689 /* Restrict dma_mask to the width that the iommu can handle */
2690 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2691
2692 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002693 /*
2694 * First try to allocate an io virtual address in
Yang Hongyang284901a92009-04-06 19:01:15 -07002695 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002696 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002697 */
David Woodhouse875764d2009-06-28 21:20:51 +01002698 iova = alloc_iova(&domain->iovad, nrpages,
2699 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2700 if (iova)
2701 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002702 }
David Woodhouse875764d2009-06-28 21:20:51 +01002703 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2704 if (unlikely(!iova)) {
2705 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2706 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002707 return NULL;
2708 }
2709
2710 return iova;
2711}
2712
David Woodhouse147202a2009-07-07 19:43:20 +01002713static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002714{
2715 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002716 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002717
2718 domain = get_domain_for_dev(pdev,
2719 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2720 if (!domain) {
2721 printk(KERN_ERR
2722 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002723 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002724 }
2725
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002726 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002727 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002728 ret = domain_context_mapping(domain, pdev,
2729 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002730 if (ret) {
2731 printk(KERN_ERR
2732 "Domain context map for %s failed",
2733 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002734 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002735 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002736 }
2737
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002738 return domain;
2739}
2740
David Woodhouse147202a2009-07-07 19:43:20 +01002741static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2742{
2743 struct device_domain_info *info;
2744
2745 /* No lock here, assumes no domain exit in normal case */
2746 info = dev->dev.archdata.iommu;
2747 if (likely(info))
2748 return info->domain;
2749
2750 return __get_valid_domain_for_dev(dev);
2751}
2752
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002753static int iommu_dummy(struct pci_dev *pdev)
2754{
2755 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2756}
2757
2758/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002759static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002760{
David Woodhouse73676832009-07-04 14:08:36 +01002761 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002762 int found;
2763
Yijing Wangdbad0862013-12-05 19:43:42 +08002764 if (unlikely(!dev_is_pci(dev)))
David Woodhouse73676832009-07-04 14:08:36 +01002765 return 1;
2766
2767 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002768 if (iommu_dummy(pdev))
2769 return 1;
2770
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002771 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002772 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002773
2774 found = identity_mapping(pdev);
2775 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002776 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002777 return 1;
2778 else {
2779 /*
2780 * 32 bit DMA is removed from si_domain and fall back
2781 * to non-identity mapping.
2782 */
2783 domain_remove_one_dev_info(si_domain, pdev);
2784 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2785 pci_name(pdev));
2786 return 0;
2787 }
2788 } else {
2789 /*
2790 * In case of a detached 64 bit DMA device from vm, the device
2791 * is put into si_domain for identity mapping.
2792 */
David Woodhouse6941af22009-07-04 18:24:27 +01002793 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002794 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002795 ret = domain_add_dev_info(si_domain, pdev,
2796 hw_pass_through ?
2797 CONTEXT_TT_PASS_THROUGH :
2798 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002799 if (!ret) {
2800 printk(KERN_INFO "64bit %s uses identity mapping\n",
2801 pci_name(pdev));
2802 return 1;
2803 }
2804 }
2805 }
2806
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002807 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002808}
2809
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002810static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2811 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002812{
2813 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002814 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002815 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002816 struct iova *iova;
2817 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002818 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002819 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002820 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002821
2822 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002823
David Woodhouse73676832009-07-04 14:08:36 +01002824 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002825 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002826
2827 domain = get_valid_domain_for_dev(pdev);
2828 if (!domain)
2829 return 0;
2830
Weidong Han8c11e792008-12-08 15:29:22 +08002831 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002832 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002833
Mike Travisc681d0b2011-05-28 13:15:05 -05002834 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002835 if (!iova)
2836 goto error;
2837
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002838 /*
2839 * Check if DMAR supports zero-length reads on write only
2840 * mappings..
2841 */
2842 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002843 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002844 prot |= DMA_PTE_READ;
2845 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2846 prot |= DMA_PTE_WRITE;
2847 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002848 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002849 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002850 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002851 * is not a big problem
2852 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002853 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002854 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002855 if (ret)
2856 goto error;
2857
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002858 /* it's a non-present to present mapping. Only flush if caching mode */
2859 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002860 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002861 else
Weidong Han8c11e792008-12-08 15:29:22 +08002862 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002863
David Woodhouse03d6a242009-06-28 15:33:46 +01002864 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2865 start_paddr += paddr & ~PAGE_MASK;
2866 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002867
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002868error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002869 if (iova)
2870 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002871 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002872 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002873 return 0;
2874}
2875
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002876static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2877 unsigned long offset, size_t size,
2878 enum dma_data_direction dir,
2879 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002880{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002881 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2882 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002883}
2884
mark gross5e0d2a62008-03-04 15:22:08 -08002885static void flush_unmaps(void)
2886{
mark gross80b20dd2008-04-18 13:53:58 -07002887 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002888
mark gross5e0d2a62008-03-04 15:22:08 -08002889 timer_on = 0;
2890
2891 /* just flush them all */
2892 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002893 struct intel_iommu *iommu = g_iommus[i];
2894 if (!iommu)
2895 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002896
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002897 if (!deferred_flush[i].next)
2898 continue;
2899
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002900 /* In caching mode, global flushes turn emulation expensive */
2901 if (!cap_caching_mode(iommu->cap))
2902 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002903 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002904 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002905 unsigned long mask;
2906 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002907 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002908
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002909 /* On real hardware multiple invalidations are expensive */
2910 if (cap_caching_mode(iommu->cap))
2911 iommu_flush_iotlb_psi(iommu, domain->id,
2912 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2913 else {
2914 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2915 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2916 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2917 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002918 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002919 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002920 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002921 }
2922
mark gross5e0d2a62008-03-04 15:22:08 -08002923 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002924}
2925
2926static void flush_unmaps_timeout(unsigned long data)
2927{
mark gross80b20dd2008-04-18 13:53:58 -07002928 unsigned long flags;
2929
2930 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002931 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002932 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002933}
2934
2935static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2936{
2937 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002938 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002939 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002940
2941 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002942 if (list_size == HIGH_WATER_MARK)
2943 flush_unmaps();
2944
Weidong Han8c11e792008-12-08 15:29:22 +08002945 iommu = domain_get_iommu(dom);
2946 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002947
mark gross80b20dd2008-04-18 13:53:58 -07002948 next = deferred_flush[iommu_id].next;
2949 deferred_flush[iommu_id].domain[next] = dom;
2950 deferred_flush[iommu_id].iova[next] = iova;
2951 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002952
2953 if (!timer_on) {
2954 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2955 timer_on = 1;
2956 }
2957 list_size++;
2958 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2959}
2960
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002961static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2962 size_t size, enum dma_data_direction dir,
2963 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002964{
2965 struct pci_dev *pdev = to_pci_dev(dev);
2966 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002967 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002968 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002969 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002970
David Woodhouse73676832009-07-04 14:08:36 +01002971 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002972 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002973
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002974 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002975 BUG_ON(!domain);
2976
Weidong Han8c11e792008-12-08 15:29:22 +08002977 iommu = domain_get_iommu(domain);
2978
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002979 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002980 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2981 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002982 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002983
David Woodhoused794dc92009-06-28 00:27:49 +01002984 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2985 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002986
David Woodhoused794dc92009-06-28 00:27:49 +01002987 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2988 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002989
2990 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002991 dma_pte_clear_range(domain, start_pfn, last_pfn);
2992
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002993 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002994 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2995
mark gross5e0d2a62008-03-04 15:22:08 -08002996 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002997 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002998 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002999 /* free iova */
3000 __free_iova(&domain->iovad, iova);
3001 } else {
3002 add_unmap(domain, iova);
3003 /*
3004 * queue up the release of the unmap to save the 1/6th of the
3005 * cpu used up by the iotlb flush operation...
3006 */
mark gross5e0d2a62008-03-04 15:22:08 -08003007 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003008}
3009
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003010static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003011 dma_addr_t *dma_handle, gfp_t flags,
3012 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003013{
3014 void *vaddr;
3015 int order;
3016
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003017 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003018 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07003019
3020 if (!iommu_no_mapping(hwdev))
3021 flags &= ~(GFP_DMA | GFP_DMA32);
3022 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
3023 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
3024 flags |= GFP_DMA;
3025 else
3026 flags |= GFP_DMA32;
3027 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003028
3029 vaddr = (void *)__get_free_pages(flags, order);
3030 if (!vaddr)
3031 return NULL;
3032 memset(vaddr, 0, size);
3033
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003034 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
3035 DMA_BIDIRECTIONAL,
3036 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003037 if (*dma_handle)
3038 return vaddr;
3039 free_pages((unsigned long)vaddr, order);
3040 return NULL;
3041}
3042
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003043static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003044 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003045{
3046 int order;
3047
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003048 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003049 order = get_order(size);
3050
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003051 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003052 free_pages((unsigned long)vaddr, order);
3053}
3054
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003055static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3056 int nelems, enum dma_data_direction dir,
3057 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003058{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003059 struct pci_dev *pdev = to_pci_dev(hwdev);
3060 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003061 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003062 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003063 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003064
David Woodhouse73676832009-07-04 14:08:36 +01003065 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003066 return;
3067
3068 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003069 BUG_ON(!domain);
3070
3071 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003072
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003073 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003074 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3075 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003076 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003077
David Woodhoused794dc92009-06-28 00:27:49 +01003078 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3079 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003080
3081 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003082 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003083
David Woodhoused794dc92009-06-28 00:27:49 +01003084 /* free page tables */
3085 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3086
David Woodhouseacea0012009-07-14 01:55:11 +01003087 if (intel_iommu_strict) {
3088 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003089 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003090 /* free iova */
3091 __free_iova(&domain->iovad, iova);
3092 } else {
3093 add_unmap(domain, iova);
3094 /*
3095 * queue up the release of the unmap to save the 1/6th of the
3096 * cpu used up by the iotlb flush operation...
3097 */
3098 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003099}
3100
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003101static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003102 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003103{
3104 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003105 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003106
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003107 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003108 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003109 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003110 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003111 }
3112 return nelems;
3113}
3114
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003115static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3116 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003117{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003118 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003119 struct pci_dev *pdev = to_pci_dev(hwdev);
3120 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003121 size_t size = 0;
3122 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003123 struct iova *iova = NULL;
3124 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003125 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003126 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003127 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003128
3129 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003130 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003131 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003132
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003133 domain = get_valid_domain_for_dev(pdev);
3134 if (!domain)
3135 return 0;
3136
Weidong Han8c11e792008-12-08 15:29:22 +08003137 iommu = domain_get_iommu(domain);
3138
David Woodhouseb536d242009-06-28 14:49:31 +01003139 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003140 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003141
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003142 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3143 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003144 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003145 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003146 return 0;
3147 }
3148
3149 /*
3150 * Check if DMAR supports zero-length reads on write only
3151 * mappings..
3152 */
3153 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003154 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003155 prot |= DMA_PTE_READ;
3156 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3157 prot |= DMA_PTE_WRITE;
3158
David Woodhouseb536d242009-06-28 14:49:31 +01003159 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003160
Fenghua Yuf5329592009-08-04 15:09:37 -07003161 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003162 if (unlikely(ret)) {
3163 /* clear the page */
3164 dma_pte_clear_range(domain, start_vpfn,
3165 start_vpfn + size - 1);
3166 /* free page tables */
3167 dma_pte_free_pagetable(domain, start_vpfn,
3168 start_vpfn + size - 1);
3169 /* free iova */
3170 __free_iova(&domain->iovad, iova);
3171 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003172 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003173
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003174 /* it's a non-present to present mapping. Only flush if caching mode */
3175 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003176 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003177 else
Weidong Han8c11e792008-12-08 15:29:22 +08003178 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003179
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003180 return nelems;
3181}
3182
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003183static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3184{
3185 return !dma_addr;
3186}
3187
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003188struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003189 .alloc = intel_alloc_coherent,
3190 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003191 .map_sg = intel_map_sg,
3192 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003193 .map_page = intel_map_page,
3194 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003195 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003196};
3197
3198static inline int iommu_domain_cache_init(void)
3199{
3200 int ret = 0;
3201
3202 iommu_domain_cache = kmem_cache_create("iommu_domain",
3203 sizeof(struct dmar_domain),
3204 0,
3205 SLAB_HWCACHE_ALIGN,
3206
3207 NULL);
3208 if (!iommu_domain_cache) {
3209 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3210 ret = -ENOMEM;
3211 }
3212
3213 return ret;
3214}
3215
3216static inline int iommu_devinfo_cache_init(void)
3217{
3218 int ret = 0;
3219
3220 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3221 sizeof(struct device_domain_info),
3222 0,
3223 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003224 NULL);
3225 if (!iommu_devinfo_cache) {
3226 printk(KERN_ERR "Couldn't create devinfo cache\n");
3227 ret = -ENOMEM;
3228 }
3229
3230 return ret;
3231}
3232
3233static inline int iommu_iova_cache_init(void)
3234{
3235 int ret = 0;
3236
3237 iommu_iova_cache = kmem_cache_create("iommu_iova",
3238 sizeof(struct iova),
3239 0,
3240 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003241 NULL);
3242 if (!iommu_iova_cache) {
3243 printk(KERN_ERR "Couldn't create iova cache\n");
3244 ret = -ENOMEM;
3245 }
3246
3247 return ret;
3248}
3249
3250static int __init iommu_init_mempool(void)
3251{
3252 int ret;
3253 ret = iommu_iova_cache_init();
3254 if (ret)
3255 return ret;
3256
3257 ret = iommu_domain_cache_init();
3258 if (ret)
3259 goto domain_error;
3260
3261 ret = iommu_devinfo_cache_init();
3262 if (!ret)
3263 return ret;
3264
3265 kmem_cache_destroy(iommu_domain_cache);
3266domain_error:
3267 kmem_cache_destroy(iommu_iova_cache);
3268
3269 return -ENOMEM;
3270}
3271
3272static void __init iommu_exit_mempool(void)
3273{
3274 kmem_cache_destroy(iommu_devinfo_cache);
3275 kmem_cache_destroy(iommu_domain_cache);
3276 kmem_cache_destroy(iommu_iova_cache);
3277
3278}
3279
Dan Williams556ab452010-07-23 15:47:56 -07003280static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3281{
3282 struct dmar_drhd_unit *drhd;
3283 u32 vtbar;
3284 int rc;
3285
3286 /* We know that this device on this chipset has its own IOMMU.
3287 * If we find it under a different IOMMU, then the BIOS is lying
3288 * to us. Hope that the IOMMU for this device is actually
3289 * disabled, and it needs no translation...
3290 */
3291 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3292 if (rc) {
3293 /* "can't" happen */
3294 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3295 return;
3296 }
3297 vtbar &= 0xffff0000;
3298
3299 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3300 drhd = dmar_find_matched_drhd_unit(pdev);
3301 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3302 TAINT_FIRMWARE_WORKAROUND,
3303 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3304 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3305}
3306DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3307
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003308static void __init init_no_remapping_devices(void)
3309{
3310 struct dmar_drhd_unit *drhd;
3311
3312 for_each_drhd_unit(drhd) {
3313 if (!drhd->include_all) {
3314 int i;
3315 for (i = 0; i < drhd->devices_cnt; i++)
3316 if (drhd->devices[i] != NULL)
3317 break;
3318 /* ignore DMAR unit if no pci devices exist */
3319 if (i == drhd->devices_cnt)
3320 drhd->ignored = 1;
3321 }
3322 }
3323
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003324 for_each_drhd_unit(drhd) {
3325 int i;
3326 if (drhd->ignored || drhd->include_all)
3327 continue;
3328
3329 for (i = 0; i < drhd->devices_cnt; i++)
3330 if (drhd->devices[i] &&
David Woodhousec0771df2011-10-14 20:59:46 +01003331 !IS_GFX_DEVICE(drhd->devices[i]))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003332 break;
3333
3334 if (i < drhd->devices_cnt)
3335 continue;
3336
David Woodhousec0771df2011-10-14 20:59:46 +01003337 /* This IOMMU has *only* gfx devices. Either bypass it or
3338 set the gfx_mapped flag, as appropriate */
3339 if (dmar_map_gfx) {
3340 intel_iommu_gfx_mapped = 1;
3341 } else {
3342 drhd->ignored = 1;
3343 for (i = 0; i < drhd->devices_cnt; i++) {
3344 if (!drhd->devices[i])
3345 continue;
3346 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3347 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003348 }
3349 }
3350}
3351
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003352#ifdef CONFIG_SUSPEND
3353static int init_iommu_hw(void)
3354{
3355 struct dmar_drhd_unit *drhd;
3356 struct intel_iommu *iommu = NULL;
3357
3358 for_each_active_iommu(iommu, drhd)
3359 if (iommu->qi)
3360 dmar_reenable_qi(iommu);
3361
Joseph Cihulab7792602011-05-03 00:08:37 -07003362 for_each_iommu(iommu, drhd) {
3363 if (drhd->ignored) {
3364 /*
3365 * we always have to disable PMRs or DMA may fail on
3366 * this device
3367 */
3368 if (force_on)
3369 iommu_disable_protect_mem_regions(iommu);
3370 continue;
3371 }
3372
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003373 iommu_flush_write_buffer(iommu);
3374
3375 iommu_set_root_entry(iommu);
3376
3377 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003378 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003379 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003380 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003381 if (iommu_enable_translation(iommu))
3382 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003383 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003384 }
3385
3386 return 0;
3387}
3388
3389static void iommu_flush_all(void)
3390{
3391 struct dmar_drhd_unit *drhd;
3392 struct intel_iommu *iommu;
3393
3394 for_each_active_iommu(iommu, drhd) {
3395 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003396 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003397 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003398 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003399 }
3400}
3401
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003402static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003403{
3404 struct dmar_drhd_unit *drhd;
3405 struct intel_iommu *iommu = NULL;
3406 unsigned long flag;
3407
3408 for_each_active_iommu(iommu, drhd) {
3409 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3410 GFP_ATOMIC);
3411 if (!iommu->iommu_state)
3412 goto nomem;
3413 }
3414
3415 iommu_flush_all();
3416
3417 for_each_active_iommu(iommu, drhd) {
3418 iommu_disable_translation(iommu);
3419
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003420 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003421
3422 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3423 readl(iommu->reg + DMAR_FECTL_REG);
3424 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3425 readl(iommu->reg + DMAR_FEDATA_REG);
3426 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3427 readl(iommu->reg + DMAR_FEADDR_REG);
3428 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3429 readl(iommu->reg + DMAR_FEUADDR_REG);
3430
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003431 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003432 }
3433 return 0;
3434
3435nomem:
3436 for_each_active_iommu(iommu, drhd)
3437 kfree(iommu->iommu_state);
3438
3439 return -ENOMEM;
3440}
3441
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003442static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003443{
3444 struct dmar_drhd_unit *drhd;
3445 struct intel_iommu *iommu = NULL;
3446 unsigned long flag;
3447
3448 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003449 if (force_on)
3450 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3451 else
3452 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003453 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003454 }
3455
3456 for_each_active_iommu(iommu, drhd) {
3457
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003458 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003459
3460 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3461 iommu->reg + DMAR_FECTL_REG);
3462 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3463 iommu->reg + DMAR_FEDATA_REG);
3464 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3465 iommu->reg + DMAR_FEADDR_REG);
3466 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3467 iommu->reg + DMAR_FEUADDR_REG);
3468
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003469 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003470 }
3471
3472 for_each_active_iommu(iommu, drhd)
3473 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003474}
3475
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003476static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003477 .resume = iommu_resume,
3478 .suspend = iommu_suspend,
3479};
3480
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003481static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003482{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003483 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003484}
3485
3486#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003487static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003488#endif /* CONFIG_PM */
3489
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003490LIST_HEAD(dmar_rmrr_units);
3491
3492static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3493{
3494 list_add(&rmrr->list, &dmar_rmrr_units);
3495}
3496
3497
3498int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3499{
3500 struct acpi_dmar_reserved_memory *rmrr;
3501 struct dmar_rmrr_unit *rmrru;
3502
3503 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3504 if (!rmrru)
3505 return -ENOMEM;
3506
3507 rmrru->hdr = header;
3508 rmrr = (struct acpi_dmar_reserved_memory *)header;
3509 rmrru->base_address = rmrr->base_address;
3510 rmrru->end_address = rmrr->end_address;
3511
3512 dmar_register_rmrr_unit(rmrru);
3513 return 0;
3514}
3515
3516static int __init
3517rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3518{
3519 struct acpi_dmar_reserved_memory *rmrr;
3520 int ret;
3521
3522 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
3523 ret = dmar_parse_dev_scope((void *)(rmrr + 1),
3524 ((void *)rmrr) + rmrr->header.length,
3525 &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
3526
3527 if (ret || (rmrru->devices_cnt == 0)) {
3528 list_del(&rmrru->list);
3529 kfree(rmrru);
3530 }
3531 return ret;
3532}
3533
3534static LIST_HEAD(dmar_atsr_units);
3535
3536int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3537{
3538 struct acpi_dmar_atsr *atsr;
3539 struct dmar_atsr_unit *atsru;
3540
3541 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3542 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3543 if (!atsru)
3544 return -ENOMEM;
3545
3546 atsru->hdr = hdr;
3547 atsru->include_all = atsr->flags & 0x1;
3548
3549 list_add(&atsru->list, &dmar_atsr_units);
3550
3551 return 0;
3552}
3553
3554static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3555{
3556 int rc;
3557 struct acpi_dmar_atsr *atsr;
3558
3559 if (atsru->include_all)
3560 return 0;
3561
3562 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3563 rc = dmar_parse_dev_scope((void *)(atsr + 1),
3564 (void *)atsr + atsr->header.length,
3565 &atsru->devices_cnt, &atsru->devices,
3566 atsr->segment);
3567 if (rc || !atsru->devices_cnt) {
3568 list_del(&atsru->list);
3569 kfree(atsru);
3570 }
3571
3572 return rc;
3573}
3574
3575int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3576{
3577 int i;
3578 struct pci_bus *bus;
3579 struct acpi_dmar_atsr *atsr;
3580 struct dmar_atsr_unit *atsru;
3581
3582 dev = pci_physfn(dev);
3583
3584 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3585 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3586 if (atsr->segment == pci_domain_nr(dev->bus))
3587 goto found;
3588 }
3589
3590 return 0;
3591
3592found:
3593 for (bus = dev->bus; bus; bus = bus->parent) {
3594 struct pci_dev *bridge = bus->self;
3595
3596 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003597 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003598 return 0;
3599
Yijing Wang62f87c02012-07-24 17:20:03 +08003600 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003601 for (i = 0; i < atsru->devices_cnt; i++)
3602 if (atsru->devices[i] == bridge)
3603 return 1;
3604 break;
3605 }
3606 }
3607
3608 if (atsru->include_all)
3609 return 1;
3610
3611 return 0;
3612}
3613
Sergey Senozhatskyc8f369a2011-10-26 18:45:39 +03003614int __init dmar_parse_rmrr_atsr_dev(void)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003615{
3616 struct dmar_rmrr_unit *rmrr, *rmrr_n;
3617 struct dmar_atsr_unit *atsr, *atsr_n;
3618 int ret = 0;
3619
3620 list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
3621 ret = rmrr_parse_dev(rmrr);
3622 if (ret)
3623 return ret;
3624 }
3625
3626 list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
3627 ret = atsr_parse_dev(atsr);
3628 if (ret)
3629 return ret;
3630 }
3631
3632 return ret;
3633}
3634
Fenghua Yu99dcade2009-11-11 07:23:06 -08003635/*
3636 * Here we only respond to action of unbound device from driver.
3637 *
3638 * Added device is not attached to its DMAR domain here yet. That will happen
3639 * when mapping the device to iova.
3640 */
3641static int device_notifier(struct notifier_block *nb,
3642 unsigned long action, void *data)
3643{
3644 struct device *dev = data;
3645 struct pci_dev *pdev = to_pci_dev(dev);
3646 struct dmar_domain *domain;
3647
David Woodhouse44cd6132009-12-02 10:18:30 +00003648 if (iommu_no_mapping(dev))
3649 return 0;
3650
Fenghua Yu99dcade2009-11-11 07:23:06 -08003651 domain = find_domain(pdev);
3652 if (!domain)
3653 return 0;
3654
Alex Williamsona97590e2011-03-04 14:52:16 -07003655 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
Fenghua Yu99dcade2009-11-11 07:23:06 -08003656 domain_remove_one_dev_info(domain, pdev);
3657
Alex Williamsona97590e2011-03-04 14:52:16 -07003658 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3659 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3660 list_empty(&domain->devices))
3661 domain_exit(domain);
3662 }
3663
Fenghua Yu99dcade2009-11-11 07:23:06 -08003664 return 0;
3665}
3666
3667static struct notifier_block device_nb = {
3668 .notifier_call = device_notifier,
3669};
3670
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003671int __init intel_iommu_init(void)
3672{
3673 int ret = 0;
Takao Indoh3a93c842013-04-23 17:35:03 +09003674 struct dmar_drhd_unit *drhd;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003675
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003676 /* VT-d is required for a TXT/tboot launch, so enforce that */
3677 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003678
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003679 if (dmar_table_init()) {
3680 if (force_on)
3681 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003682 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003683 }
3684
Takao Indoh3a93c842013-04-23 17:35:03 +09003685 /*
3686 * Disable translation if already enabled prior to OS handover.
3687 */
3688 for_each_drhd_unit(drhd) {
3689 struct intel_iommu *iommu;
3690
3691 if (drhd->ignored)
3692 continue;
3693
3694 iommu = drhd->iommu;
3695 if (iommu->gcmd & DMA_GCMD_TE)
3696 iommu_disable_translation(iommu);
3697 }
3698
Suresh Siddhac2c72862011-08-23 17:05:19 -07003699 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003700 if (force_on)
3701 panic("tboot: Failed to initialize DMAR device scope\n");
3702 return -ENODEV;
3703 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003704
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003705 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003706 return -ENODEV;
3707
Joseph Cihula51a63e62011-03-21 11:04:24 -07003708 if (iommu_init_mempool()) {
3709 if (force_on)
3710 panic("tboot: Failed to initialize iommu memory\n");
3711 return -ENODEV;
3712 }
3713
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003714 if (list_empty(&dmar_rmrr_units))
3715 printk(KERN_INFO "DMAR: No RMRR found\n");
3716
3717 if (list_empty(&dmar_atsr_units))
3718 printk(KERN_INFO "DMAR: No ATSR found\n");
3719
Joseph Cihula51a63e62011-03-21 11:04:24 -07003720 if (dmar_init_reserved_ranges()) {
3721 if (force_on)
3722 panic("tboot: Failed to reserve iommu ranges\n");
3723 return -ENODEV;
3724 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003725
3726 init_no_remapping_devices();
3727
Joseph Cihulab7792602011-05-03 00:08:37 -07003728 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003729 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003730 if (force_on)
3731 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003732 printk(KERN_ERR "IOMMU: dmar init failed\n");
3733 put_iova_domain(&reserved_iova_list);
3734 iommu_exit_mempool();
3735 return ret;
3736 }
3737 printk(KERN_INFO
3738 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3739
mark gross5e0d2a62008-03-04 15:22:08 -08003740 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003741#ifdef CONFIG_SWIOTLB
3742 swiotlb = 0;
3743#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003744 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003745
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003746 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003747
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003748 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003749
Fenghua Yu99dcade2009-11-11 07:23:06 -08003750 bus_register_notifier(&pci_bus_type, &device_nb);
3751
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003752 intel_iommu_enabled = 1;
3753
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003754 return 0;
3755}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003756
Han, Weidong3199aa62009-02-26 17:31:12 +08003757static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3758 struct pci_dev *pdev)
3759{
3760 struct pci_dev *tmp, *parent;
3761
3762 if (!iommu || !pdev)
3763 return;
3764
3765 /* dependent device detach */
3766 tmp = pci_find_upstream_pcie_bridge(pdev);
3767 /* Secondary interface's bus number and devfn 0 */
3768 if (tmp) {
3769 parent = pdev->bus->self;
3770 while (parent != tmp) {
3771 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01003772 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003773 parent = parent->bus->self;
3774 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003775 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003776 iommu_detach_dev(iommu,
3777 tmp->subordinate->number, 0);
3778 else /* this is a legacy PCI bridge */
David Woodhouse276dbf92009-04-04 01:45:37 +01003779 iommu_detach_dev(iommu, tmp->bus->number,
3780 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003781 }
3782}
3783
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003784static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003785 struct pci_dev *pdev)
3786{
Yijing Wangbca2b912013-10-31 17:26:04 +08003787 struct device_domain_info *info, *tmp;
Weidong Hanc7151a82008-12-08 22:51:37 +08003788 struct intel_iommu *iommu;
3789 unsigned long flags;
3790 int found = 0;
Weidong Hanc7151a82008-12-08 22:51:37 +08003791
David Woodhouse276dbf92009-04-04 01:45:37 +01003792 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3793 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003794 if (!iommu)
3795 return;
3796
3797 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wangbca2b912013-10-31 17:26:04 +08003798 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
Mike Habeck8519dc42011-05-28 13:15:07 -05003799 if (info->segment == pci_domain_nr(pdev->bus) &&
3800 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003801 info->devfn == pdev->devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01003802 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003803 spin_unlock_irqrestore(&device_domain_lock, flags);
3804
Yu Zhao93a23a72009-05-18 13:51:37 +08003805 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003806 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003807 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003808 free_devinfo_mem(info);
3809
3810 spin_lock_irqsave(&device_domain_lock, flags);
3811
3812 if (found)
3813 break;
3814 else
3815 continue;
3816 }
3817
3818 /* if there is no other devices under the same iommu
3819 * owned by this domain, clear this iommu in iommu_bmp
3820 * update iommu count and coherency
3821 */
David Woodhouse276dbf92009-04-04 01:45:37 +01003822 if (iommu == device_to_iommu(info->segment, info->bus,
3823 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003824 found = 1;
3825 }
3826
Roland Dreier3e7abe22011-07-20 06:22:21 -07003827 spin_unlock_irqrestore(&device_domain_lock, flags);
3828
Weidong Hanc7151a82008-12-08 22:51:37 +08003829 if (found == 0) {
3830 unsigned long tmp_flags;
3831 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003832 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003833 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003834 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003835 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003836
Alex Williamson9b4554b2011-05-24 12:19:04 -04003837 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3838 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3839 spin_lock_irqsave(&iommu->lock, tmp_flags);
3840 clear_bit(domain->id, iommu->domain_ids);
3841 iommu->domains[domain->id] = NULL;
3842 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3843 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003844 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003845}
3846
3847static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3848{
3849 struct device_domain_info *info;
3850 struct intel_iommu *iommu;
3851 unsigned long flags1, flags2;
3852
3853 spin_lock_irqsave(&device_domain_lock, flags1);
3854 while (!list_empty(&domain->devices)) {
3855 info = list_entry(domain->devices.next,
3856 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01003857 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003858 spin_unlock_irqrestore(&device_domain_lock, flags1);
3859
Yu Zhao93a23a72009-05-18 13:51:37 +08003860 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01003861 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003862 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003863 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003864
3865 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003866 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003867 */
3868 spin_lock_irqsave(&domain->iommu_lock, flags2);
3869 if (test_and_clear_bit(iommu->seq_id,
Mike Travis1b198bb2012-03-05 15:05:16 -08003870 domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08003871 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003872 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003873 }
3874 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3875
3876 free_devinfo_mem(info);
3877 spin_lock_irqsave(&device_domain_lock, flags1);
3878 }
3879 spin_unlock_irqrestore(&device_domain_lock, flags1);
3880}
3881
Weidong Han5e98c4b2008-12-08 23:03:27 +08003882/* domain id for virtual machine, it won't be set in context */
Jiang Liu18d99162014-01-06 14:18:10 +08003883static atomic_t vm_domid = ATOMIC_INIT(0);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003884
3885static struct dmar_domain *iommu_alloc_vm_domain(void)
3886{
3887 struct dmar_domain *domain;
3888
3889 domain = alloc_domain_mem();
3890 if (!domain)
3891 return NULL;
3892
Jiang Liu18d99162014-01-06 14:18:10 +08003893 domain->id = atomic_inc_return(&vm_domid);
Suresh Siddha4c923d42009-10-02 11:01:24 -07003894 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08003895 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003896 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3897
3898 return domain;
3899}
3900
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003901static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003902{
3903 int adjust_width;
3904
3905 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003906 spin_lock_init(&domain->iommu_lock);
3907
3908 domain_reserve_special_ranges(domain);
3909
3910 /* calculate AGAW */
3911 domain->gaw = guest_width;
3912 adjust_width = guestwidth_to_adjustwidth(guest_width);
3913 domain->agaw = width_to_agaw(adjust_width);
3914
3915 INIT_LIST_HEAD(&domain->devices);
3916
3917 domain->iommu_count = 0;
3918 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003919 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003920 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003921 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003922 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003923
3924 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003925 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003926 if (!domain->pgd)
3927 return -ENOMEM;
3928 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3929 return 0;
3930}
3931
3932static void iommu_free_vm_domain(struct dmar_domain *domain)
3933{
3934 unsigned long flags;
3935 struct dmar_drhd_unit *drhd;
3936 struct intel_iommu *iommu;
3937 unsigned long i;
3938 unsigned long ndomains;
3939
3940 for_each_drhd_unit(drhd) {
3941 if (drhd->ignored)
3942 continue;
3943 iommu = drhd->iommu;
3944
3945 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08003946 for_each_set_bit(i, iommu->domain_ids, ndomains) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003947 if (iommu->domains[i] == domain) {
3948 spin_lock_irqsave(&iommu->lock, flags);
3949 clear_bit(i, iommu->domain_ids);
3950 iommu->domains[i] = NULL;
3951 spin_unlock_irqrestore(&iommu->lock, flags);
3952 break;
3953 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08003954 }
3955 }
3956}
3957
3958static void vm_domain_exit(struct dmar_domain *domain)
3959{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003960 /* Domain 0 is reserved, so dont process it */
3961 if (!domain)
3962 return;
3963
3964 vm_domain_remove_all_dev_info(domain);
3965 /* destroy iovas */
3966 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003967
3968 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003969 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003970
3971 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003972 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003973
3974 iommu_free_vm_domain(domain);
3975 free_domain_mem(domain);
3976}
3977
Joerg Roedel5d450802008-12-03 14:52:32 +01003978static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003979{
Joerg Roedel5d450802008-12-03 14:52:32 +01003980 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003981
Joerg Roedel5d450802008-12-03 14:52:32 +01003982 dmar_domain = iommu_alloc_vm_domain();
3983 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003984 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003985 "intel_iommu_domain_init: dmar_domain == NULL\n");
3986 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003987 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003988 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003989 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003990 "intel_iommu_domain_init() failed\n");
3991 vm_domain_exit(dmar_domain);
3992 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003993 }
Allen Kay8140a952011-10-14 12:32:17 -07003994 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003995 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003996
Joerg Roedel8a0e7152012-01-26 19:40:54 +01003997 domain->geometry.aperture_start = 0;
3998 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
3999 domain->geometry.force_aperture = true;
4000
Joerg Roedel5d450802008-12-03 14:52:32 +01004001 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004002}
Kay, Allen M38717942008-09-09 18:37:29 +03004003
Joerg Roedel5d450802008-12-03 14:52:32 +01004004static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03004005{
Joerg Roedel5d450802008-12-03 14:52:32 +01004006 struct dmar_domain *dmar_domain = domain->priv;
4007
4008 domain->priv = NULL;
4009 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03004010}
Kay, Allen M38717942008-09-09 18:37:29 +03004011
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004012static int intel_iommu_attach_device(struct iommu_domain *domain,
4013 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004014{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004015 struct dmar_domain *dmar_domain = domain->priv;
4016 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004017 struct intel_iommu *iommu;
4018 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03004019
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004020 /* normally pdev is not mapped */
4021 if (unlikely(domain_context_mapped(pdev))) {
4022 struct dmar_domain *old_domain;
4023
4024 old_domain = find_domain(pdev);
4025 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004026 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
4027 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
4028 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004029 else
4030 domain_remove_dev_info(old_domain);
4031 }
4032 }
4033
David Woodhouse276dbf92009-04-04 01:45:37 +01004034 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
4035 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004036 if (!iommu)
4037 return -ENODEV;
4038
4039 /* check if this iommu agaw is sufficient for max mapped address */
4040 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01004041 if (addr_width > cap_mgaw(iommu->cap))
4042 addr_width = cap_mgaw(iommu->cap);
4043
4044 if (dmar_domain->max_addr > (1LL << addr_width)) {
4045 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004046 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01004047 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004048 return -EFAULT;
4049 }
Tom Lyona99c47a2010-05-17 08:20:45 +01004050 dmar_domain->gaw = addr_width;
4051
4052 /*
4053 * Knock out extra levels of page tables if necessary
4054 */
4055 while (iommu->agaw < dmar_domain->agaw) {
4056 struct dma_pte *pte;
4057
4058 pte = dmar_domain->pgd;
4059 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08004060 dmar_domain->pgd = (struct dma_pte *)
4061 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01004062 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01004063 }
4064 dmar_domain->agaw--;
4065 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004066
David Woodhouse5fe60f42009-08-09 10:53:41 +01004067 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004068}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004069
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004070static void intel_iommu_detach_device(struct iommu_domain *domain,
4071 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004072{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004073 struct dmar_domain *dmar_domain = domain->priv;
4074 struct pci_dev *pdev = to_pci_dev(dev);
4075
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004076 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03004077}
Kay, Allen M38717942008-09-09 18:37:29 +03004078
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004079static int intel_iommu_map(struct iommu_domain *domain,
4080 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004081 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03004082{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004083 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004084 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004085 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004086 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004087
Joerg Roedeldde57a22008-12-03 15:04:09 +01004088 if (iommu_prot & IOMMU_READ)
4089 prot |= DMA_PTE_READ;
4090 if (iommu_prot & IOMMU_WRITE)
4091 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08004092 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4093 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004094
David Woodhouse163cc522009-06-28 00:51:17 +01004095 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004096 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004097 u64 end;
4098
4099 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01004100 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004101 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004102 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004103 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004104 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004105 return -EFAULT;
4106 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004107 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004108 }
David Woodhousead051222009-06-28 14:22:28 +01004109 /* Round up size to next multiple of PAGE_SIZE, if it and
4110 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004111 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004112 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4113 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004114 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004115}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004116
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004117static size_t intel_iommu_unmap(struct iommu_domain *domain,
4118 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004119{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004120 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07004121 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01004122
Allen Kay292827c2011-10-14 12:31:54 -07004123 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004124 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004125
David Woodhouse163cc522009-06-28 00:51:17 +01004126 if (dmar_domain->max_addr == iova + size)
4127 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004128
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004129 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004130}
Kay, Allen M38717942008-09-09 18:37:29 +03004131
Joerg Roedeld14d6572008-12-03 15:06:57 +01004132static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
Varun Sethibb5547ac2013-03-29 01:23:58 +05304133 dma_addr_t iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004134{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004135 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004136 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004137 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004138
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004139 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004140 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004141 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004142
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004143 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004144}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004145
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004146static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4147 unsigned long cap)
4148{
4149 struct dmar_domain *dmar_domain = domain->priv;
4150
4151 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4152 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004153 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004154 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004155
4156 return 0;
4157}
4158
Alex Williamson783f1572012-05-30 14:19:43 -06004159#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4160
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004161static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004162{
4163 struct pci_dev *pdev = to_pci_dev(dev);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004164 struct pci_dev *bridge, *dma_pdev = NULL;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004165 struct iommu_group *group;
4166 int ret;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004167
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004168 if (!device_to_iommu(pci_domain_nr(pdev->bus),
4169 pdev->bus->number, pdev->devfn))
Alex Williamson70ae6f02011-10-21 15:56:11 -04004170 return -ENODEV;
4171
4172 bridge = pci_find_upstream_pcie_bridge(pdev);
4173 if (bridge) {
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004174 if (pci_is_pcie(bridge))
4175 dma_pdev = pci_get_domain_bus_and_slot(
4176 pci_domain_nr(pdev->bus),
4177 bridge->subordinate->number, 0);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004178 if (!dma_pdev)
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004179 dma_pdev = pci_dev_get(bridge);
4180 } else
4181 dma_pdev = pci_dev_get(pdev);
4182
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004183 /* Account for quirked devices */
Alex Williamson783f1572012-05-30 14:19:43 -06004184 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4185
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004186 /*
4187 * If it's a multifunction device that does not support our
Alex Williamsonc14d2692013-05-30 12:39:18 -06004188 * required ACS flags, add to the same group as lowest numbered
4189 * function that also does not suport the required ACS flags.
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004190 */
Alex Williamson783f1572012-05-30 14:19:43 -06004191 if (dma_pdev->multifunction &&
Alex Williamsonc14d2692013-05-30 12:39:18 -06004192 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
4193 u8 i, slot = PCI_SLOT(dma_pdev->devfn);
4194
4195 for (i = 0; i < 8; i++) {
4196 struct pci_dev *tmp;
4197
4198 tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
4199 if (!tmp)
4200 continue;
4201
4202 if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
4203 swap_pci_ref(&dma_pdev, tmp);
4204 break;
4205 }
4206 pci_dev_put(tmp);
4207 }
4208 }
Alex Williamson783f1572012-05-30 14:19:43 -06004209
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004210 /*
4211 * Devices on the root bus go through the iommu. If that's not us,
4212 * find the next upstream device and test ACS up to the root bus.
4213 * Finding the next device may require skipping virtual buses.
4214 */
Alex Williamson783f1572012-05-30 14:19:43 -06004215 while (!pci_is_root_bus(dma_pdev->bus)) {
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004216 struct pci_bus *bus = dma_pdev->bus;
4217
4218 while (!bus->self) {
4219 if (!pci_is_root_bus(bus))
4220 bus = bus->parent;
4221 else
4222 goto root_bus;
4223 }
4224
4225 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
Alex Williamson783f1572012-05-30 14:19:43 -06004226 break;
4227
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004228 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
Alex Williamson70ae6f02011-10-21 15:56:11 -04004229 }
4230
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004231root_bus:
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004232 group = iommu_group_get(&dma_pdev->dev);
4233 pci_dev_put(dma_pdev);
4234 if (!group) {
4235 group = iommu_group_alloc();
4236 if (IS_ERR(group))
4237 return PTR_ERR(group);
4238 }
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004239
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004240 ret = iommu_group_add_device(group, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004241
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004242 iommu_group_put(group);
4243 return ret;
4244}
4245
4246static void intel_iommu_remove_device(struct device *dev)
4247{
4248 iommu_group_remove_device(dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004249}
4250
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004251static struct iommu_ops intel_iommu_ops = {
4252 .domain_init = intel_iommu_domain_init,
4253 .domain_destroy = intel_iommu_domain_destroy,
4254 .attach_dev = intel_iommu_attach_device,
4255 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004256 .map = intel_iommu_map,
4257 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004258 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004259 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004260 .add_device = intel_iommu_add_device,
4261 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004262 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004263};
David Woodhouse9af88142009-02-13 23:18:03 +00004264
Daniel Vetter94526182013-01-20 23:50:13 +01004265static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4266{
4267 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4268 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4269 dmar_map_gfx = 0;
4270}
4271
4272DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4273DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4274DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4275DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4276DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4277DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4278DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4279
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004280static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004281{
4282 /*
4283 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004284 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004285 */
4286 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4287 rwbf_quirk = 1;
4288}
4289
4290DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004291DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4292DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4293DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4294DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4295DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4296DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004297
Adam Jacksoneecfd572010-08-25 21:17:34 +01004298#define GGC 0x52
4299#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4300#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4301#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4302#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4303#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4304#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4305#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4306#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4307
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004308static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004309{
4310 unsigned short ggc;
4311
Adam Jacksoneecfd572010-08-25 21:17:34 +01004312 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004313 return;
4314
Adam Jacksoneecfd572010-08-25 21:17:34 +01004315 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004316 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4317 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004318 } else if (dmar_map_gfx) {
4319 /* we have to ensure the gfx device is idle before we flush */
4320 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4321 intel_iommu_strict = 1;
4322 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004323}
4324DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4325DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4326DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4327DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4328
David Woodhousee0fc7e02009-09-30 09:12:17 -07004329/* On Tylersburg chipsets, some BIOSes have been known to enable the
4330 ISOCH DMAR unit for the Azalia sound device, but not give it any
4331 TLB entries, which causes it to deadlock. Check for that. We do
4332 this in a function called from init_dmars(), instead of in a PCI
4333 quirk, because we don't want to print the obnoxious "BIOS broken"
4334 message if VT-d is actually disabled.
4335*/
4336static void __init check_tylersburg_isoch(void)
4337{
4338 struct pci_dev *pdev;
4339 uint32_t vtisochctrl;
4340
4341 /* If there's no Azalia in the system anyway, forget it. */
4342 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4343 if (!pdev)
4344 return;
4345 pci_dev_put(pdev);
4346
4347 /* System Management Registers. Might be hidden, in which case
4348 we can't do the sanity check. But that's OK, because the
4349 known-broken BIOSes _don't_ actually hide it, so far. */
4350 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4351 if (!pdev)
4352 return;
4353
4354 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4355 pci_dev_put(pdev);
4356 return;
4357 }
4358
4359 pci_dev_put(pdev);
4360
4361 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4362 if (vtisochctrl & 1)
4363 return;
4364
4365 /* Drop all bits other than the number of TLB entries */
4366 vtisochctrl &= 0x1c;
4367
4368 /* If we have the recommended number of TLB entries (16), fine. */
4369 if (vtisochctrl == 0x10)
4370 return;
4371
4372 /* Zero TLB entries? You get to ride the short bus to school. */
4373 if (!vtisochctrl) {
4374 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4375 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4376 dmi_get_system_info(DMI_BIOS_VENDOR),
4377 dmi_get_system_info(DMI_BIOS_VERSION),
4378 dmi_get_system_info(DMI_PRODUCT_VERSION));
4379 iommu_identity_mapping |= IDENTMAP_AZALIA;
4380 return;
4381 }
4382
4383 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4384 vtisochctrl);
4385}