blob: 414d2d20dd59ae0560d3f7a2251eff6e78633ac7 [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"
50
Fenghua Yu5b6985c2008-10-16 18:02:32 -070051#define ROOT_SIZE VTD_PAGE_SIZE
52#define CONTEXT_SIZE VTD_PAGE_SIZE
53
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070054#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
55#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070056#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070057
58#define IOAPIC_RANGE_START (0xfee00000)
59#define IOAPIC_RANGE_END (0xfeefffff)
60#define IOVA_START_ADDR (0x1000)
61
62#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
63
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070064#define MAX_AGAW_WIDTH 64
65
David Woodhouse2ebe3152009-09-19 07:34:04 -070066#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
67#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
68
69/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
70 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
71#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
72 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
73#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070074
Mark McLoughlinf27be032008-11-20 15:49:43 +000075#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070076#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070077#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080078
Andrew Mortondf08cdc2010-09-22 13:05:11 -070079/* page table handling */
80#define LEVEL_STRIDE (9)
81#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
82
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +020083/*
84 * This bitmap is used to advertise the page sizes our hardware support
85 * to the IOMMU core, which will then use this information to split
86 * physically contiguous memory regions it is mapping into page sizes
87 * that we support.
88 *
89 * Traditionally the IOMMU core just handed us the mappings directly,
90 * after making sure the size is an order of a 4KiB page and that the
91 * mapping has natural alignment.
92 *
93 * To retain this behavior, we currently advertise that we support
94 * all page sizes that are an order of 4KiB.
95 *
96 * If at some point we'd like to utilize the IOMMU core's new behavior,
97 * we could change this to advertise the real page sizes we support.
98 */
99#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
100
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700101static inline int agaw_to_level(int agaw)
102{
103 return agaw + 2;
104}
105
106static inline int agaw_to_width(int agaw)
107{
108 return 30 + agaw * LEVEL_STRIDE;
109}
110
111static inline int width_to_agaw(int width)
112{
113 return (width - 30) / LEVEL_STRIDE;
114}
115
116static inline unsigned int level_to_offset_bits(int level)
117{
118 return (level - 1) * LEVEL_STRIDE;
119}
120
121static inline int pfn_level_offset(unsigned long pfn, int level)
122{
123 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
124}
125
126static inline unsigned long level_mask(int level)
127{
128 return -1UL << level_to_offset_bits(level);
129}
130
131static inline unsigned long level_size(int level)
132{
133 return 1UL << level_to_offset_bits(level);
134}
135
136static inline unsigned long align_to_level(unsigned long pfn, int level)
137{
138 return (pfn + level_size(level) - 1) & level_mask(level);
139}
David Woodhousefd18de52009-05-10 23:57:41 +0100140
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100141static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
142{
143 return 1 << ((lvl - 1) * LEVEL_STRIDE);
144}
145
David Woodhousedd4e8312009-06-27 16:21:20 +0100146/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
147 are never going to work. */
148static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
149{
150 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
151}
152
153static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
154{
155 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
156}
157static inline unsigned long page_to_dma_pfn(struct page *pg)
158{
159 return mm_to_dma_pfn(page_to_pfn(pg));
160}
161static inline unsigned long virt_to_dma_pfn(void *p)
162{
163 return page_to_dma_pfn(virt_to_page(p));
164}
165
Weidong Hand9630fe2008-12-08 11:06:32 +0800166/* global iommu list, set NULL for ignored DMAR units */
167static struct intel_iommu **g_iommus;
168
David Woodhousee0fc7e02009-09-30 09:12:17 -0700169static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000170static int rwbf_quirk;
171
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000172/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700173 * set to 1 to panic kernel if can't successfully enable VT-d
174 * (used when kernel is launched w/ TXT)
175 */
176static int force_on = 0;
177
178/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000179 * 0: Present
180 * 1-11: Reserved
181 * 12-63: Context Ptr (12 - (haw-1))
182 * 64-127: Reserved
183 */
184struct root_entry {
185 u64 val;
186 u64 rsvd1;
187};
188#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
189static inline bool root_present(struct root_entry *root)
190{
191 return (root->val & 1);
192}
193static inline void set_root_present(struct root_entry *root)
194{
195 root->val |= 1;
196}
197static inline void set_root_value(struct root_entry *root, unsigned long value)
198{
199 root->val |= value & VTD_PAGE_MASK;
200}
201
202static inline struct context_entry *
203get_context_addr_from_root(struct root_entry *root)
204{
205 return (struct context_entry *)
206 (root_present(root)?phys_to_virt(
207 root->val & VTD_PAGE_MASK) :
208 NULL);
209}
210
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000211/*
212 * low 64 bits:
213 * 0: present
214 * 1: fault processing disable
215 * 2-3: translation type
216 * 12-63: address space root
217 * high 64 bits:
218 * 0-2: address width
219 * 3-6: aval
220 * 8-23: domain id
221 */
222struct context_entry {
223 u64 lo;
224 u64 hi;
225};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000226
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000227static inline bool context_present(struct context_entry *context)
228{
229 return (context->lo & 1);
230}
231static inline void context_set_present(struct context_entry *context)
232{
233 context->lo |= 1;
234}
235
236static inline void context_set_fault_enable(struct context_entry *context)
237{
238 context->lo &= (((u64)-1) << 2) | 1;
239}
240
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000241static inline void context_set_translation_type(struct context_entry *context,
242 unsigned long value)
243{
244 context->lo &= (((u64)-1) << 4) | 3;
245 context->lo |= (value & 3) << 2;
246}
247
248static inline void context_set_address_root(struct context_entry *context,
249 unsigned long value)
250{
251 context->lo |= value & VTD_PAGE_MASK;
252}
253
254static inline void context_set_address_width(struct context_entry *context,
255 unsigned long value)
256{
257 context->hi |= value & 7;
258}
259
260static inline void context_set_domain_id(struct context_entry *context,
261 unsigned long value)
262{
263 context->hi |= (value & ((1 << 16) - 1)) << 8;
264}
265
266static inline void context_clear_entry(struct context_entry *context)
267{
268 context->lo = 0;
269 context->hi = 0;
270}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000271
Mark McLoughlin622ba122008-11-20 15:49:46 +0000272/*
273 * 0: readable
274 * 1: writable
275 * 2-6: reserved
276 * 7: super page
Sheng Yang9cf06692009-03-18 15:33:07 +0800277 * 8-10: available
278 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000279 * 12-63: Host physcial address
280 */
281struct dma_pte {
282 u64 val;
283};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000284
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000285static inline void dma_clear_pte(struct dma_pte *pte)
286{
287 pte->val = 0;
288}
289
290static inline void dma_set_pte_readable(struct dma_pte *pte)
291{
292 pte->val |= DMA_PTE_READ;
293}
294
295static inline void dma_set_pte_writable(struct dma_pte *pte)
296{
297 pte->val |= DMA_PTE_WRITE;
298}
299
Sheng Yang9cf06692009-03-18 15:33:07 +0800300static inline void dma_set_pte_snp(struct dma_pte *pte)
301{
302 pte->val |= DMA_PTE_SNP;
303}
304
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000305static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
306{
307 pte->val = (pte->val & ~3) | (prot & 3);
308}
309
310static inline u64 dma_pte_addr(struct dma_pte *pte)
311{
David Woodhousec85994e2009-07-01 19:21:24 +0100312#ifdef CONFIG_64BIT
313 return pte->val & VTD_PAGE_MASK;
314#else
315 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100316 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100317#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000318}
319
David Woodhousedd4e8312009-06-27 16:21:20 +0100320static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000321{
David Woodhousedd4e8312009-06-27 16:21:20 +0100322 pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000323}
324
325static inline bool dma_pte_present(struct dma_pte *pte)
326{
327 return (pte->val & 3) != 0;
328}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000329
Allen Kay4399c8b2011-10-14 12:32:46 -0700330static inline bool dma_pte_superpage(struct dma_pte *pte)
331{
332 return (pte->val & (1 << 7));
333}
334
David Woodhouse75e6bf92009-07-02 11:21:16 +0100335static inline int first_pte_in_page(struct dma_pte *pte)
336{
337 return !((unsigned long)pte & ~VTD_PAGE_MASK);
338}
339
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700340/*
341 * This domain is a statically identity mapping domain.
342 * 1. This domain creats a static 1:1 mapping to all usable memory.
343 * 2. It maps to each iommu if successful.
344 * 3. Each iommu mapps to this domain if successful.
345 */
David Woodhouse19943b02009-08-04 16:19:20 +0100346static struct dmar_domain *si_domain;
347static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700348
Weidong Han3b5410e2008-12-08 09:17:15 +0800349/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100350#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800351
Weidong Han1ce28fe2008-12-08 16:35:39 +0800352/* domain represents a virtual machine, more than one devices
353 * across iommus may be owned in one domain, e.g. kvm guest.
354 */
355#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
356
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700357/* si_domain contains mulitple devices */
358#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
359
Mike Travis1b198bb2012-03-05 15:05:16 -0800360/* define the limit of IOMMUs supported in each domain */
361#ifdef CONFIG_X86
362# define IOMMU_UNITS_SUPPORTED MAX_IO_APICS
363#else
364# define IOMMU_UNITS_SUPPORTED 64
365#endif
366
Mark McLoughlin99126f72008-11-20 15:49:47 +0000367struct dmar_domain {
368 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700369 int nid; /* node id */
Mike Travis1b198bb2012-03-05 15:05:16 -0800370 DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
371 /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000372
373 struct list_head devices; /* all devices' list */
374 struct iova_domain iovad; /* iova's that belong to this domain */
375
376 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000377 int gaw; /* max guest address width */
378
379 /* adjusted guest address width, 0 is level 2 30-bit */
380 int agaw;
381
Weidong Han3b5410e2008-12-08 09:17:15 +0800382 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800383
384 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800385 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800386 int iommu_count; /* reference count of iommu */
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100387 int iommu_superpage;/* Level of superpages supported:
388 0 == 4KiB (no superpages), 1 == 2MiB,
389 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
Weidong Hanc7151a82008-12-08 22:51:37 +0800390 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800391 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000392};
393
Mark McLoughlina647dac2008-11-20 15:49:48 +0000394/* PCI domain-device relationship */
395struct device_domain_info {
396 struct list_head link; /* link to domain siblings */
397 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100398 int segment; /* PCI domain */
399 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000400 u8 devfn; /* PCI devfn number */
Stefan Assmann45e829e2009-12-03 06:49:24 -0500401 struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800402 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000403 struct dmar_domain *domain; /* pointer to domain */
404};
405
mark gross5e0d2a62008-03-04 15:22:08 -0800406static void flush_unmaps_timeout(unsigned long data);
407
408DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
409
mark gross80b20dd2008-04-18 13:53:58 -0700410#define HIGH_WATER_MARK 250
411struct deferred_flush_tables {
412 int next;
413 struct iova *iova[HIGH_WATER_MARK];
414 struct dmar_domain *domain[HIGH_WATER_MARK];
415};
416
417static struct deferred_flush_tables *deferred_flush;
418
mark gross5e0d2a62008-03-04 15:22:08 -0800419/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800420static int g_num_of_iommus;
421
422static DEFINE_SPINLOCK(async_umap_flush_lock);
423static LIST_HEAD(unmaps_to_do);
424
425static int timer_on;
426static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800427
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700428static void domain_remove_dev_info(struct dmar_domain *domain);
429
Suresh Siddhad3f13812011-08-23 17:05:25 -0700430#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800431int dmar_disabled = 0;
432#else
433int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700434#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800435
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200436int intel_iommu_enabled = 0;
437EXPORT_SYMBOL_GPL(intel_iommu_enabled);
438
David Woodhouse2d9e6672010-06-15 10:57:57 +0100439static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700440static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800441static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100442static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700443
David Woodhousec0771df2011-10-14 20:59:46 +0100444int intel_iommu_gfx_mapped;
445EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
446
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700447#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
448static DEFINE_SPINLOCK(device_domain_lock);
449static LIST_HEAD(device_domain_list);
450
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100451static struct iommu_ops intel_iommu_ops;
452
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700453static int __init intel_iommu_setup(char *str)
454{
455 if (!str)
456 return -EINVAL;
457 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800458 if (!strncmp(str, "on", 2)) {
459 dmar_disabled = 0;
460 printk(KERN_INFO "Intel-IOMMU: enabled\n");
461 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700462 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800463 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700464 } else if (!strncmp(str, "igfx_off", 8)) {
465 dmar_map_gfx = 0;
466 printk(KERN_INFO
467 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700468 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800469 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700470 "Intel-IOMMU: Forcing DAC for PCI devices\n");
471 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800472 } else if (!strncmp(str, "strict", 6)) {
473 printk(KERN_INFO
474 "Intel-IOMMU: disable batched IOTLB flush\n");
475 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100476 } else if (!strncmp(str, "sp_off", 6)) {
477 printk(KERN_INFO
478 "Intel-IOMMU: disable supported super page\n");
479 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700480 }
481
482 str += strcspn(str, ",");
483 while (*str == ',')
484 str++;
485 }
486 return 0;
487}
488__setup("intel_iommu=", intel_iommu_setup);
489
490static struct kmem_cache *iommu_domain_cache;
491static struct kmem_cache *iommu_devinfo_cache;
492static struct kmem_cache *iommu_iova_cache;
493
Suresh Siddha4c923d42009-10-02 11:01:24 -0700494static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700495{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700496 struct page *page;
497 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700498
Suresh Siddha4c923d42009-10-02 11:01:24 -0700499 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
500 if (page)
501 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700502 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700503}
504
505static inline void free_pgtable_page(void *vaddr)
506{
507 free_page((unsigned long)vaddr);
508}
509
510static inline void *alloc_domain_mem(void)
511{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900512 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700513}
514
Kay, Allen M38717942008-09-09 18:37:29 +0300515static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700516{
517 kmem_cache_free(iommu_domain_cache, vaddr);
518}
519
520static inline void * alloc_devinfo_mem(void)
521{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900522 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700523}
524
525static inline void free_devinfo_mem(void *vaddr)
526{
527 kmem_cache_free(iommu_devinfo_cache, vaddr);
528}
529
530struct iova *alloc_iova_mem(void)
531{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900532 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700533}
534
535void free_iova_mem(struct iova *iova)
536{
537 kmem_cache_free(iommu_iova_cache, iova);
538}
539
Weidong Han1b573682008-12-08 15:34:06 +0800540
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700541static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800542{
543 unsigned long sagaw;
544 int agaw = -1;
545
546 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700547 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800548 agaw >= 0; agaw--) {
549 if (test_bit(agaw, &sagaw))
550 break;
551 }
552
553 return agaw;
554}
555
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700556/*
557 * Calculate max SAGAW for each iommu.
558 */
559int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
560{
561 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
562}
563
564/*
565 * calculate agaw for each iommu.
566 * "SAGAW" may be different across iommus, use a default agaw, and
567 * get a supported less agaw for iommus that don't support the default agaw.
568 */
569int iommu_calculate_agaw(struct intel_iommu *iommu)
570{
571 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
572}
573
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700574/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800575static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
576{
577 int iommu_id;
578
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700579 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800580 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700581 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800582
Mike Travis1b198bb2012-03-05 15:05:16 -0800583 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800584 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
585 return NULL;
586
587 return g_iommus[iommu_id];
588}
589
Weidong Han8e6040972008-12-08 15:49:06 +0800590static void domain_update_iommu_coherency(struct dmar_domain *domain)
591{
592 int i;
593
Alex Williamson2e12bc22011-11-11 17:26:44 -0700594 i = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
595
596 domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0;
Weidong Han8e6040972008-12-08 15:49:06 +0800597
Mike Travis1b198bb2012-03-05 15:05:16 -0800598 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e6040972008-12-08 15:49:06 +0800599 if (!ecap_coherent(g_iommus[i]->ecap)) {
600 domain->iommu_coherency = 0;
601 break;
602 }
Weidong Han8e6040972008-12-08 15:49:06 +0800603 }
604}
605
Sheng Yang58c610b2009-03-18 15:33:05 +0800606static void domain_update_iommu_snooping(struct dmar_domain *domain)
607{
608 int i;
609
610 domain->iommu_snooping = 1;
611
Mike Travis1b198bb2012-03-05 15:05:16 -0800612 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800613 if (!ecap_sc_support(g_iommus[i]->ecap)) {
614 domain->iommu_snooping = 0;
615 break;
616 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800617 }
618}
619
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100620static void domain_update_iommu_superpage(struct dmar_domain *domain)
621{
Allen Kay8140a952011-10-14 12:32:17 -0700622 struct dmar_drhd_unit *drhd;
623 struct intel_iommu *iommu = NULL;
624 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100625
626 if (!intel_iommu_superpage) {
627 domain->iommu_superpage = 0;
628 return;
629 }
630
Allen Kay8140a952011-10-14 12:32:17 -0700631 /* set iommu_superpage to the smallest common denominator */
632 for_each_active_iommu(iommu, drhd) {
633 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100634 if (!mask) {
635 break;
636 }
637 }
638 domain->iommu_superpage = fls(mask);
639}
640
Sheng Yang58c610b2009-03-18 15:33:05 +0800641/* Some capabilities may be different across iommus */
642static void domain_update_iommu_cap(struct dmar_domain *domain)
643{
644 domain_update_iommu_coherency(domain);
645 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100646 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800647}
648
David Woodhouse276dbf992009-04-04 01:45:37 +0100649static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800650{
651 struct dmar_drhd_unit *drhd = NULL;
652 int i;
653
654 for_each_drhd_unit(drhd) {
655 if (drhd->ignored)
656 continue;
David Woodhouse276dbf992009-04-04 01:45:37 +0100657 if (segment != drhd->segment)
658 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800659
David Woodhouse924b6232009-04-04 00:39:25 +0100660 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000661 if (drhd->devices[i] &&
662 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800663 drhd->devices[i]->devfn == devfn)
664 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700665 if (drhd->devices[i] &&
666 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100667 drhd->devices[i]->subordinate->number <= bus &&
Yinghai Lub918c622012-05-17 18:51:11 -0700668 drhd->devices[i]->subordinate->busn_res.end >= bus)
David Woodhouse924b6232009-04-04 00:39:25 +0100669 return drhd->iommu;
670 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800671
672 if (drhd->include_all)
673 return drhd->iommu;
674 }
675
676 return NULL;
677}
678
Weidong Han5331fe62008-12-08 23:00:00 +0800679static void domain_flush_cache(struct dmar_domain *domain,
680 void *addr, int size)
681{
682 if (!domain->iommu_coherency)
683 clflush_cache_range(addr, size);
684}
685
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700686/* Gets context entry for a given bus and devfn */
687static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
688 u8 bus, u8 devfn)
689{
690 struct root_entry *root;
691 struct context_entry *context;
692 unsigned long phy_addr;
693 unsigned long flags;
694
695 spin_lock_irqsave(&iommu->lock, flags);
696 root = &iommu->root_entry[bus];
697 context = get_context_addr_from_root(root);
698 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700699 context = (struct context_entry *)
700 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700701 if (!context) {
702 spin_unlock_irqrestore(&iommu->lock, flags);
703 return NULL;
704 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700705 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700706 phy_addr = virt_to_phys((void *)context);
707 set_root_value(root, phy_addr);
708 set_root_present(root);
709 __iommu_flush_cache(iommu, root, sizeof(*root));
710 }
711 spin_unlock_irqrestore(&iommu->lock, flags);
712 return &context[devfn];
713}
714
715static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
716{
717 struct root_entry *root;
718 struct context_entry *context;
719 int ret;
720 unsigned long flags;
721
722 spin_lock_irqsave(&iommu->lock, flags);
723 root = &iommu->root_entry[bus];
724 context = get_context_addr_from_root(root);
725 if (!context) {
726 ret = 0;
727 goto out;
728 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000729 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700730out:
731 spin_unlock_irqrestore(&iommu->lock, flags);
732 return ret;
733}
734
735static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
736{
737 struct root_entry *root;
738 struct context_entry *context;
739 unsigned long flags;
740
741 spin_lock_irqsave(&iommu->lock, flags);
742 root = &iommu->root_entry[bus];
743 context = get_context_addr_from_root(root);
744 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000745 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700746 __iommu_flush_cache(iommu, &context[devfn], \
747 sizeof(*context));
748 }
749 spin_unlock_irqrestore(&iommu->lock, flags);
750}
751
752static void free_context_table(struct intel_iommu *iommu)
753{
754 struct root_entry *root;
755 int i;
756 unsigned long flags;
757 struct context_entry *context;
758
759 spin_lock_irqsave(&iommu->lock, flags);
760 if (!iommu->root_entry) {
761 goto out;
762 }
763 for (i = 0; i < ROOT_ENTRY_NR; i++) {
764 root = &iommu->root_entry[i];
765 context = get_context_addr_from_root(root);
766 if (context)
767 free_pgtable_page(context);
768 }
769 free_pgtable_page(iommu->root_entry);
770 iommu->root_entry = NULL;
771out:
772 spin_unlock_irqrestore(&iommu->lock, flags);
773}
774
David Woodhouseb026fd22009-06-28 10:37:25 +0100775static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
Allen Kay4399c8b2011-10-14 12:32:46 -0700776 unsigned long pfn, int target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700777{
David Woodhouseb026fd22009-06-28 10:37:25 +0100778 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700779 struct dma_pte *parent, *pte = NULL;
780 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700781 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700782
783 BUG_ON(!domain->pgd);
David Woodhouseb026fd22009-06-28 10:37:25 +0100784 BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700785 parent = domain->pgd;
786
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700787 while (level > 0) {
788 void *tmp_page;
789
David Woodhouseb026fd22009-06-28 10:37:25 +0100790 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700791 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700792 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100793 break;
794 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700795 break;
796
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000797 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100798 uint64_t pteval;
799
Suresh Siddha4c923d42009-10-02 11:01:24 -0700800 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700801
David Woodhouse206a73c2009-07-01 19:30:28 +0100802 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700803 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100804
David Woodhousec85994e2009-07-01 19:21:24 +0100805 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400806 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 +0100807 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
808 /* Someone else set it while we were thinking; use theirs. */
809 free_pgtable_page(tmp_page);
810 } else {
811 dma_pte_addr(pte);
812 domain_flush_cache(domain, pte, sizeof(*pte));
813 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700814 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000815 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700816 level--;
817 }
818
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700819 return pte;
820}
821
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100822
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700823/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100824static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
825 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100826 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700827{
828 struct dma_pte *parent, *pte = NULL;
829 int total = agaw_to_level(domain->agaw);
830 int offset;
831
832 parent = domain->pgd;
833 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100834 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700835 pte = &parent[offset];
836 if (level == total)
837 return pte;
838
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100839 if (!dma_pte_present(pte)) {
840 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700841 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100842 }
843
844 if (pte->val & DMA_PTE_LARGE_PAGE) {
845 *large_page = total;
846 return pte;
847 }
848
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000849 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700850 total--;
851 }
852 return NULL;
853}
854
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700855/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700856static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100857 unsigned long start_pfn,
858 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700859{
David Woodhouse04b18e62009-06-27 19:15:01 +0100860 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100861 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100862 struct dma_pte *first_pte, *pte;
Allen Kay292827c2011-10-14 12:31:54 -0700863 int order;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700864
David Woodhouse04b18e62009-06-27 19:15:01 +0100865 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100866 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700867 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100868
David Woodhouse04b18e62009-06-27 19:15:01 +0100869 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700870 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100871 large_page = 1;
872 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100873 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100874 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100875 continue;
876 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100877 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100878 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100879 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100880 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100881 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
882
David Woodhouse310a5ab2009-06-28 18:52:20 +0100883 domain_flush_cache(domain, first_pte,
884 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700885
886 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700887
888 order = (large_page - 1) * 9;
889 return order;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700890}
891
892/* free page table pages. last level pte should already be cleared */
893static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100894 unsigned long start_pfn,
895 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700896{
David Woodhouse6660c632009-06-27 22:41:00 +0100897 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhousef3a0a522009-06-30 03:40:07 +0100898 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700899 int total = agaw_to_level(domain->agaw);
900 int level;
David Woodhouse6660c632009-06-27 22:41:00 +0100901 unsigned long tmp;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100902 int large_page = 2;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700903
David Woodhouse6660c632009-06-27 22:41:00 +0100904 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
905 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700906 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700907
David Woodhousef3a0a522009-06-30 03:40:07 +0100908 /* We don't need lock here; nobody else touches the iova range */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700909 level = 2;
910 while (level <= total) {
David Woodhouse6660c632009-06-27 22:41:00 +0100911 tmp = align_to_level(start_pfn, level);
912
David Woodhousef3a0a522009-06-30 03:40:07 +0100913 /* If we can't even clear one PTE at this level, we're done */
David Woodhouse6660c632009-06-27 22:41:00 +0100914 if (tmp + level_size(level) - 1 > last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700915 return;
916
David Woodhouse59c36282009-09-19 07:36:28 -0700917 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100918 large_page = level;
919 first_pte = pte = dma_pfn_level_pte(domain, tmp, level, &large_page);
920 if (large_page > level)
921 level = large_page + 1;
David Woodhousef3a0a522009-06-30 03:40:07 +0100922 if (!pte) {
923 tmp = align_to_level(tmp + 1, level + 1);
924 continue;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700925 }
David Woodhouse75e6bf92009-07-02 11:21:16 +0100926 do {
David Woodhouse6a43e572009-07-02 12:02:34 +0100927 if (dma_pte_present(pte)) {
928 free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
929 dma_clear_pte(pte);
930 }
David Woodhousef3a0a522009-06-30 03:40:07 +0100931 pte++;
932 tmp += level_size(level);
David Woodhouse75e6bf92009-07-02 11:21:16 +0100933 } while (!first_pte_in_page(pte) &&
934 tmp + level_size(level) - 1 <= last_pfn);
935
David Woodhousef3a0a522009-06-30 03:40:07 +0100936 domain_flush_cache(domain, first_pte,
937 (void *)pte - (void *)first_pte);
938
David Woodhouse59c36282009-09-19 07:36:28 -0700939 } while (tmp && tmp + level_size(level) - 1 <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700940 level++;
941 }
942 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100943 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700944 free_pgtable_page(domain->pgd);
945 domain->pgd = NULL;
946 }
947}
948
949/* iommu handling */
950static int iommu_alloc_root_entry(struct intel_iommu *iommu)
951{
952 struct root_entry *root;
953 unsigned long flags;
954
Suresh Siddha4c923d42009-10-02 11:01:24 -0700955 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700956 if (!root)
957 return -ENOMEM;
958
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700959 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700960
961 spin_lock_irqsave(&iommu->lock, flags);
962 iommu->root_entry = root;
963 spin_unlock_irqrestore(&iommu->lock, flags);
964
965 return 0;
966}
967
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700968static void iommu_set_root_entry(struct intel_iommu *iommu)
969{
970 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100971 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700972 unsigned long flag;
973
974 addr = iommu->root_entry;
975
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200976 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700977 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
978
David Woodhousec416daa2009-05-10 20:30:58 +0100979 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700980
981 /* Make sure hardware complete it */
982 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100983 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700984
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200985 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700986}
987
988static void iommu_flush_write_buffer(struct intel_iommu *iommu)
989{
990 u32 val;
991 unsigned long flag;
992
David Woodhouse9af88142009-02-13 23:18:03 +0000993 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700994 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700995
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200996 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100997 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700998
999 /* Make sure hardware complete it */
1000 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001001 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001002
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001003 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001004}
1005
1006/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001007static void __iommu_flush_context(struct intel_iommu *iommu,
1008 u16 did, u16 source_id, u8 function_mask,
1009 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001010{
1011 u64 val = 0;
1012 unsigned long flag;
1013
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001014 switch (type) {
1015 case DMA_CCMD_GLOBAL_INVL:
1016 val = DMA_CCMD_GLOBAL_INVL;
1017 break;
1018 case DMA_CCMD_DOMAIN_INVL:
1019 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1020 break;
1021 case DMA_CCMD_DEVICE_INVL:
1022 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1023 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1024 break;
1025 default:
1026 BUG();
1027 }
1028 val |= DMA_CCMD_ICC;
1029
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001030 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001031 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1032
1033 /* Make sure hardware complete it */
1034 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1035 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1036
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001037 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001038}
1039
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001040/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001041static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1042 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001043{
1044 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1045 u64 val = 0, val_iva = 0;
1046 unsigned long flag;
1047
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001048 switch (type) {
1049 case DMA_TLB_GLOBAL_FLUSH:
1050 /* global flush doesn't need set IVA_REG */
1051 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1052 break;
1053 case DMA_TLB_DSI_FLUSH:
1054 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1055 break;
1056 case DMA_TLB_PSI_FLUSH:
1057 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1058 /* Note: always flush non-leaf currently */
1059 val_iva = size_order | addr;
1060 break;
1061 default:
1062 BUG();
1063 }
1064 /* Note: set drain read/write */
1065#if 0
1066 /*
1067 * This is probably to be super secure.. Looks like we can
1068 * ignore it without any impact.
1069 */
1070 if (cap_read_drain(iommu->cap))
1071 val |= DMA_TLB_READ_DRAIN;
1072#endif
1073 if (cap_write_drain(iommu->cap))
1074 val |= DMA_TLB_WRITE_DRAIN;
1075
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001076 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001077 /* Note: Only uses first TLB reg currently */
1078 if (val_iva)
1079 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1080 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1081
1082 /* Make sure hardware complete it */
1083 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1084 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1085
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001086 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001087
1088 /* check IOTLB invalidation granularity */
1089 if (DMA_TLB_IAIG(val) == 0)
1090 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1091 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1092 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001093 (unsigned long long)DMA_TLB_IIRG(type),
1094 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001095}
1096
Yu Zhao93a23a72009-05-18 13:51:37 +08001097static struct device_domain_info *iommu_support_dev_iotlb(
1098 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001099{
Yu Zhao93a23a72009-05-18 13:51:37 +08001100 int found = 0;
1101 unsigned long flags;
1102 struct device_domain_info *info;
1103 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1104
1105 if (!ecap_dev_iotlb_support(iommu->ecap))
1106 return NULL;
1107
1108 if (!iommu->qi)
1109 return NULL;
1110
1111 spin_lock_irqsave(&device_domain_lock, flags);
1112 list_for_each_entry(info, &domain->devices, link)
1113 if (info->bus == bus && info->devfn == devfn) {
1114 found = 1;
1115 break;
1116 }
1117 spin_unlock_irqrestore(&device_domain_lock, flags);
1118
1119 if (!found || !info->dev)
1120 return NULL;
1121
1122 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1123 return NULL;
1124
1125 if (!dmar_find_matched_atsr_unit(info->dev))
1126 return NULL;
1127
1128 info->iommu = iommu;
1129
1130 return info;
1131}
1132
1133static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1134{
1135 if (!info)
1136 return;
1137
1138 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1139}
1140
1141static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1142{
1143 if (!info->dev || !pci_ats_enabled(info->dev))
1144 return;
1145
1146 pci_disable_ats(info->dev);
1147}
1148
1149static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1150 u64 addr, unsigned mask)
1151{
1152 u16 sid, qdep;
1153 unsigned long flags;
1154 struct device_domain_info *info;
1155
1156 spin_lock_irqsave(&device_domain_lock, flags);
1157 list_for_each_entry(info, &domain->devices, link) {
1158 if (!info->dev || !pci_ats_enabled(info->dev))
1159 continue;
1160
1161 sid = info->bus << 8 | info->devfn;
1162 qdep = pci_ats_queue_depth(info->dev);
1163 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1164 }
1165 spin_unlock_irqrestore(&device_domain_lock, flags);
1166}
1167
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001168static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001169 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001170{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001171 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001172 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001173
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001174 BUG_ON(pages == 0);
1175
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001176 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001177 * Fallback to domain selective flush if no PSI support or the size is
1178 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001179 * PSI requires page size to be 2 ^ x, and the base address is naturally
1180 * aligned to the size
1181 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001182 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1183 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001184 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001185 else
1186 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1187 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001188
1189 /*
Nadav Amit82653632010-04-01 13:24:40 +03001190 * In caching mode, changes of pages from non-present to present require
1191 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001192 */
Nadav Amit82653632010-04-01 13:24:40 +03001193 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001194 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001195}
1196
mark grossf8bab732008-02-08 04:18:38 -08001197static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1198{
1199 u32 pmen;
1200 unsigned long flags;
1201
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001202 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001203 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1204 pmen &= ~DMA_PMEN_EPM;
1205 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1206
1207 /* wait for the protected region status bit to clear */
1208 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1209 readl, !(pmen & DMA_PMEN_PRS), pmen);
1210
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001211 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001212}
1213
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001214static int iommu_enable_translation(struct intel_iommu *iommu)
1215{
1216 u32 sts;
1217 unsigned long flags;
1218
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001219 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001220 iommu->gcmd |= DMA_GCMD_TE;
1221 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001222
1223 /* Make sure hardware complete it */
1224 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001225 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001226
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001227 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001228 return 0;
1229}
1230
1231static int iommu_disable_translation(struct intel_iommu *iommu)
1232{
1233 u32 sts;
1234 unsigned long flag;
1235
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001236 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001237 iommu->gcmd &= ~DMA_GCMD_TE;
1238 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1239
1240 /* Make sure hardware complete it */
1241 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001242 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001243
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001244 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001245 return 0;
1246}
1247
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001248
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001249static int iommu_init_domains(struct intel_iommu *iommu)
1250{
1251 unsigned long ndomains;
1252 unsigned long nlongs;
1253
1254 ndomains = cap_ndoms(iommu->cap);
Masanari Iida68aeb962012-01-25 00:25:52 +09001255 pr_debug("IOMMU %d: Number of Domains supported <%ld>\n", iommu->seq_id,
Yinghai Lu680a7522010-04-08 19:58:23 +01001256 ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001257 nlongs = BITS_TO_LONGS(ndomains);
1258
Donald Dutile94a91b52009-08-20 16:51:34 -04001259 spin_lock_init(&iommu->lock);
1260
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001261 /* TBD: there might be 64K domains,
1262 * consider other allocation for future chip
1263 */
1264 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1265 if (!iommu->domain_ids) {
1266 printk(KERN_ERR "Allocating domain id array failed\n");
1267 return -ENOMEM;
1268 }
1269 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1270 GFP_KERNEL);
1271 if (!iommu->domains) {
1272 printk(KERN_ERR "Allocating domain array failed\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001273 return -ENOMEM;
1274 }
1275
1276 /*
1277 * if Caching mode is set, then invalid translations are tagged
1278 * with domainid 0. Hence we need to pre-allocate it.
1279 */
1280 if (cap_caching_mode(iommu->cap))
1281 set_bit(0, iommu->domain_ids);
1282 return 0;
1283}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001284
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001285
1286static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001287static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001288
1289void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001290{
1291 struct dmar_domain *domain;
1292 int i;
Weidong Hanc7151a82008-12-08 22:51:37 +08001293 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001294
Donald Dutile94a91b52009-08-20 16:51:34 -04001295 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001296 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001297 domain = iommu->domains[i];
1298 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001299
Donald Dutile94a91b52009-08-20 16:51:34 -04001300 spin_lock_irqsave(&domain->iommu_lock, flags);
1301 if (--domain->iommu_count == 0) {
1302 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1303 vm_domain_exit(domain);
1304 else
1305 domain_exit(domain);
1306 }
1307 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001308 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001309 }
1310
1311 if (iommu->gcmd & DMA_GCMD_TE)
1312 iommu_disable_translation(iommu);
1313
1314 if (iommu->irq) {
Thomas Gleixnerdced35a2011-03-28 17:49:12 +02001315 irq_set_handler_data(iommu->irq, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001316 /* This will mask the irq */
1317 free_irq(iommu->irq, iommu);
1318 destroy_irq(iommu->irq);
1319 }
1320
1321 kfree(iommu->domains);
1322 kfree(iommu->domain_ids);
1323
Weidong Hand9630fe2008-12-08 11:06:32 +08001324 g_iommus[iommu->seq_id] = NULL;
1325
1326 /* if all iommus are freed, free g_iommus */
1327 for (i = 0; i < g_num_of_iommus; i++) {
1328 if (g_iommus[i])
1329 break;
1330 }
1331
1332 if (i == g_num_of_iommus)
1333 kfree(g_iommus);
1334
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001335 /* free context mapping */
1336 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001337}
1338
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001339static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001340{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001341 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001342
1343 domain = alloc_domain_mem();
1344 if (!domain)
1345 return NULL;
1346
Suresh Siddha4c923d42009-10-02 11:01:24 -07001347 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08001348 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001349 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001350
1351 return domain;
1352}
1353
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001354static int iommu_attach_domain(struct dmar_domain *domain,
1355 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001356{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001357 int num;
1358 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001359 unsigned long flags;
1360
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001361 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001362
1363 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001364
1365 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1366 if (num >= ndomains) {
1367 spin_unlock_irqrestore(&iommu->lock, flags);
1368 printk(KERN_ERR "IOMMU: no free domain ids\n");
1369 return -ENOMEM;
1370 }
1371
1372 domain->id = num;
1373 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001374 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001375 iommu->domains[num] = domain;
1376 spin_unlock_irqrestore(&iommu->lock, flags);
1377
1378 return 0;
1379}
1380
1381static void iommu_detach_domain(struct dmar_domain *domain,
1382 struct intel_iommu *iommu)
1383{
1384 unsigned long flags;
1385 int num, ndomains;
1386 int found = 0;
1387
1388 spin_lock_irqsave(&iommu->lock, flags);
1389 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001390 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001391 if (iommu->domains[num] == domain) {
1392 found = 1;
1393 break;
1394 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001395 }
1396
1397 if (found) {
1398 clear_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001399 clear_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001400 iommu->domains[num] = NULL;
1401 }
Weidong Han8c11e792008-12-08 15:29:22 +08001402 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001403}
1404
1405static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001406static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001407
Joseph Cihula51a63e62011-03-21 11:04:24 -07001408static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001409{
1410 struct pci_dev *pdev = NULL;
1411 struct iova *iova;
1412 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001413
David Millerf6611972008-02-06 01:36:23 -08001414 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001415
Mark Gross8a443df2008-03-04 14:59:31 -08001416 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1417 &reserved_rbtree_key);
1418
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001419 /* IOAPIC ranges shouldn't be accessed by DMA */
1420 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1421 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001422 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001423 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001424 return -ENODEV;
1425 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001426
1427 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1428 for_each_pci_dev(pdev) {
1429 struct resource *r;
1430
1431 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1432 r = &pdev->resource[i];
1433 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1434 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001435 iova = reserve_iova(&reserved_iova_list,
1436 IOVA_PFN(r->start),
1437 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001438 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001439 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001440 return -ENODEV;
1441 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001442 }
1443 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001444 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001445}
1446
1447static void domain_reserve_special_ranges(struct dmar_domain *domain)
1448{
1449 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1450}
1451
1452static inline int guestwidth_to_adjustwidth(int gaw)
1453{
1454 int agaw;
1455 int r = (gaw - 12) % 9;
1456
1457 if (r == 0)
1458 agaw = gaw;
1459 else
1460 agaw = gaw + 9 - r;
1461 if (agaw > 64)
1462 agaw = 64;
1463 return agaw;
1464}
1465
1466static int domain_init(struct dmar_domain *domain, int guest_width)
1467{
1468 struct intel_iommu *iommu;
1469 int adjust_width, agaw;
1470 unsigned long sagaw;
1471
David Millerf6611972008-02-06 01:36:23 -08001472 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001473 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001474
1475 domain_reserve_special_ranges(domain);
1476
1477 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001478 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001479 if (guest_width > cap_mgaw(iommu->cap))
1480 guest_width = cap_mgaw(iommu->cap);
1481 domain->gaw = guest_width;
1482 adjust_width = guestwidth_to_adjustwidth(guest_width);
1483 agaw = width_to_agaw(adjust_width);
1484 sagaw = cap_sagaw(iommu->cap);
1485 if (!test_bit(agaw, &sagaw)) {
1486 /* hardware doesn't support it, choose a bigger one */
1487 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1488 agaw = find_next_bit(&sagaw, 5, agaw);
1489 if (agaw >= 5)
1490 return -ENODEV;
1491 }
1492 domain->agaw = agaw;
1493 INIT_LIST_HEAD(&domain->devices);
1494
Weidong Han8e6040972008-12-08 15:49:06 +08001495 if (ecap_coherent(iommu->ecap))
1496 domain->iommu_coherency = 1;
1497 else
1498 domain->iommu_coherency = 0;
1499
Sheng Yang58c610b2009-03-18 15:33:05 +08001500 if (ecap_sc_support(iommu->ecap))
1501 domain->iommu_snooping = 1;
1502 else
1503 domain->iommu_snooping = 0;
1504
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001505 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Weidong Hanc7151a82008-12-08 22:51:37 +08001506 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001507 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001508
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001509 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001510 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001511 if (!domain->pgd)
1512 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001513 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001514 return 0;
1515}
1516
1517static void domain_exit(struct dmar_domain *domain)
1518{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001519 struct dmar_drhd_unit *drhd;
1520 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001521
1522 /* Domain 0 is reserved, so dont process it */
1523 if (!domain)
1524 return;
1525
Alex Williamson7b668352011-05-24 12:02:41 +01001526 /* Flush any lazy unmaps that may reference this domain */
1527 if (!intel_iommu_strict)
1528 flush_unmaps_timeout(0);
1529
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001530 domain_remove_dev_info(domain);
1531 /* destroy iovas */
1532 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001533
1534 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001535 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001536
1537 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001538 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001539
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001540 for_each_active_iommu(iommu, drhd)
Mike Travis1b198bb2012-03-05 15:05:16 -08001541 if (test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001542 iommu_detach_domain(domain, iommu);
1543
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001544 free_domain_mem(domain);
1545}
1546
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001547static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1548 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001549{
1550 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001551 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001552 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001553 struct dma_pte *pgd;
1554 unsigned long num;
1555 unsigned long ndomains;
1556 int id;
1557 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001558 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001559
1560 pr_debug("Set context mapping for %02x:%02x.%d\n",
1561 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001562
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001563 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001564 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1565 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001566
David Woodhouse276dbf992009-04-04 01:45:37 +01001567 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001568 if (!iommu)
1569 return -ENODEV;
1570
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001571 context = device_to_context_entry(iommu, bus, devfn);
1572 if (!context)
1573 return -ENOMEM;
1574 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001575 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001576 spin_unlock_irqrestore(&iommu->lock, flags);
1577 return 0;
1578 }
1579
Weidong Hanea6606b2008-12-08 23:08:15 +08001580 id = domain->id;
1581 pgd = domain->pgd;
1582
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001583 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1584 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001585 int found = 0;
1586
1587 /* find an available domain id for this device in iommu */
1588 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001589 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001590 if (iommu->domains[num] == domain) {
1591 id = num;
1592 found = 1;
1593 break;
1594 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001595 }
1596
1597 if (found == 0) {
1598 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1599 if (num >= ndomains) {
1600 spin_unlock_irqrestore(&iommu->lock, flags);
1601 printk(KERN_ERR "IOMMU: no free domain ids\n");
1602 return -EFAULT;
1603 }
1604
1605 set_bit(num, iommu->domain_ids);
1606 iommu->domains[num] = domain;
1607 id = num;
1608 }
1609
1610 /* Skip top levels of page tables for
1611 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001612 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001613 */
Chris Wright1672af12009-12-02 12:06:34 -08001614 if (translation != CONTEXT_TT_PASS_THROUGH) {
1615 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1616 pgd = phys_to_virt(dma_pte_addr(pgd));
1617 if (!dma_pte_present(pgd)) {
1618 spin_unlock_irqrestore(&iommu->lock, flags);
1619 return -ENOMEM;
1620 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001621 }
1622 }
1623 }
1624
1625 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001626
Yu Zhao93a23a72009-05-18 13:51:37 +08001627 if (translation != CONTEXT_TT_PASS_THROUGH) {
1628 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1629 translation = info ? CONTEXT_TT_DEV_IOTLB :
1630 CONTEXT_TT_MULTI_LEVEL;
1631 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001632 /*
1633 * In pass through mode, AW must be programmed to indicate the largest
1634 * AGAW value supported by hardware. And ASR is ignored by hardware.
1635 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001636 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001637 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001638 else {
1639 context_set_address_root(context, virt_to_phys(pgd));
1640 context_set_address_width(context, iommu->agaw);
1641 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001642
1643 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001644 context_set_fault_enable(context);
1645 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001646 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001647
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001648 /*
1649 * It's a non-present to present mapping. If hardware doesn't cache
1650 * non-present entry we only need to flush the write-buffer. If the
1651 * _does_ cache non-present entries, then it does so in the special
1652 * domain #0, which we have to flush:
1653 */
1654 if (cap_caching_mode(iommu->cap)) {
1655 iommu->flush.flush_context(iommu, 0,
1656 (((u16)bus) << 8) | devfn,
1657 DMA_CCMD_MASK_NOBIT,
1658 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001659 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001660 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001661 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001662 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001663 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001664 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001665
1666 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001667 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001668 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001669 if (domain->iommu_count == 1)
1670 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001671 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001672 }
1673 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001674 return 0;
1675}
1676
1677static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001678domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1679 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001680{
1681 int ret;
1682 struct pci_dev *tmp, *parent;
1683
David Woodhouse276dbf992009-04-04 01:45:37 +01001684 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001685 pdev->bus->number, pdev->devfn,
1686 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001687 if (ret)
1688 return ret;
1689
1690 /* dependent device mapping */
1691 tmp = pci_find_upstream_pcie_bridge(pdev);
1692 if (!tmp)
1693 return 0;
1694 /* Secondary interface's bus number and devfn 0 */
1695 parent = pdev->bus->self;
1696 while (parent != tmp) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001697 ret = domain_context_mapping_one(domain,
1698 pci_domain_nr(parent->bus),
1699 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001700 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001701 if (ret)
1702 return ret;
1703 parent = parent->bus->self;
1704 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001705 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001706 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001707 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001708 tmp->subordinate->number, 0,
1709 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001710 else /* this is a legacy PCI bridge */
1711 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001712 pci_domain_nr(tmp->bus),
1713 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001714 tmp->devfn,
1715 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001716}
1717
Weidong Han5331fe62008-12-08 23:00:00 +08001718static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001719{
1720 int ret;
1721 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001722 struct intel_iommu *iommu;
1723
David Woodhouse276dbf992009-04-04 01:45:37 +01001724 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1725 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001726 if (!iommu)
1727 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001728
David Woodhouse276dbf992009-04-04 01:45:37 +01001729 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001730 if (!ret)
1731 return ret;
1732 /* dependent device mapping */
1733 tmp = pci_find_upstream_pcie_bridge(pdev);
1734 if (!tmp)
1735 return ret;
1736 /* Secondary interface's bus number and devfn 0 */
1737 parent = pdev->bus->self;
1738 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001739 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001740 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001741 if (!ret)
1742 return ret;
1743 parent = parent->bus->self;
1744 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001745 if (pci_is_pcie(tmp))
David Woodhouse276dbf992009-04-04 01:45:37 +01001746 return device_context_mapped(iommu, tmp->subordinate->number,
1747 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001748 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001749 return device_context_mapped(iommu, tmp->bus->number,
1750 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001751}
1752
Fenghua Yuf5329592009-08-04 15:09:37 -07001753/* Returns a number of VTD pages, but aligned to MM page size */
1754static inline unsigned long aligned_nrpages(unsigned long host_addr,
1755 size_t size)
1756{
1757 host_addr &= ~PAGE_MASK;
1758 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1759}
1760
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001761/* Return largest possible superpage level for a given mapping */
1762static inline int hardware_largepage_caps(struct dmar_domain *domain,
1763 unsigned long iov_pfn,
1764 unsigned long phy_pfn,
1765 unsigned long pages)
1766{
1767 int support, level = 1;
1768 unsigned long pfnmerge;
1769
1770 support = domain->iommu_superpage;
1771
1772 /* To use a large page, the virtual *and* physical addresses
1773 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1774 of them will mean we have to use smaller pages. So just
1775 merge them and check both at once. */
1776 pfnmerge = iov_pfn | phy_pfn;
1777
1778 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1779 pages >>= VTD_STRIDE_SHIFT;
1780 if (!pages)
1781 break;
1782 pfnmerge >>= VTD_STRIDE_SHIFT;
1783 level++;
1784 support--;
1785 }
1786 return level;
1787}
1788
David Woodhouse9051aa02009-06-29 12:30:54 +01001789static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1790 struct scatterlist *sg, unsigned long phys_pfn,
1791 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001792{
1793 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001794 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001795 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001796 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001797 unsigned int largepage_lvl = 0;
1798 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001799
1800 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1801
1802 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1803 return -EINVAL;
1804
1805 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1806
David Woodhouse9051aa02009-06-29 12:30:54 +01001807 if (sg)
1808 sg_res = 0;
1809 else {
1810 sg_res = nr_pages + 1;
1811 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1812 }
1813
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001814 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001815 uint64_t tmp;
1816
David Woodhousee1605492009-06-29 11:17:38 +01001817 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001818 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001819 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1820 sg->dma_length = sg->length;
1821 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001822 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001823 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001824
David Woodhousee1605492009-06-29 11:17:38 +01001825 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001826 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1827
1828 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001829 if (!pte)
1830 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001831 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001832 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001833 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001834 /* Ensure that old small page tables are removed to make room
1835 for superpage, if they exist. */
1836 dma_pte_clear_range(domain, iov_pfn,
1837 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1838 dma_pte_free_pagetable(domain, iov_pfn,
1839 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1840 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001841 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001842 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001843
David Woodhousee1605492009-06-29 11:17:38 +01001844 }
1845 /* We don't need lock here, nobody else
1846 * touches the iova range
1847 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001848 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001849 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001850 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001851 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1852 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001853 if (dumps) {
1854 dumps--;
1855 debug_dma_dump_mappings(NULL);
1856 }
1857 WARN_ON(1);
1858 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001859
1860 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1861
1862 BUG_ON(nr_pages < lvl_pages);
1863 BUG_ON(sg_res < lvl_pages);
1864
1865 nr_pages -= lvl_pages;
1866 iov_pfn += lvl_pages;
1867 phys_pfn += lvl_pages;
1868 pteval += lvl_pages * VTD_PAGE_SIZE;
1869 sg_res -= lvl_pages;
1870
1871 /* If the next PTE would be the first in a new page, then we
1872 need to flush the cache on the entries we've just written.
1873 And then we'll need to recalculate 'pte', so clear it and
1874 let it get set again in the if (!pte) block above.
1875
1876 If we're done (!nr_pages) we need to flush the cache too.
1877
1878 Also if we've been setting superpages, we may need to
1879 recalculate 'pte' and switch back to smaller pages for the
1880 end of the mapping, if the trailing size is not enough to
1881 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001882 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001883 if (!nr_pages || first_pte_in_page(pte) ||
1884 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001885 domain_flush_cache(domain, first_pte,
1886 (void *)pte - (void *)first_pte);
1887 pte = NULL;
1888 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001889
1890 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001891 sg = sg_next(sg);
1892 }
1893 return 0;
1894}
1895
David Woodhouse9051aa02009-06-29 12:30:54 +01001896static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1897 struct scatterlist *sg, unsigned long nr_pages,
1898 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001899{
David Woodhouse9051aa02009-06-29 12:30:54 +01001900 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1901}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001902
David Woodhouse9051aa02009-06-29 12:30:54 +01001903static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1904 unsigned long phys_pfn, unsigned long nr_pages,
1905 int prot)
1906{
1907 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001908}
1909
Weidong Hanc7151a82008-12-08 22:51:37 +08001910static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001911{
Weidong Hanc7151a82008-12-08 22:51:37 +08001912 if (!iommu)
1913 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001914
1915 clear_context_table(iommu, bus, devfn);
1916 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001917 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001918 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001919}
1920
David Woodhouse109b9b02012-05-25 17:43:02 +01001921static inline void unlink_domain_info(struct device_domain_info *info)
1922{
1923 assert_spin_locked(&device_domain_lock);
1924 list_del(&info->link);
1925 list_del(&info->global);
1926 if (info->dev)
1927 info->dev->dev.archdata.iommu = NULL;
1928}
1929
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001930static void domain_remove_dev_info(struct dmar_domain *domain)
1931{
1932 struct device_domain_info *info;
1933 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001934 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001935
1936 spin_lock_irqsave(&device_domain_lock, flags);
1937 while (!list_empty(&domain->devices)) {
1938 info = list_entry(domain->devices.next,
1939 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01001940 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001941 spin_unlock_irqrestore(&device_domain_lock, flags);
1942
Yu Zhao93a23a72009-05-18 13:51:37 +08001943 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01001944 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001945 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001946 free_devinfo_mem(info);
1947
1948 spin_lock_irqsave(&device_domain_lock, flags);
1949 }
1950 spin_unlock_irqrestore(&device_domain_lock, flags);
1951}
1952
1953/*
1954 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001955 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001956 */
Kay, Allen M38717942008-09-09 18:37:29 +03001957static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001958find_domain(struct pci_dev *pdev)
1959{
1960 struct device_domain_info *info;
1961
1962 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001963 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001964 if (info)
1965 return info->domain;
1966 return NULL;
1967}
1968
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001969/* domain is initialized */
1970static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
1971{
1972 struct dmar_domain *domain, *found = NULL;
1973 struct intel_iommu *iommu;
1974 struct dmar_drhd_unit *drhd;
1975 struct device_domain_info *info, *tmp;
1976 struct pci_dev *dev_tmp;
1977 unsigned long flags;
1978 int bus = 0, devfn = 0;
David Woodhouse276dbf992009-04-04 01:45:37 +01001979 int segment;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001980 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001981
1982 domain = find_domain(pdev);
1983 if (domain)
1984 return domain;
1985
David Woodhouse276dbf992009-04-04 01:45:37 +01001986 segment = pci_domain_nr(pdev->bus);
1987
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001988 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
1989 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001990 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001991 bus = dev_tmp->subordinate->number;
1992 devfn = 0;
1993 } else {
1994 bus = dev_tmp->bus->number;
1995 devfn = dev_tmp->devfn;
1996 }
1997 spin_lock_irqsave(&device_domain_lock, flags);
1998 list_for_each_entry(info, &device_domain_list, global) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001999 if (info->segment == segment &&
2000 info->bus == bus && info->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002001 found = info->domain;
2002 break;
2003 }
2004 }
2005 spin_unlock_irqrestore(&device_domain_lock, flags);
2006 /* pcie-pci bridge already has a domain, uses it */
2007 if (found) {
2008 domain = found;
2009 goto found_domain;
2010 }
2011 }
2012
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002013 domain = alloc_domain();
2014 if (!domain)
2015 goto error;
2016
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002017 /* Allocate new domain for the device */
2018 drhd = dmar_find_matched_drhd_unit(pdev);
2019 if (!drhd) {
2020 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2021 pci_name(pdev));
Julia Lawalld2900bd2012-07-24 16:18:14 +02002022 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002023 return NULL;
2024 }
2025 iommu = drhd->iommu;
2026
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002027 ret = iommu_attach_domain(domain, iommu);
2028 if (ret) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002029 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002030 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002031 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002032
2033 if (domain_init(domain, gaw)) {
2034 domain_exit(domain);
2035 goto error;
2036 }
2037
2038 /* register pcie-to-pci device */
2039 if (dev_tmp) {
2040 info = alloc_devinfo_mem();
2041 if (!info) {
2042 domain_exit(domain);
2043 goto error;
2044 }
David Woodhouse276dbf992009-04-04 01:45:37 +01002045 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002046 info->bus = bus;
2047 info->devfn = devfn;
2048 info->dev = NULL;
2049 info->domain = domain;
2050 /* This domain is shared by devices under p2p bridge */
Weidong Han3b5410e2008-12-08 09:17:15 +08002051 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002052
2053 /* pcie-to-pci bridge already has a domain, uses it */
2054 found = NULL;
2055 spin_lock_irqsave(&device_domain_lock, flags);
2056 list_for_each_entry(tmp, &device_domain_list, global) {
David Woodhouse276dbf992009-04-04 01:45:37 +01002057 if (tmp->segment == segment &&
2058 tmp->bus == bus && tmp->devfn == devfn) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002059 found = tmp->domain;
2060 break;
2061 }
2062 }
2063 if (found) {
Jiri Slaby00dfff72010-06-14 17:17:32 +02002064 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002065 free_devinfo_mem(info);
2066 domain_exit(domain);
2067 domain = found;
2068 } else {
2069 list_add(&info->link, &domain->devices);
2070 list_add(&info->global, &device_domain_list);
Jiri Slaby00dfff72010-06-14 17:17:32 +02002071 spin_unlock_irqrestore(&device_domain_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002072 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002073 }
2074
2075found_domain:
2076 info = alloc_devinfo_mem();
2077 if (!info)
2078 goto error;
David Woodhouse276dbf992009-04-04 01:45:37 +01002079 info->segment = segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002080 info->bus = pdev->bus->number;
2081 info->devfn = pdev->devfn;
2082 info->dev = pdev;
2083 info->domain = domain;
2084 spin_lock_irqsave(&device_domain_lock, flags);
2085 /* somebody is fast */
2086 found = find_domain(pdev);
2087 if (found != NULL) {
2088 spin_unlock_irqrestore(&device_domain_lock, flags);
2089 if (found != domain) {
2090 domain_exit(domain);
2091 domain = found;
2092 }
2093 free_devinfo_mem(info);
2094 return domain;
2095 }
2096 list_add(&info->link, &domain->devices);
2097 list_add(&info->global, &device_domain_list);
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002098 pdev->dev.archdata.iommu = info;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002099 spin_unlock_irqrestore(&device_domain_lock, flags);
2100 return domain;
2101error:
2102 /* recheck it here, maybe others set it */
2103 return find_domain(pdev);
2104}
2105
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002106static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002107#define IDENTMAP_ALL 1
2108#define IDENTMAP_GFX 2
2109#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002110
David Woodhouseb2132032009-06-26 18:50:28 +01002111static int iommu_domain_identity_map(struct dmar_domain *domain,
2112 unsigned long long start,
2113 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002114{
David Woodhousec5395d52009-06-28 16:35:56 +01002115 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2116 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002117
David Woodhousec5395d52009-06-28 16:35:56 +01002118 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2119 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002120 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002121 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002122 }
2123
David Woodhousec5395d52009-06-28 16:35:56 +01002124 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2125 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002126 /*
2127 * RMRR range might have overlap with physical memory range,
2128 * clear it first
2129 */
David Woodhousec5395d52009-06-28 16:35:56 +01002130 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002131
David Woodhousec5395d52009-06-28 16:35:56 +01002132 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2133 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002134 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002135}
2136
2137static int iommu_prepare_identity_map(struct pci_dev *pdev,
2138 unsigned long long start,
2139 unsigned long long end)
2140{
2141 struct dmar_domain *domain;
2142 int ret;
2143
David Woodhousec7ab48d2009-06-26 19:10:36 +01002144 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002145 if (!domain)
2146 return -ENOMEM;
2147
David Woodhouse19943b02009-08-04 16:19:20 +01002148 /* For _hardware_ passthrough, don't bother. But for software
2149 passthrough, we do it anyway -- it may indicate a memory
2150 range which is reserved in E820, so which didn't get set
2151 up to start with in si_domain */
2152 if (domain == si_domain && hw_pass_through) {
2153 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2154 pci_name(pdev), start, end);
2155 return 0;
2156 }
2157
2158 printk(KERN_INFO
2159 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2160 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002161
David Woodhouse5595b522009-12-02 09:21:55 +00002162 if (end < start) {
2163 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2164 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2165 dmi_get_system_info(DMI_BIOS_VENDOR),
2166 dmi_get_system_info(DMI_BIOS_VERSION),
2167 dmi_get_system_info(DMI_PRODUCT_VERSION));
2168 ret = -EIO;
2169 goto error;
2170 }
2171
David Woodhouse2ff729f2009-08-26 14:25:41 +01002172 if (end >> agaw_to_width(domain->agaw)) {
2173 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2174 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2175 agaw_to_width(domain->agaw),
2176 dmi_get_system_info(DMI_BIOS_VENDOR),
2177 dmi_get_system_info(DMI_BIOS_VERSION),
2178 dmi_get_system_info(DMI_PRODUCT_VERSION));
2179 ret = -EIO;
2180 goto error;
2181 }
David Woodhouse19943b02009-08-04 16:19:20 +01002182
David Woodhouseb2132032009-06-26 18:50:28 +01002183 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002184 if (ret)
2185 goto error;
2186
2187 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002188 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002189 if (ret)
2190 goto error;
2191
2192 return 0;
2193
2194 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002195 domain_exit(domain);
2196 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002197}
2198
2199static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2200 struct pci_dev *pdev)
2201{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002202 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002203 return 0;
2204 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002205 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002206}
2207
Suresh Siddhad3f13812011-08-23 17:05:25 -07002208#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002209static inline void iommu_prepare_isa(void)
2210{
2211 struct pci_dev *pdev;
2212 int ret;
2213
2214 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2215 if (!pdev)
2216 return;
2217
David Woodhousec7ab48d2009-06-26 19:10:36 +01002218 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002219 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002220
2221 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002222 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2223 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002224
2225}
2226#else
2227static inline void iommu_prepare_isa(void)
2228{
2229 return;
2230}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002231#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002232
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002233static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002234
Matt Kraai071e1372009-08-23 22:30:22 -07002235static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002236{
2237 struct dmar_drhd_unit *drhd;
2238 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002239 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002240
2241 si_domain = alloc_domain();
2242 if (!si_domain)
2243 return -EFAULT;
2244
David Woodhousec7ab48d2009-06-26 19:10:36 +01002245 pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002246
2247 for_each_active_iommu(iommu, drhd) {
2248 ret = iommu_attach_domain(si_domain, iommu);
2249 if (ret) {
2250 domain_exit(si_domain);
2251 return -EFAULT;
2252 }
2253 }
2254
2255 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2256 domain_exit(si_domain);
2257 return -EFAULT;
2258 }
2259
2260 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2261
David Woodhouse19943b02009-08-04 16:19:20 +01002262 if (hw)
2263 return 0;
2264
David Woodhousec7ab48d2009-06-26 19:10:36 +01002265 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002266 unsigned long start_pfn, end_pfn;
2267 int i;
2268
2269 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2270 ret = iommu_domain_identity_map(si_domain,
2271 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2272 if (ret)
2273 return ret;
2274 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002275 }
2276
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002277 return 0;
2278}
2279
2280static void domain_remove_one_dev_info(struct dmar_domain *domain,
2281 struct pci_dev *pdev);
2282static int identity_mapping(struct pci_dev *pdev)
2283{
2284 struct device_domain_info *info;
2285
2286 if (likely(!iommu_identity_mapping))
2287 return 0;
2288
Mike Traviscb452a42011-05-28 13:15:03 -05002289 info = pdev->dev.archdata.iommu;
2290 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2291 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002292
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002293 return 0;
2294}
2295
2296static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002297 struct pci_dev *pdev,
2298 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002299{
2300 struct device_domain_info *info;
2301 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002302 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002303
2304 info = alloc_devinfo_mem();
2305 if (!info)
2306 return -ENOMEM;
2307
2308 info->segment = pci_domain_nr(pdev->bus);
2309 info->bus = pdev->bus->number;
2310 info->devfn = pdev->devfn;
2311 info->dev = pdev;
2312 info->domain = domain;
2313
2314 spin_lock_irqsave(&device_domain_lock, flags);
2315 list_add(&info->link, &domain->devices);
2316 list_add(&info->global, &device_domain_list);
2317 pdev->dev.archdata.iommu = info;
2318 spin_unlock_irqrestore(&device_domain_lock, flags);
2319
David Woodhousee2ad23d2012-05-25 17:42:54 +01002320 ret = domain_context_mapping(domain, pdev, translation);
2321 if (ret) {
2322 spin_lock_irqsave(&device_domain_lock, flags);
David Woodhouse109b9b02012-05-25 17:43:02 +01002323 unlink_domain_info(info);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002324 spin_unlock_irqrestore(&device_domain_lock, flags);
2325 free_devinfo_mem(info);
2326 return ret;
2327 }
2328
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002329 return 0;
2330}
2331
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002332static bool device_has_rmrr(struct pci_dev *dev)
2333{
2334 struct dmar_rmrr_unit *rmrr;
2335 int i;
2336
2337 for_each_rmrr_units(rmrr) {
2338 for (i = 0; i < rmrr->devices_cnt; i++) {
2339 /*
2340 * Return TRUE if this RMRR contains the device that
2341 * is passed in.
2342 */
2343 if (rmrr->devices[i] == dev)
2344 return true;
2345 }
2346 }
2347 return false;
2348}
2349
David Woodhouse6941af22009-07-04 18:24:27 +01002350static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2351{
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002352
2353 /*
2354 * We want to prevent any device associated with an RMRR from
2355 * getting placed into the SI Domain. This is done because
2356 * problems exist when devices are moved in and out of domains
2357 * and their respective RMRR info is lost. We exempt USB devices
2358 * from this process due to their usage of RMRRs that are known
2359 * to not be needed after BIOS hand-off to OS.
2360 */
2361 if (device_has_rmrr(pdev) &&
2362 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2363 return 0;
2364
David Woodhousee0fc7e02009-09-30 09:12:17 -07002365 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2366 return 1;
2367
2368 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2369 return 1;
2370
2371 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2372 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002373
David Woodhouse3dfc8132009-07-04 19:11:08 +01002374 /*
2375 * We want to start off with all devices in the 1:1 domain, and
2376 * take them out later if we find they can't access all of memory.
2377 *
2378 * However, we can't do this for PCI devices behind bridges,
2379 * because all PCI devices behind the same bridge will end up
2380 * with the same source-id on their transactions.
2381 *
2382 * Practically speaking, we can't change things around for these
2383 * devices at run-time, because we can't be sure there'll be no
2384 * DMA transactions in flight for any of their siblings.
2385 *
2386 * So PCI devices (unless they're on the root bus) as well as
2387 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2388 * the 1:1 domain, just in _case_ one of their siblings turns out
2389 * not to be able to map all of memory.
2390 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002391 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002392 if (!pci_is_root_bus(pdev->bus))
2393 return 0;
2394 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2395 return 0;
Yijing Wang62f87c02012-07-24 17:20:03 +08002396 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
David Woodhouse3dfc8132009-07-04 19:11:08 +01002397 return 0;
2398
2399 /*
2400 * At boot time, we don't yet know if devices will be 64-bit capable.
2401 * Assume that they will -- if they turn out not to be, then we can
2402 * take them out of the 1:1 domain later.
2403 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002404 if (!startup) {
2405 /*
2406 * If the device's dma_mask is less than the system's memory
2407 * size then this is not a candidate for identity mapping.
2408 */
2409 u64 dma_mask = pdev->dma_mask;
2410
2411 if (pdev->dev.coherent_dma_mask &&
2412 pdev->dev.coherent_dma_mask < dma_mask)
2413 dma_mask = pdev->dev.coherent_dma_mask;
2414
2415 return dma_mask >= dma_get_required_mask(&pdev->dev);
2416 }
David Woodhouse6941af22009-07-04 18:24:27 +01002417
2418 return 1;
2419}
2420
Matt Kraai071e1372009-08-23 22:30:22 -07002421static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002422{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002423 struct pci_dev *pdev = NULL;
2424 int ret;
2425
David Woodhouse19943b02009-08-04 16:19:20 +01002426 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002427 if (ret)
2428 return -EFAULT;
2429
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002430 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002431 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002432 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002433 hw ? CONTEXT_TT_PASS_THROUGH :
2434 CONTEXT_TT_MULTI_LEVEL);
2435 if (ret) {
2436 /* device not associated with an iommu */
2437 if (ret == -ENODEV)
2438 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002439 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002440 }
2441 pr_info("IOMMU: %s identity mapping for device %s\n",
2442 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002443 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002444 }
2445
2446 return 0;
2447}
2448
Joseph Cihulab7792602011-05-03 00:08:37 -07002449static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002450{
2451 struct dmar_drhd_unit *drhd;
2452 struct dmar_rmrr_unit *rmrr;
2453 struct pci_dev *pdev;
2454 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002455 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002456
2457 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002458 * for each drhd
2459 * allocate root
2460 * initialize and program root entry to not present
2461 * endfor
2462 */
2463 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002464 /*
2465 * lock not needed as this is only incremented in the single
2466 * threaded kernel __init code path all other access are read
2467 * only
2468 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002469 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2470 g_num_of_iommus++;
2471 continue;
2472 }
2473 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2474 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002475 }
2476
Weidong Hand9630fe2008-12-08 11:06:32 +08002477 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2478 GFP_KERNEL);
2479 if (!g_iommus) {
2480 printk(KERN_ERR "Allocating global iommu array failed\n");
2481 ret = -ENOMEM;
2482 goto error;
2483 }
2484
mark gross80b20dd2008-04-18 13:53:58 -07002485 deferred_flush = kzalloc(g_num_of_iommus *
2486 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2487 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002488 ret = -ENOMEM;
2489 goto error;
2490 }
2491
mark gross5e0d2a62008-03-04 15:22:08 -08002492 for_each_drhd_unit(drhd) {
2493 if (drhd->ignored)
2494 continue;
Suresh Siddha1886e8a2008-07-10 11:16:37 -07002495
2496 iommu = drhd->iommu;
Weidong Hand9630fe2008-12-08 11:06:32 +08002497 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002498
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002499 ret = iommu_init_domains(iommu);
2500 if (ret)
2501 goto error;
2502
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002503 /*
2504 * TBD:
2505 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002506 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002507 */
2508 ret = iommu_alloc_root_entry(iommu);
2509 if (ret) {
2510 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
2511 goto error;
2512 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002513 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002514 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002515 }
2516
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002517 /*
2518 * Start from the sane iommu hardware state.
2519 */
Youquan Songa77b67d2008-10-16 16:31:56 -07002520 for_each_drhd_unit(drhd) {
2521 if (drhd->ignored)
2522 continue;
2523
2524 iommu = drhd->iommu;
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002525
2526 /*
2527 * If the queued invalidation is already initialized by us
2528 * (for example, while enabling interrupt-remapping) then
2529 * we got the things already rolling from a sane state.
2530 */
2531 if (iommu->qi)
2532 continue;
2533
2534 /*
2535 * Clear any previous faults.
2536 */
2537 dmar_fault(-1, iommu);
2538 /*
2539 * Disable queued invalidation if supported and already enabled
2540 * before OS handover.
2541 */
2542 dmar_disable_qi(iommu);
2543 }
2544
2545 for_each_drhd_unit(drhd) {
2546 if (drhd->ignored)
2547 continue;
2548
2549 iommu = drhd->iommu;
2550
Youquan Songa77b67d2008-10-16 16:31:56 -07002551 if (dmar_enable_qi(iommu)) {
2552 /*
2553 * Queued Invalidate not enabled, use Register Based
2554 * Invalidate
2555 */
2556 iommu->flush.flush_context = __iommu_flush_context;
2557 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002558 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002559 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002560 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002561 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002562 } else {
2563 iommu->flush.flush_context = qi_flush_context;
2564 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002565 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002566 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002567 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002568 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002569 }
2570 }
2571
David Woodhouse19943b02009-08-04 16:19:20 +01002572 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002573 iommu_identity_mapping |= IDENTMAP_ALL;
2574
Suresh Siddhad3f13812011-08-23 17:05:25 -07002575#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002576 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002577#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002578
2579 check_tylersburg_isoch();
2580
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002581 /*
2582 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002583 * identity mappings for rmrr, gfx, and isa and may fall back to static
2584 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002585 */
David Woodhouse19943b02009-08-04 16:19:20 +01002586 if (iommu_identity_mapping) {
2587 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2588 if (ret) {
2589 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
2590 goto error;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002591 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002592 }
David Woodhouse19943b02009-08-04 16:19:20 +01002593 /*
2594 * For each rmrr
2595 * for each dev attached to rmrr
2596 * do
2597 * locate drhd for dev, alloc domain for dev
2598 * allocate free domain
2599 * allocate page table entries for rmrr
2600 * if context not allocated for bus
2601 * allocate and init context
2602 * set present in root table for this bus
2603 * init context with domain, translation etc
2604 * endfor
2605 * endfor
2606 */
2607 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2608 for_each_rmrr_units(rmrr) {
2609 for (i = 0; i < rmrr->devices_cnt; i++) {
2610 pdev = rmrr->devices[i];
2611 /*
2612 * some BIOS lists non-exist devices in DMAR
2613 * table.
2614 */
2615 if (!pdev)
2616 continue;
2617 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2618 if (ret)
2619 printk(KERN_ERR
2620 "IOMMU: mapping reserved region failed\n");
2621 }
2622 }
2623
2624 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002625
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002626 /*
2627 * for each drhd
2628 * enable fault log
2629 * global invalidate context cache
2630 * global invalidate iotlb
2631 * enable translation
2632 */
2633 for_each_drhd_unit(drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002634 if (drhd->ignored) {
2635 /*
2636 * we always have to disable PMRs or DMA may fail on
2637 * this device
2638 */
2639 if (force_on)
2640 iommu_disable_protect_mem_regions(drhd->iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002641 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002642 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002643 iommu = drhd->iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002644
2645 iommu_flush_write_buffer(iommu);
2646
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002647 ret = dmar_set_interrupt(iommu);
2648 if (ret)
2649 goto error;
2650
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002651 iommu_set_root_entry(iommu);
2652
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002653 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002654 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002655
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002656 ret = iommu_enable_translation(iommu);
2657 if (ret)
2658 goto error;
David Woodhouseb94996c2009-09-19 15:28:12 -07002659
2660 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002661 }
2662
2663 return 0;
2664error:
2665 for_each_drhd_unit(drhd) {
2666 if (drhd->ignored)
2667 continue;
2668 iommu = drhd->iommu;
2669 free_iommu(iommu);
2670 }
Weidong Hand9630fe2008-12-08 11:06:32 +08002671 kfree(g_iommus);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002672 return ret;
2673}
2674
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002675/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002676static struct iova *intel_alloc_iova(struct device *dev,
2677 struct dmar_domain *domain,
2678 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002679{
2680 struct pci_dev *pdev = to_pci_dev(dev);
2681 struct iova *iova = NULL;
2682
David Woodhouse875764d2009-06-28 21:20:51 +01002683 /* Restrict dma_mask to the width that the iommu can handle */
2684 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2685
2686 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002687 /*
2688 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002689 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002690 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002691 */
David Woodhouse875764d2009-06-28 21:20:51 +01002692 iova = alloc_iova(&domain->iovad, nrpages,
2693 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2694 if (iova)
2695 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002696 }
David Woodhouse875764d2009-06-28 21:20:51 +01002697 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2698 if (unlikely(!iova)) {
2699 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2700 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002701 return NULL;
2702 }
2703
2704 return iova;
2705}
2706
David Woodhouse147202a2009-07-07 19:43:20 +01002707static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002708{
2709 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002710 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002711
2712 domain = get_domain_for_dev(pdev,
2713 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2714 if (!domain) {
2715 printk(KERN_ERR
2716 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002717 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002718 }
2719
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002720 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002721 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002722 ret = domain_context_mapping(domain, pdev,
2723 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002724 if (ret) {
2725 printk(KERN_ERR
2726 "Domain context map for %s failed",
2727 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002728 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002729 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002730 }
2731
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002732 return domain;
2733}
2734
David Woodhouse147202a2009-07-07 19:43:20 +01002735static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2736{
2737 struct device_domain_info *info;
2738
2739 /* No lock here, assumes no domain exit in normal case */
2740 info = dev->dev.archdata.iommu;
2741 if (likely(info))
2742 return info->domain;
2743
2744 return __get_valid_domain_for_dev(dev);
2745}
2746
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002747static int iommu_dummy(struct pci_dev *pdev)
2748{
2749 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2750}
2751
2752/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002753static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002754{
David Woodhouse73676832009-07-04 14:08:36 +01002755 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002756 int found;
2757
David Woodhouse73676832009-07-04 14:08:36 +01002758 if (unlikely(dev->bus != &pci_bus_type))
2759 return 1;
2760
2761 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002762 if (iommu_dummy(pdev))
2763 return 1;
2764
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002765 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002766 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002767
2768 found = identity_mapping(pdev);
2769 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002770 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002771 return 1;
2772 else {
2773 /*
2774 * 32 bit DMA is removed from si_domain and fall back
2775 * to non-identity mapping.
2776 */
2777 domain_remove_one_dev_info(si_domain, pdev);
2778 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2779 pci_name(pdev));
2780 return 0;
2781 }
2782 } else {
2783 /*
2784 * In case of a detached 64 bit DMA device from vm, the device
2785 * is put into si_domain for identity mapping.
2786 */
David Woodhouse6941af22009-07-04 18:24:27 +01002787 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002788 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002789 ret = domain_add_dev_info(si_domain, pdev,
2790 hw_pass_through ?
2791 CONTEXT_TT_PASS_THROUGH :
2792 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002793 if (!ret) {
2794 printk(KERN_INFO "64bit %s uses identity mapping\n",
2795 pci_name(pdev));
2796 return 1;
2797 }
2798 }
2799 }
2800
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002801 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002802}
2803
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002804static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2805 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002806{
2807 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002808 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002809 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002810 struct iova *iova;
2811 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002812 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002813 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002814 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002815
2816 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002817
David Woodhouse73676832009-07-04 14:08:36 +01002818 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002819 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002820
2821 domain = get_valid_domain_for_dev(pdev);
2822 if (!domain)
2823 return 0;
2824
Weidong Han8c11e792008-12-08 15:29:22 +08002825 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002826 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002827
Mike Travisc681d0b2011-05-28 13:15:05 -05002828 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002829 if (!iova)
2830 goto error;
2831
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002832 /*
2833 * Check if DMAR supports zero-length reads on write only
2834 * mappings..
2835 */
2836 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002837 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002838 prot |= DMA_PTE_READ;
2839 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2840 prot |= DMA_PTE_WRITE;
2841 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002842 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002843 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002844 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002845 * is not a big problem
2846 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002847 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002848 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002849 if (ret)
2850 goto error;
2851
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002852 /* it's a non-present to present mapping. Only flush if caching mode */
2853 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002854 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002855 else
Weidong Han8c11e792008-12-08 15:29:22 +08002856 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002857
David Woodhouse03d6a242009-06-28 15:33:46 +01002858 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2859 start_paddr += paddr & ~PAGE_MASK;
2860 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002861
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002862error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002863 if (iova)
2864 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002865 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002866 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002867 return 0;
2868}
2869
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002870static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2871 unsigned long offset, size_t size,
2872 enum dma_data_direction dir,
2873 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002874{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002875 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2876 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002877}
2878
mark gross5e0d2a62008-03-04 15:22:08 -08002879static void flush_unmaps(void)
2880{
mark gross80b20dd2008-04-18 13:53:58 -07002881 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002882
mark gross5e0d2a62008-03-04 15:22:08 -08002883 timer_on = 0;
2884
2885 /* just flush them all */
2886 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002887 struct intel_iommu *iommu = g_iommus[i];
2888 if (!iommu)
2889 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002890
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002891 if (!deferred_flush[i].next)
2892 continue;
2893
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002894 /* In caching mode, global flushes turn emulation expensive */
2895 if (!cap_caching_mode(iommu->cap))
2896 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002897 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002898 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002899 unsigned long mask;
2900 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002901 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002902
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002903 /* On real hardware multiple invalidations are expensive */
2904 if (cap_caching_mode(iommu->cap))
2905 iommu_flush_iotlb_psi(iommu, domain->id,
2906 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2907 else {
2908 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2909 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2910 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2911 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002912 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002913 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002914 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002915 }
2916
mark gross5e0d2a62008-03-04 15:22:08 -08002917 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002918}
2919
2920static void flush_unmaps_timeout(unsigned long data)
2921{
mark gross80b20dd2008-04-18 13:53:58 -07002922 unsigned long flags;
2923
2924 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002925 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002926 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002927}
2928
2929static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2930{
2931 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002932 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002933 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002934
2935 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002936 if (list_size == HIGH_WATER_MARK)
2937 flush_unmaps();
2938
Weidong Han8c11e792008-12-08 15:29:22 +08002939 iommu = domain_get_iommu(dom);
2940 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002941
mark gross80b20dd2008-04-18 13:53:58 -07002942 next = deferred_flush[iommu_id].next;
2943 deferred_flush[iommu_id].domain[next] = dom;
2944 deferred_flush[iommu_id].iova[next] = iova;
2945 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002946
2947 if (!timer_on) {
2948 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2949 timer_on = 1;
2950 }
2951 list_size++;
2952 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2953}
2954
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002955static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2956 size_t size, enum dma_data_direction dir,
2957 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002958{
2959 struct pci_dev *pdev = to_pci_dev(dev);
2960 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002961 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002962 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002963 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002964
David Woodhouse73676832009-07-04 14:08:36 +01002965 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002966 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002967
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002968 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002969 BUG_ON(!domain);
2970
Weidong Han8c11e792008-12-08 15:29:22 +08002971 iommu = domain_get_iommu(domain);
2972
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002973 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002974 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2975 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002976 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002977
David Woodhoused794dc92009-06-28 00:27:49 +01002978 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2979 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002980
David Woodhoused794dc92009-06-28 00:27:49 +01002981 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2982 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002983
2984 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002985 dma_pte_clear_range(domain, start_pfn, last_pfn);
2986
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002987 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002988 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2989
mark gross5e0d2a62008-03-04 15:22:08 -08002990 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002991 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002992 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002993 /* free iova */
2994 __free_iova(&domain->iovad, iova);
2995 } else {
2996 add_unmap(domain, iova);
2997 /*
2998 * queue up the release of the unmap to save the 1/6th of the
2999 * cpu used up by the iotlb flush operation...
3000 */
mark gross5e0d2a62008-03-04 15:22:08 -08003001 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003002}
3003
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003004static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003005 dma_addr_t *dma_handle, gfp_t flags,
3006 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003007{
3008 void *vaddr;
3009 int order;
3010
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003011 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003012 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07003013
3014 if (!iommu_no_mapping(hwdev))
3015 flags &= ~(GFP_DMA | GFP_DMA32);
3016 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
3017 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
3018 flags |= GFP_DMA;
3019 else
3020 flags |= GFP_DMA32;
3021 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003022
3023 vaddr = (void *)__get_free_pages(flags, order);
3024 if (!vaddr)
3025 return NULL;
3026 memset(vaddr, 0, size);
3027
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003028 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
3029 DMA_BIDIRECTIONAL,
3030 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003031 if (*dma_handle)
3032 return vaddr;
3033 free_pages((unsigned long)vaddr, order);
3034 return NULL;
3035}
3036
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003037static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003038 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003039{
3040 int order;
3041
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003042 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003043 order = get_order(size);
3044
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003045 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003046 free_pages((unsigned long)vaddr, order);
3047}
3048
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003049static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3050 int nelems, enum dma_data_direction dir,
3051 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003052{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003053 struct pci_dev *pdev = to_pci_dev(hwdev);
3054 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003055 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003056 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003057 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003058
David Woodhouse73676832009-07-04 14:08:36 +01003059 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003060 return;
3061
3062 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003063 BUG_ON(!domain);
3064
3065 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003066
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003067 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003068 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3069 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003070 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003071
David Woodhoused794dc92009-06-28 00:27:49 +01003072 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3073 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003074
3075 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003076 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003077
David Woodhoused794dc92009-06-28 00:27:49 +01003078 /* free page tables */
3079 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3080
David Woodhouseacea0012009-07-14 01:55:11 +01003081 if (intel_iommu_strict) {
3082 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003083 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003084 /* free iova */
3085 __free_iova(&domain->iovad, iova);
3086 } else {
3087 add_unmap(domain, iova);
3088 /*
3089 * queue up the release of the unmap to save the 1/6th of the
3090 * cpu used up by the iotlb flush operation...
3091 */
3092 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003093}
3094
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003095static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003096 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003097{
3098 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003099 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003100
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003101 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003102 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003103 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003104 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003105 }
3106 return nelems;
3107}
3108
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003109static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3110 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003111{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003112 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003113 struct pci_dev *pdev = to_pci_dev(hwdev);
3114 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003115 size_t size = 0;
3116 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003117 struct iova *iova = NULL;
3118 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003119 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003120 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003121 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003122
3123 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003124 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003125 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003126
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003127 domain = get_valid_domain_for_dev(pdev);
3128 if (!domain)
3129 return 0;
3130
Weidong Han8c11e792008-12-08 15:29:22 +08003131 iommu = domain_get_iommu(domain);
3132
David Woodhouseb536d242009-06-28 14:49:31 +01003133 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003134 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003135
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003136 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3137 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003138 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003139 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003140 return 0;
3141 }
3142
3143 /*
3144 * Check if DMAR supports zero-length reads on write only
3145 * mappings..
3146 */
3147 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003148 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003149 prot |= DMA_PTE_READ;
3150 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3151 prot |= DMA_PTE_WRITE;
3152
David Woodhouseb536d242009-06-28 14:49:31 +01003153 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003154
Fenghua Yuf5329592009-08-04 15:09:37 -07003155 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003156 if (unlikely(ret)) {
3157 /* clear the page */
3158 dma_pte_clear_range(domain, start_vpfn,
3159 start_vpfn + size - 1);
3160 /* free page tables */
3161 dma_pte_free_pagetable(domain, start_vpfn,
3162 start_vpfn + size - 1);
3163 /* free iova */
3164 __free_iova(&domain->iovad, iova);
3165 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003166 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003167
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003168 /* it's a non-present to present mapping. Only flush if caching mode */
3169 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003170 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003171 else
Weidong Han8c11e792008-12-08 15:29:22 +08003172 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003173
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003174 return nelems;
3175}
3176
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003177static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3178{
3179 return !dma_addr;
3180}
3181
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003182struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003183 .alloc = intel_alloc_coherent,
3184 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003185 .map_sg = intel_map_sg,
3186 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003187 .map_page = intel_map_page,
3188 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003189 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003190};
3191
3192static inline int iommu_domain_cache_init(void)
3193{
3194 int ret = 0;
3195
3196 iommu_domain_cache = kmem_cache_create("iommu_domain",
3197 sizeof(struct dmar_domain),
3198 0,
3199 SLAB_HWCACHE_ALIGN,
3200
3201 NULL);
3202 if (!iommu_domain_cache) {
3203 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3204 ret = -ENOMEM;
3205 }
3206
3207 return ret;
3208}
3209
3210static inline int iommu_devinfo_cache_init(void)
3211{
3212 int ret = 0;
3213
3214 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3215 sizeof(struct device_domain_info),
3216 0,
3217 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003218 NULL);
3219 if (!iommu_devinfo_cache) {
3220 printk(KERN_ERR "Couldn't create devinfo cache\n");
3221 ret = -ENOMEM;
3222 }
3223
3224 return ret;
3225}
3226
3227static inline int iommu_iova_cache_init(void)
3228{
3229 int ret = 0;
3230
3231 iommu_iova_cache = kmem_cache_create("iommu_iova",
3232 sizeof(struct iova),
3233 0,
3234 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003235 NULL);
3236 if (!iommu_iova_cache) {
3237 printk(KERN_ERR "Couldn't create iova cache\n");
3238 ret = -ENOMEM;
3239 }
3240
3241 return ret;
3242}
3243
3244static int __init iommu_init_mempool(void)
3245{
3246 int ret;
3247 ret = iommu_iova_cache_init();
3248 if (ret)
3249 return ret;
3250
3251 ret = iommu_domain_cache_init();
3252 if (ret)
3253 goto domain_error;
3254
3255 ret = iommu_devinfo_cache_init();
3256 if (!ret)
3257 return ret;
3258
3259 kmem_cache_destroy(iommu_domain_cache);
3260domain_error:
3261 kmem_cache_destroy(iommu_iova_cache);
3262
3263 return -ENOMEM;
3264}
3265
3266static void __init iommu_exit_mempool(void)
3267{
3268 kmem_cache_destroy(iommu_devinfo_cache);
3269 kmem_cache_destroy(iommu_domain_cache);
3270 kmem_cache_destroy(iommu_iova_cache);
3271
3272}
3273
Dan Williams556ab452010-07-23 15:47:56 -07003274static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3275{
3276 struct dmar_drhd_unit *drhd;
3277 u32 vtbar;
3278 int rc;
3279
3280 /* We know that this device on this chipset has its own IOMMU.
3281 * If we find it under a different IOMMU, then the BIOS is lying
3282 * to us. Hope that the IOMMU for this device is actually
3283 * disabled, and it needs no translation...
3284 */
3285 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3286 if (rc) {
3287 /* "can't" happen */
3288 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3289 return;
3290 }
3291 vtbar &= 0xffff0000;
3292
3293 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3294 drhd = dmar_find_matched_drhd_unit(pdev);
3295 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3296 TAINT_FIRMWARE_WORKAROUND,
3297 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3298 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3299}
3300DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3301
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003302static void __init init_no_remapping_devices(void)
3303{
3304 struct dmar_drhd_unit *drhd;
3305
3306 for_each_drhd_unit(drhd) {
3307 if (!drhd->include_all) {
3308 int i;
3309 for (i = 0; i < drhd->devices_cnt; i++)
3310 if (drhd->devices[i] != NULL)
3311 break;
3312 /* ignore DMAR unit if no pci devices exist */
3313 if (i == drhd->devices_cnt)
3314 drhd->ignored = 1;
3315 }
3316 }
3317
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003318 for_each_drhd_unit(drhd) {
3319 int i;
3320 if (drhd->ignored || drhd->include_all)
3321 continue;
3322
3323 for (i = 0; i < drhd->devices_cnt; i++)
3324 if (drhd->devices[i] &&
David Woodhousec0771df2011-10-14 20:59:46 +01003325 !IS_GFX_DEVICE(drhd->devices[i]))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003326 break;
3327
3328 if (i < drhd->devices_cnt)
3329 continue;
3330
David Woodhousec0771df2011-10-14 20:59:46 +01003331 /* This IOMMU has *only* gfx devices. Either bypass it or
3332 set the gfx_mapped flag, as appropriate */
3333 if (dmar_map_gfx) {
3334 intel_iommu_gfx_mapped = 1;
3335 } else {
3336 drhd->ignored = 1;
3337 for (i = 0; i < drhd->devices_cnt; i++) {
3338 if (!drhd->devices[i])
3339 continue;
3340 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3341 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003342 }
3343 }
3344}
3345
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003346#ifdef CONFIG_SUSPEND
3347static int init_iommu_hw(void)
3348{
3349 struct dmar_drhd_unit *drhd;
3350 struct intel_iommu *iommu = NULL;
3351
3352 for_each_active_iommu(iommu, drhd)
3353 if (iommu->qi)
3354 dmar_reenable_qi(iommu);
3355
Joseph Cihulab7792602011-05-03 00:08:37 -07003356 for_each_iommu(iommu, drhd) {
3357 if (drhd->ignored) {
3358 /*
3359 * we always have to disable PMRs or DMA may fail on
3360 * this device
3361 */
3362 if (force_on)
3363 iommu_disable_protect_mem_regions(iommu);
3364 continue;
3365 }
3366
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003367 iommu_flush_write_buffer(iommu);
3368
3369 iommu_set_root_entry(iommu);
3370
3371 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003372 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003373 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003374 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003375 if (iommu_enable_translation(iommu))
3376 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003377 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003378 }
3379
3380 return 0;
3381}
3382
3383static void iommu_flush_all(void)
3384{
3385 struct dmar_drhd_unit *drhd;
3386 struct intel_iommu *iommu;
3387
3388 for_each_active_iommu(iommu, drhd) {
3389 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003390 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003391 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003392 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003393 }
3394}
3395
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003396static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003397{
3398 struct dmar_drhd_unit *drhd;
3399 struct intel_iommu *iommu = NULL;
3400 unsigned long flag;
3401
3402 for_each_active_iommu(iommu, drhd) {
3403 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3404 GFP_ATOMIC);
3405 if (!iommu->iommu_state)
3406 goto nomem;
3407 }
3408
3409 iommu_flush_all();
3410
3411 for_each_active_iommu(iommu, drhd) {
3412 iommu_disable_translation(iommu);
3413
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003414 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003415
3416 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3417 readl(iommu->reg + DMAR_FECTL_REG);
3418 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3419 readl(iommu->reg + DMAR_FEDATA_REG);
3420 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3421 readl(iommu->reg + DMAR_FEADDR_REG);
3422 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3423 readl(iommu->reg + DMAR_FEUADDR_REG);
3424
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003425 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003426 }
3427 return 0;
3428
3429nomem:
3430 for_each_active_iommu(iommu, drhd)
3431 kfree(iommu->iommu_state);
3432
3433 return -ENOMEM;
3434}
3435
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003436static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003437{
3438 struct dmar_drhd_unit *drhd;
3439 struct intel_iommu *iommu = NULL;
3440 unsigned long flag;
3441
3442 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003443 if (force_on)
3444 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3445 else
3446 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003447 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003448 }
3449
3450 for_each_active_iommu(iommu, drhd) {
3451
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003452 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003453
3454 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3455 iommu->reg + DMAR_FECTL_REG);
3456 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3457 iommu->reg + DMAR_FEDATA_REG);
3458 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3459 iommu->reg + DMAR_FEADDR_REG);
3460 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3461 iommu->reg + DMAR_FEUADDR_REG);
3462
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003463 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003464 }
3465
3466 for_each_active_iommu(iommu, drhd)
3467 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003468}
3469
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003470static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003471 .resume = iommu_resume,
3472 .suspend = iommu_suspend,
3473};
3474
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003475static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003476{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003477 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003478}
3479
3480#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003481static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003482#endif /* CONFIG_PM */
3483
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003484LIST_HEAD(dmar_rmrr_units);
3485
3486static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3487{
3488 list_add(&rmrr->list, &dmar_rmrr_units);
3489}
3490
3491
3492int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3493{
3494 struct acpi_dmar_reserved_memory *rmrr;
3495 struct dmar_rmrr_unit *rmrru;
3496
3497 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3498 if (!rmrru)
3499 return -ENOMEM;
3500
3501 rmrru->hdr = header;
3502 rmrr = (struct acpi_dmar_reserved_memory *)header;
3503 rmrru->base_address = rmrr->base_address;
3504 rmrru->end_address = rmrr->end_address;
3505
3506 dmar_register_rmrr_unit(rmrru);
3507 return 0;
3508}
3509
3510static int __init
3511rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3512{
3513 struct acpi_dmar_reserved_memory *rmrr;
3514 int ret;
3515
3516 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
3517 ret = dmar_parse_dev_scope((void *)(rmrr + 1),
3518 ((void *)rmrr) + rmrr->header.length,
3519 &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
3520
3521 if (ret || (rmrru->devices_cnt == 0)) {
3522 list_del(&rmrru->list);
3523 kfree(rmrru);
3524 }
3525 return ret;
3526}
3527
3528static LIST_HEAD(dmar_atsr_units);
3529
3530int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3531{
3532 struct acpi_dmar_atsr *atsr;
3533 struct dmar_atsr_unit *atsru;
3534
3535 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3536 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3537 if (!atsru)
3538 return -ENOMEM;
3539
3540 atsru->hdr = hdr;
3541 atsru->include_all = atsr->flags & 0x1;
3542
3543 list_add(&atsru->list, &dmar_atsr_units);
3544
3545 return 0;
3546}
3547
3548static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3549{
3550 int rc;
3551 struct acpi_dmar_atsr *atsr;
3552
3553 if (atsru->include_all)
3554 return 0;
3555
3556 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3557 rc = dmar_parse_dev_scope((void *)(atsr + 1),
3558 (void *)atsr + atsr->header.length,
3559 &atsru->devices_cnt, &atsru->devices,
3560 atsr->segment);
3561 if (rc || !atsru->devices_cnt) {
3562 list_del(&atsru->list);
3563 kfree(atsru);
3564 }
3565
3566 return rc;
3567}
3568
3569int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3570{
3571 int i;
3572 struct pci_bus *bus;
3573 struct acpi_dmar_atsr *atsr;
3574 struct dmar_atsr_unit *atsru;
3575
3576 dev = pci_physfn(dev);
3577
3578 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3579 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3580 if (atsr->segment == pci_domain_nr(dev->bus))
3581 goto found;
3582 }
3583
3584 return 0;
3585
3586found:
3587 for (bus = dev->bus; bus; bus = bus->parent) {
3588 struct pci_dev *bridge = bus->self;
3589
3590 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003591 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003592 return 0;
3593
Yijing Wang62f87c02012-07-24 17:20:03 +08003594 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003595 for (i = 0; i < atsru->devices_cnt; i++)
3596 if (atsru->devices[i] == bridge)
3597 return 1;
3598 break;
3599 }
3600 }
3601
3602 if (atsru->include_all)
3603 return 1;
3604
3605 return 0;
3606}
3607
Sergey Senozhatskyc8f369a2011-10-26 18:45:39 +03003608int __init dmar_parse_rmrr_atsr_dev(void)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003609{
3610 struct dmar_rmrr_unit *rmrr, *rmrr_n;
3611 struct dmar_atsr_unit *atsr, *atsr_n;
3612 int ret = 0;
3613
3614 list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
3615 ret = rmrr_parse_dev(rmrr);
3616 if (ret)
3617 return ret;
3618 }
3619
3620 list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
3621 ret = atsr_parse_dev(atsr);
3622 if (ret)
3623 return ret;
3624 }
3625
3626 return ret;
3627}
3628
Fenghua Yu99dcade2009-11-11 07:23:06 -08003629/*
3630 * Here we only respond to action of unbound device from driver.
3631 *
3632 * Added device is not attached to its DMAR domain here yet. That will happen
3633 * when mapping the device to iova.
3634 */
3635static int device_notifier(struct notifier_block *nb,
3636 unsigned long action, void *data)
3637{
3638 struct device *dev = data;
3639 struct pci_dev *pdev = to_pci_dev(dev);
3640 struct dmar_domain *domain;
3641
David Woodhouse44cd6132009-12-02 10:18:30 +00003642 if (iommu_no_mapping(dev))
3643 return 0;
3644
Fenghua Yu99dcade2009-11-11 07:23:06 -08003645 domain = find_domain(pdev);
3646 if (!domain)
3647 return 0;
3648
Alex Williamsona97590e2011-03-04 14:52:16 -07003649 if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
Fenghua Yu99dcade2009-11-11 07:23:06 -08003650 domain_remove_one_dev_info(domain, pdev);
3651
Alex Williamsona97590e2011-03-04 14:52:16 -07003652 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3653 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3654 list_empty(&domain->devices))
3655 domain_exit(domain);
3656 }
3657
Fenghua Yu99dcade2009-11-11 07:23:06 -08003658 return 0;
3659}
3660
3661static struct notifier_block device_nb = {
3662 .notifier_call = device_notifier,
3663};
3664
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003665int __init intel_iommu_init(void)
3666{
3667 int ret = 0;
Takao Indoh3a93c842013-04-23 17:35:03 +09003668 struct dmar_drhd_unit *drhd;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003669
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003670 /* VT-d is required for a TXT/tboot launch, so enforce that */
3671 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003672
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003673 if (dmar_table_init()) {
3674 if (force_on)
3675 panic("tboot: Failed to initialize DMAR table\n");
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003676 return -ENODEV;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003677 }
3678
Takao Indoh3a93c842013-04-23 17:35:03 +09003679 /*
3680 * Disable translation if already enabled prior to OS handover.
3681 */
3682 for_each_drhd_unit(drhd) {
3683 struct intel_iommu *iommu;
3684
3685 if (drhd->ignored)
3686 continue;
3687
3688 iommu = drhd->iommu;
3689 if (iommu->gcmd & DMA_GCMD_TE)
3690 iommu_disable_translation(iommu);
3691 }
3692
Suresh Siddhac2c72862011-08-23 17:05:19 -07003693 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003694 if (force_on)
3695 panic("tboot: Failed to initialize DMAR device scope\n");
3696 return -ENODEV;
3697 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003698
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003699 if (no_iommu || dmar_disabled)
Suresh Siddha2ae21012008-07-10 11:16:43 -07003700 return -ENODEV;
3701
Joseph Cihula51a63e62011-03-21 11:04:24 -07003702 if (iommu_init_mempool()) {
3703 if (force_on)
3704 panic("tboot: Failed to initialize iommu memory\n");
3705 return -ENODEV;
3706 }
3707
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003708 if (list_empty(&dmar_rmrr_units))
3709 printk(KERN_INFO "DMAR: No RMRR found\n");
3710
3711 if (list_empty(&dmar_atsr_units))
3712 printk(KERN_INFO "DMAR: No ATSR found\n");
3713
Joseph Cihula51a63e62011-03-21 11:04:24 -07003714 if (dmar_init_reserved_ranges()) {
3715 if (force_on)
3716 panic("tboot: Failed to reserve iommu ranges\n");
3717 return -ENODEV;
3718 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003719
3720 init_no_remapping_devices();
3721
Joseph Cihulab7792602011-05-03 00:08:37 -07003722 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003723 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003724 if (force_on)
3725 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003726 printk(KERN_ERR "IOMMU: dmar init failed\n");
3727 put_iova_domain(&reserved_iova_list);
3728 iommu_exit_mempool();
3729 return ret;
3730 }
3731 printk(KERN_INFO
3732 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3733
mark gross5e0d2a62008-03-04 15:22:08 -08003734 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003735#ifdef CONFIG_SWIOTLB
3736 swiotlb = 0;
3737#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003738 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003739
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003740 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003741
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003742 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003743
Fenghua Yu99dcade2009-11-11 07:23:06 -08003744 bus_register_notifier(&pci_bus_type, &device_nb);
3745
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003746 intel_iommu_enabled = 1;
3747
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003748 return 0;
3749}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003750
Han, Weidong3199aa62009-02-26 17:31:12 +08003751static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3752 struct pci_dev *pdev)
3753{
3754 struct pci_dev *tmp, *parent;
3755
3756 if (!iommu || !pdev)
3757 return;
3758
3759 /* dependent device detach */
3760 tmp = pci_find_upstream_pcie_bridge(pdev);
3761 /* Secondary interface's bus number and devfn 0 */
3762 if (tmp) {
3763 parent = pdev->bus->self;
3764 while (parent != tmp) {
3765 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01003766 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003767 parent = parent->bus->self;
3768 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003769 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003770 iommu_detach_dev(iommu,
3771 tmp->subordinate->number, 0);
3772 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01003773 iommu_detach_dev(iommu, tmp->bus->number,
3774 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003775 }
3776}
3777
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003778static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003779 struct pci_dev *pdev)
3780{
3781 struct device_domain_info *info;
3782 struct intel_iommu *iommu;
3783 unsigned long flags;
3784 int found = 0;
3785 struct list_head *entry, *tmp;
3786
David Woodhouse276dbf992009-04-04 01:45:37 +01003787 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3788 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003789 if (!iommu)
3790 return;
3791
3792 spin_lock_irqsave(&device_domain_lock, flags);
3793 list_for_each_safe(entry, tmp, &domain->devices) {
3794 info = list_entry(entry, struct device_domain_info, link);
Mike Habeck8519dc42011-05-28 13:15:07 -05003795 if (info->segment == pci_domain_nr(pdev->bus) &&
3796 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003797 info->devfn == pdev->devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01003798 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003799 spin_unlock_irqrestore(&device_domain_lock, flags);
3800
Yu Zhao93a23a72009-05-18 13:51:37 +08003801 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003802 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003803 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003804 free_devinfo_mem(info);
3805
3806 spin_lock_irqsave(&device_domain_lock, flags);
3807
3808 if (found)
3809 break;
3810 else
3811 continue;
3812 }
3813
3814 /* if there is no other devices under the same iommu
3815 * owned by this domain, clear this iommu in iommu_bmp
3816 * update iommu count and coherency
3817 */
David Woodhouse276dbf992009-04-04 01:45:37 +01003818 if (iommu == device_to_iommu(info->segment, info->bus,
3819 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003820 found = 1;
3821 }
3822
Roland Dreier3e7abe22011-07-20 06:22:21 -07003823 spin_unlock_irqrestore(&device_domain_lock, flags);
3824
Weidong Hanc7151a82008-12-08 22:51:37 +08003825 if (found == 0) {
3826 unsigned long tmp_flags;
3827 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003828 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003829 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003830 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003831 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003832
Alex Williamson9b4554b2011-05-24 12:19:04 -04003833 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3834 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3835 spin_lock_irqsave(&iommu->lock, tmp_flags);
3836 clear_bit(domain->id, iommu->domain_ids);
3837 iommu->domains[domain->id] = NULL;
3838 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3839 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003840 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003841}
3842
3843static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3844{
3845 struct device_domain_info *info;
3846 struct intel_iommu *iommu;
3847 unsigned long flags1, flags2;
3848
3849 spin_lock_irqsave(&device_domain_lock, flags1);
3850 while (!list_empty(&domain->devices)) {
3851 info = list_entry(domain->devices.next,
3852 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01003853 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003854 spin_unlock_irqrestore(&device_domain_lock, flags1);
3855
Yu Zhao93a23a72009-05-18 13:51:37 +08003856 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01003857 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003858 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003859 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003860
3861 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003862 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003863 */
3864 spin_lock_irqsave(&domain->iommu_lock, flags2);
3865 if (test_and_clear_bit(iommu->seq_id,
Mike Travis1b198bb2012-03-05 15:05:16 -08003866 domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08003867 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003868 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003869 }
3870 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3871
3872 free_devinfo_mem(info);
3873 spin_lock_irqsave(&device_domain_lock, flags1);
3874 }
3875 spin_unlock_irqrestore(&device_domain_lock, flags1);
3876}
3877
Weidong Han5e98c4b2008-12-08 23:03:27 +08003878/* domain id for virtual machine, it won't be set in context */
3879static unsigned long vm_domid;
3880
3881static struct dmar_domain *iommu_alloc_vm_domain(void)
3882{
3883 struct dmar_domain *domain;
3884
3885 domain = alloc_domain_mem();
3886 if (!domain)
3887 return NULL;
3888
3889 domain->id = vm_domid++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003890 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08003891 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003892 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3893
3894 return domain;
3895}
3896
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003897static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003898{
3899 int adjust_width;
3900
3901 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003902 spin_lock_init(&domain->iommu_lock);
3903
3904 domain_reserve_special_ranges(domain);
3905
3906 /* calculate AGAW */
3907 domain->gaw = guest_width;
3908 adjust_width = guestwidth_to_adjustwidth(guest_width);
3909 domain->agaw = width_to_agaw(adjust_width);
3910
3911 INIT_LIST_HEAD(&domain->devices);
3912
3913 domain->iommu_count = 0;
3914 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003915 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003916 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003917 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003918 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003919
3920 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003921 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003922 if (!domain->pgd)
3923 return -ENOMEM;
3924 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3925 return 0;
3926}
3927
3928static void iommu_free_vm_domain(struct dmar_domain *domain)
3929{
3930 unsigned long flags;
3931 struct dmar_drhd_unit *drhd;
3932 struct intel_iommu *iommu;
3933 unsigned long i;
3934 unsigned long ndomains;
3935
3936 for_each_drhd_unit(drhd) {
3937 if (drhd->ignored)
3938 continue;
3939 iommu = drhd->iommu;
3940
3941 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08003942 for_each_set_bit(i, iommu->domain_ids, ndomains) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003943 if (iommu->domains[i] == domain) {
3944 spin_lock_irqsave(&iommu->lock, flags);
3945 clear_bit(i, iommu->domain_ids);
3946 iommu->domains[i] = NULL;
3947 spin_unlock_irqrestore(&iommu->lock, flags);
3948 break;
3949 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08003950 }
3951 }
3952}
3953
3954static void vm_domain_exit(struct dmar_domain *domain)
3955{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003956 /* Domain 0 is reserved, so dont process it */
3957 if (!domain)
3958 return;
3959
3960 vm_domain_remove_all_dev_info(domain);
3961 /* destroy iovas */
3962 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003963
3964 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003965 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003966
3967 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003968 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003969
3970 iommu_free_vm_domain(domain);
3971 free_domain_mem(domain);
3972}
3973
Joerg Roedel5d450802008-12-03 14:52:32 +01003974static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003975{
Joerg Roedel5d450802008-12-03 14:52:32 +01003976 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003977
Joerg Roedel5d450802008-12-03 14:52:32 +01003978 dmar_domain = iommu_alloc_vm_domain();
3979 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003980 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003981 "intel_iommu_domain_init: dmar_domain == NULL\n");
3982 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003983 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003984 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003985 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003986 "intel_iommu_domain_init() failed\n");
3987 vm_domain_exit(dmar_domain);
3988 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003989 }
Allen Kay8140a952011-10-14 12:32:17 -07003990 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003991 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003992
Joerg Roedel8a0e7152012-01-26 19:40:54 +01003993 domain->geometry.aperture_start = 0;
3994 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
3995 domain->geometry.force_aperture = true;
3996
Joerg Roedel5d450802008-12-03 14:52:32 +01003997 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003998}
Kay, Allen M38717942008-09-09 18:37:29 +03003999
Joerg Roedel5d450802008-12-03 14:52:32 +01004000static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03004001{
Joerg Roedel5d450802008-12-03 14:52:32 +01004002 struct dmar_domain *dmar_domain = domain->priv;
4003
4004 domain->priv = NULL;
4005 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03004006}
Kay, Allen M38717942008-09-09 18:37:29 +03004007
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004008static int intel_iommu_attach_device(struct iommu_domain *domain,
4009 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004010{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004011 struct dmar_domain *dmar_domain = domain->priv;
4012 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004013 struct intel_iommu *iommu;
4014 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03004015
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004016 /* normally pdev is not mapped */
4017 if (unlikely(domain_context_mapped(pdev))) {
4018 struct dmar_domain *old_domain;
4019
4020 old_domain = find_domain(pdev);
4021 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004022 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
4023 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
4024 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004025 else
4026 domain_remove_dev_info(old_domain);
4027 }
4028 }
4029
David Woodhouse276dbf992009-04-04 01:45:37 +01004030 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
4031 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004032 if (!iommu)
4033 return -ENODEV;
4034
4035 /* check if this iommu agaw is sufficient for max mapped address */
4036 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01004037 if (addr_width > cap_mgaw(iommu->cap))
4038 addr_width = cap_mgaw(iommu->cap);
4039
4040 if (dmar_domain->max_addr > (1LL << addr_width)) {
4041 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004042 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01004043 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004044 return -EFAULT;
4045 }
Tom Lyona99c47a2010-05-17 08:20:45 +01004046 dmar_domain->gaw = addr_width;
4047
4048 /*
4049 * Knock out extra levels of page tables if necessary
4050 */
4051 while (iommu->agaw < dmar_domain->agaw) {
4052 struct dma_pte *pte;
4053
4054 pte = dmar_domain->pgd;
4055 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08004056 dmar_domain->pgd = (struct dma_pte *)
4057 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01004058 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01004059 }
4060 dmar_domain->agaw--;
4061 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004062
David Woodhouse5fe60f42009-08-09 10:53:41 +01004063 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004064}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004065
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004066static void intel_iommu_detach_device(struct iommu_domain *domain,
4067 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004068{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004069 struct dmar_domain *dmar_domain = domain->priv;
4070 struct pci_dev *pdev = to_pci_dev(dev);
4071
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004072 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03004073}
Kay, Allen M38717942008-09-09 18:37:29 +03004074
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004075static int intel_iommu_map(struct iommu_domain *domain,
4076 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004077 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03004078{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004079 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004080 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004081 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004082 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004083
Joerg Roedeldde57a22008-12-03 15:04:09 +01004084 if (iommu_prot & IOMMU_READ)
4085 prot |= DMA_PTE_READ;
4086 if (iommu_prot & IOMMU_WRITE)
4087 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08004088 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4089 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004090
David Woodhouse163cc522009-06-28 00:51:17 +01004091 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004092 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004093 u64 end;
4094
4095 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01004096 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004097 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004098 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004099 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004100 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004101 return -EFAULT;
4102 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004103 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004104 }
David Woodhousead051222009-06-28 14:22:28 +01004105 /* Round up size to next multiple of PAGE_SIZE, if it and
4106 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004107 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004108 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4109 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004110 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004111}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004112
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004113static size_t intel_iommu_unmap(struct iommu_domain *domain,
4114 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004115{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004116 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07004117 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01004118
Allen Kay292827c2011-10-14 12:31:54 -07004119 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004120 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004121
David Woodhouse163cc522009-06-28 00:51:17 +01004122 if (dmar_domain->max_addr == iova + size)
4123 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004124
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004125 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004126}
Kay, Allen M38717942008-09-09 18:37:29 +03004127
Joerg Roedeld14d6572008-12-03 15:06:57 +01004128static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
4129 unsigned long iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004130{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004131 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004132 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004133 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004134
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004135 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004136 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004137 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004138
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004139 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004140}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004141
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004142static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4143 unsigned long cap)
4144{
4145 struct dmar_domain *dmar_domain = domain->priv;
4146
4147 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4148 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004149 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004150 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004151
4152 return 0;
4153}
4154
Alex Williamson783f1572012-05-30 14:19:43 -06004155static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
4156{
4157 pci_dev_put(*from);
4158 *from = to;
4159}
4160
4161#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4162
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004163static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004164{
4165 struct pci_dev *pdev = to_pci_dev(dev);
Alex Williamson3da4af02012-11-13 10:22:03 -07004166 struct pci_dev *bridge, *dma_pdev = NULL;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004167 struct iommu_group *group;
4168 int ret;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004169
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004170 if (!device_to_iommu(pci_domain_nr(pdev->bus),
4171 pdev->bus->number, pdev->devfn))
Alex Williamson70ae6f02011-10-21 15:56:11 -04004172 return -ENODEV;
4173
4174 bridge = pci_find_upstream_pcie_bridge(pdev);
4175 if (bridge) {
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004176 if (pci_is_pcie(bridge))
4177 dma_pdev = pci_get_domain_bus_and_slot(
4178 pci_domain_nr(pdev->bus),
4179 bridge->subordinate->number, 0);
Alex Williamson3da4af02012-11-13 10:22:03 -07004180 if (!dma_pdev)
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004181 dma_pdev = pci_dev_get(bridge);
4182 } else
4183 dma_pdev = pci_dev_get(pdev);
4184
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004185 /* Account for quirked devices */
Alex Williamson783f1572012-05-30 14:19:43 -06004186 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4187
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004188 /*
4189 * If it's a multifunction device that does not support our
4190 * required ACS flags, add to the same group as function 0.
4191 */
Alex Williamson783f1572012-05-30 14:19:43 -06004192 if (dma_pdev->multifunction &&
4193 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
4194 swap_pci_ref(&dma_pdev,
4195 pci_get_slot(dma_pdev->bus,
4196 PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
4197 0)));
4198
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004199 /*
4200 * Devices on the root bus go through the iommu. If that's not us,
4201 * find the next upstream device and test ACS up to the root bus.
4202 * Finding the next device may require skipping virtual buses.
4203 */
Alex Williamson783f1572012-05-30 14:19:43 -06004204 while (!pci_is_root_bus(dma_pdev->bus)) {
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004205 struct pci_bus *bus = dma_pdev->bus;
4206
4207 while (!bus->self) {
4208 if (!pci_is_root_bus(bus))
4209 bus = bus->parent;
4210 else
4211 goto root_bus;
4212 }
4213
4214 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
Alex Williamson783f1572012-05-30 14:19:43 -06004215 break;
4216
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004217 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
Alex Williamson70ae6f02011-10-21 15:56:11 -04004218 }
4219
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004220root_bus:
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004221 group = iommu_group_get(&dma_pdev->dev);
4222 pci_dev_put(dma_pdev);
4223 if (!group) {
4224 group = iommu_group_alloc();
4225 if (IS_ERR(group))
4226 return PTR_ERR(group);
4227 }
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004228
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004229 ret = iommu_group_add_device(group, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004230
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004231 iommu_group_put(group);
4232 return ret;
4233}
4234
4235static void intel_iommu_remove_device(struct device *dev)
4236{
4237 iommu_group_remove_device(dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004238}
4239
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004240static struct iommu_ops intel_iommu_ops = {
4241 .domain_init = intel_iommu_domain_init,
4242 .domain_destroy = intel_iommu_domain_destroy,
4243 .attach_dev = intel_iommu_attach_device,
4244 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004245 .map = intel_iommu_map,
4246 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004247 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004248 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004249 .add_device = intel_iommu_add_device,
4250 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004251 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004252};
David Woodhouse9af88142009-02-13 23:18:03 +00004253
Daniel Vetter94526182013-01-20 23:50:13 +01004254static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4255{
4256 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4257 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4258 dmar_map_gfx = 0;
4259}
4260
4261DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4262DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4263DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4264DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4265DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4266DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4267DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4268
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004269static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004270{
4271 /*
4272 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004273 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004274 */
4275 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4276 rwbf_quirk = 1;
4277}
4278
4279DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004280DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4281DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4282DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4283DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4284DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4285DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004286
Adam Jacksoneecfd572010-08-25 21:17:34 +01004287#define GGC 0x52
4288#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4289#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4290#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4291#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4292#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4293#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4294#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4295#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4296
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004297static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004298{
4299 unsigned short ggc;
4300
Adam Jacksoneecfd572010-08-25 21:17:34 +01004301 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004302 return;
4303
Adam Jacksoneecfd572010-08-25 21:17:34 +01004304 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004305 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4306 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004307 } else if (dmar_map_gfx) {
4308 /* we have to ensure the gfx device is idle before we flush */
4309 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4310 intel_iommu_strict = 1;
4311 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004312}
4313DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4314DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4315DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4316DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4317
David Woodhousee0fc7e02009-09-30 09:12:17 -07004318/* On Tylersburg chipsets, some BIOSes have been known to enable the
4319 ISOCH DMAR unit for the Azalia sound device, but not give it any
4320 TLB entries, which causes it to deadlock. Check for that. We do
4321 this in a function called from init_dmars(), instead of in a PCI
4322 quirk, because we don't want to print the obnoxious "BIOS broken"
4323 message if VT-d is actually disabled.
4324*/
4325static void __init check_tylersburg_isoch(void)
4326{
4327 struct pci_dev *pdev;
4328 uint32_t vtisochctrl;
4329
4330 /* If there's no Azalia in the system anyway, forget it. */
4331 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4332 if (!pdev)
4333 return;
4334 pci_dev_put(pdev);
4335
4336 /* System Management Registers. Might be hidden, in which case
4337 we can't do the sanity check. But that's OK, because the
4338 known-broken BIOSes _don't_ actually hide it, so far. */
4339 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4340 if (!pdev)
4341 return;
4342
4343 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4344 pci_dev_put(pdev);
4345 return;
4346 }
4347
4348 pci_dev_put(pdev);
4349
4350 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4351 if (vtisochctrl & 1)
4352 return;
4353
4354 /* Drop all bits other than the number of TLB entries */
4355 vtisochctrl &= 0x1c;
4356
4357 /* If we have the recommended number of TLB entries (16), fine. */
4358 if (vtisochctrl == 0x10)
4359 return;
4360
4361 /* Zero TLB entries? You get to ride the short bus to school. */
4362 if (!vtisochctrl) {
4363 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4364 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4365 dmi_get_system_info(DMI_BIOS_VENDOR),
4366 dmi_get_system_info(DMI_BIOS_VERSION),
4367 dmi_get_system_info(DMI_PRODUCT_VERSION));
4368 iommu_identity_mapping |= IDENTMAP_AZALIA;
4369 return;
4370 }
4371
4372 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4373 vtisochctrl);
4374}