blob: cc2d22243fc085f4dbc4b848bf8ed3faf21bb630 [file] [log] [blame]
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001/*
David Woodhouseea8ea462014-03-05 17:09:32 +00002 * Copyright © 2006-2014 Intel Corporation.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003 *
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 *
David Woodhouseea8ea462014-03-05 17:09:32 +000013 * Authors: David Woodhouse <dwmw2@infradead.org>,
14 * Ashok Raj <ashok.raj@intel.com>,
15 * Shaohua Li <shaohua.li@intel.com>,
16 * Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>,
17 * Fenghua Yu <fenghua.yu@intel.com>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070018 */
19
20#include <linux/init.h>
21#include <linux/bitmap.h>
mark gross5e0d2a62008-03-04 15:22:08 -080022#include <linux/debugfs.h>
Paul Gortmaker54485c32011-10-29 10:26:25 -040023#include <linux/export.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070024#include <linux/slab.h>
25#include <linux/irq.h>
26#include <linux/interrupt.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070027#include <linux/spinlock.h>
28#include <linux/pci.h>
29#include <linux/dmar.h>
30#include <linux/dma-mapping.h>
31#include <linux/mempool.h>
Jiang Liu75f05562014-02-19 14:07:37 +080032#include <linux/memory.h>
mark gross5e0d2a62008-03-04 15:22:08 -080033#include <linux/timer.h>
Kay, Allen M38717942008-09-09 18:37:29 +030034#include <linux/iova.h>
Joerg Roedel5d450802008-12-03 14:52:32 +010035#include <linux/iommu.h>
Kay, Allen M38717942008-09-09 18:37:29 +030036#include <linux/intel-iommu.h>
Rafael J. Wysocki134fac32011-03-23 22:16:14 +010037#include <linux/syscore_ops.h>
Shane Wang69575d32009-09-01 18:25:07 -070038#include <linux/tboot.h>
Stephen Rothwelladb2fe02009-08-31 15:24:23 +100039#include <linux/dmi.h>
Joerg Roedel5cdede22011-04-04 15:55:18 +020040#include <linux/pci-ats.h>
Tejun Heo0ee332c2011-12-08 10:22:09 -080041#include <linux/memblock.h>
Akinobu Mita36746432014-06-04 16:06:51 -070042#include <linux/dma-contiguous.h>
Suresh Siddha8a8f4222012-03-30 11:47:08 -070043#include <asm/irq_remapping.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070044#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090045#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070046
Joerg Roedel078e1ee2012-09-26 12:44:43 +020047#include "irq_remapping.h"
Varun Sethi61e015a2013-04-23 10:05:24 +053048#include "pci.h"
Joerg Roedel078e1ee2012-09-26 12:44:43 +020049
Fenghua Yu5b6985c2008-10-16 18:02:32 -070050#define ROOT_SIZE VTD_PAGE_SIZE
51#define CONTEXT_SIZE VTD_PAGE_SIZE
52
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070053#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
54#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070055#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070056
57#define IOAPIC_RANGE_START (0xfee00000)
58#define IOAPIC_RANGE_END (0xfeefffff)
59#define IOVA_START_ADDR (0x1000)
60
61#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
62
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070063#define MAX_AGAW_WIDTH 64
Jiang Liu5c645b32014-01-06 14:18:12 +080064#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070065
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{
Jiang Liu5c645b32014-01-06 14:18:12 +0800108 return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700109}
110
111static inline int width_to_agaw(int width)
112{
Jiang Liu5c645b32014-01-06 14:18:12 +0800113 return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700114}
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{
Jiang Liu5c645b32014-01-06 14:18:12 +0800143 return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100144}
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
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000290static inline u64 dma_pte_addr(struct dma_pte *pte)
291{
David Woodhousec85994e2009-07-01 19:21:24 +0100292#ifdef CONFIG_64BIT
293 return pte->val & VTD_PAGE_MASK;
294#else
295 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100296 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100297#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000298}
299
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000300static inline bool dma_pte_present(struct dma_pte *pte)
301{
302 return (pte->val & 3) != 0;
303}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000304
Allen Kay4399c8b2011-10-14 12:32:46 -0700305static inline bool dma_pte_superpage(struct dma_pte *pte)
306{
Joerg Roedelc3c75eb2014-07-04 11:19:10 +0200307 return (pte->val & DMA_PTE_LARGE_PAGE);
Allen Kay4399c8b2011-10-14 12:32:46 -0700308}
309
David Woodhouse75e6bf92009-07-02 11:21:16 +0100310static inline int first_pte_in_page(struct dma_pte *pte)
311{
312 return !((unsigned long)pte & ~VTD_PAGE_MASK);
313}
314
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700315/*
316 * This domain is a statically identity mapping domain.
317 * 1. This domain creats a static 1:1 mapping to all usable memory.
318 * 2. It maps to each iommu if successful.
319 * 3. Each iommu mapps to this domain if successful.
320 */
David Woodhouse19943b02009-08-04 16:19:20 +0100321static struct dmar_domain *si_domain;
322static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700323
Weidong Han3b5410e2008-12-08 09:17:15 +0800324/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100325#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800326
Weidong Han1ce28fe2008-12-08 16:35:39 +0800327/* domain represents a virtual machine, more than one devices
328 * across iommus may be owned in one domain, e.g. kvm guest.
329 */
330#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
331
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700332/* si_domain contains mulitple devices */
333#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
334
Mike Travis1b198bb2012-03-05 15:05:16 -0800335/* define the limit of IOMMUs supported in each domain */
336#ifdef CONFIG_X86
337# define IOMMU_UNITS_SUPPORTED MAX_IO_APICS
338#else
339# define IOMMU_UNITS_SUPPORTED 64
340#endif
341
Mark McLoughlin99126f72008-11-20 15:49:47 +0000342struct dmar_domain {
343 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700344 int nid; /* node id */
Mike Travis1b198bb2012-03-05 15:05:16 -0800345 DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
346 /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000347
348 struct list_head devices; /* all devices' list */
349 struct iova_domain iovad; /* iova's that belong to this domain */
350
351 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000352 int gaw; /* max guest address width */
353
354 /* adjusted guest address width, 0 is level 2 30-bit */
355 int agaw;
356
Weidong Han3b5410e2008-12-08 09:17:15 +0800357 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800358
359 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800360 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800361 int iommu_count; /* reference count of iommu */
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100362 int iommu_superpage;/* Level of superpages supported:
363 0 == 4KiB (no superpages), 1 == 2MiB,
364 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
Weidong Hanc7151a82008-12-08 22:51:37 +0800365 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800366 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000367};
368
Mark McLoughlina647dac2008-11-20 15:49:48 +0000369/* PCI domain-device relationship */
370struct device_domain_info {
371 struct list_head link; /* link to domain siblings */
372 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100373 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000374 u8 devfn; /* PCI devfn number */
David Woodhouse0bcb3e22014-03-06 17:12:03 +0000375 struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800376 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000377 struct dmar_domain *domain; /* pointer to domain */
378};
379
Jiang Liub94e4112014-02-19 14:07:25 +0800380struct dmar_rmrr_unit {
381 struct list_head list; /* list of rmrr units */
382 struct acpi_dmar_header *hdr; /* ACPI header */
383 u64 base_address; /* reserved base address*/
384 u64 end_address; /* reserved end address */
David Woodhouse832bd852014-03-07 15:08:36 +0000385 struct dmar_dev_scope *devices; /* target devices */
Jiang Liub94e4112014-02-19 14:07:25 +0800386 int devices_cnt; /* target device count */
387};
388
389struct dmar_atsr_unit {
390 struct list_head list; /* list of ATSR units */
391 struct acpi_dmar_header *hdr; /* ACPI header */
David Woodhouse832bd852014-03-07 15:08:36 +0000392 struct dmar_dev_scope *devices; /* target devices */
Jiang Liub94e4112014-02-19 14:07:25 +0800393 int devices_cnt; /* target device count */
394 u8 include_all:1; /* include all ports */
395};
396
397static LIST_HEAD(dmar_atsr_units);
398static LIST_HEAD(dmar_rmrr_units);
399
400#define for_each_rmrr_units(rmrr) \
401 list_for_each_entry(rmrr, &dmar_rmrr_units, list)
402
mark gross5e0d2a62008-03-04 15:22:08 -0800403static void flush_unmaps_timeout(unsigned long data);
404
Jiang Liub707cb02014-01-06 14:18:26 +0800405static DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
mark gross5e0d2a62008-03-04 15:22:08 -0800406
mark gross80b20dd2008-04-18 13:53:58 -0700407#define HIGH_WATER_MARK 250
408struct deferred_flush_tables {
409 int next;
410 struct iova *iova[HIGH_WATER_MARK];
411 struct dmar_domain *domain[HIGH_WATER_MARK];
David Woodhouseea8ea462014-03-05 17:09:32 +0000412 struct page *freelist[HIGH_WATER_MARK];
mark gross80b20dd2008-04-18 13:53:58 -0700413};
414
415static struct deferred_flush_tables *deferred_flush;
416
mark gross5e0d2a62008-03-04 15:22:08 -0800417/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800418static int g_num_of_iommus;
419
420static DEFINE_SPINLOCK(async_umap_flush_lock);
421static LIST_HEAD(unmaps_to_do);
422
423static int timer_on;
424static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800425
Jiang Liu92d03cc2014-02-19 14:07:28 +0800426static void domain_exit(struct dmar_domain *domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700427static void domain_remove_dev_info(struct dmar_domain *domain);
Jiang Liub94e4112014-02-19 14:07:25 +0800428static void domain_remove_one_dev_info(struct dmar_domain *domain,
David Woodhousebf9c9ed2014-03-09 16:19:13 -0700429 struct device *dev);
Jiang Liu92d03cc2014-02-19 14:07:28 +0800430static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
David Woodhouse0bcb3e22014-03-06 17:12:03 +0000431 struct device *dev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700432
Suresh Siddhad3f13812011-08-23 17:05:25 -0700433#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800434int dmar_disabled = 0;
435#else
436int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700437#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800438
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200439int intel_iommu_enabled = 0;
440EXPORT_SYMBOL_GPL(intel_iommu_enabled);
441
David Woodhouse2d9e6672010-06-15 10:57:57 +0100442static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700443static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800444static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100445static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700446
David Woodhousec0771df2011-10-14 20:59:46 +0100447int intel_iommu_gfx_mapped;
448EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
449
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700450#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
451static DEFINE_SPINLOCK(device_domain_lock);
452static LIST_HEAD(device_domain_list);
453
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100454static struct iommu_ops intel_iommu_ops;
455
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700456static int __init intel_iommu_setup(char *str)
457{
458 if (!str)
459 return -EINVAL;
460 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800461 if (!strncmp(str, "on", 2)) {
462 dmar_disabled = 0;
463 printk(KERN_INFO "Intel-IOMMU: enabled\n");
464 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700465 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800466 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700467 } else if (!strncmp(str, "igfx_off", 8)) {
468 dmar_map_gfx = 0;
469 printk(KERN_INFO
470 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700471 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800472 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700473 "Intel-IOMMU: Forcing DAC for PCI devices\n");
474 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800475 } else if (!strncmp(str, "strict", 6)) {
476 printk(KERN_INFO
477 "Intel-IOMMU: disable batched IOTLB flush\n");
478 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100479 } else if (!strncmp(str, "sp_off", 6)) {
480 printk(KERN_INFO
481 "Intel-IOMMU: disable supported super page\n");
482 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700483 }
484
485 str += strcspn(str, ",");
486 while (*str == ',')
487 str++;
488 }
489 return 0;
490}
491__setup("intel_iommu=", intel_iommu_setup);
492
493static struct kmem_cache *iommu_domain_cache;
494static struct kmem_cache *iommu_devinfo_cache;
495static struct kmem_cache *iommu_iova_cache;
496
Suresh Siddha4c923d42009-10-02 11:01:24 -0700497static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700498{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700499 struct page *page;
500 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700501
Suresh Siddha4c923d42009-10-02 11:01:24 -0700502 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
503 if (page)
504 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700505 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700506}
507
508static inline void free_pgtable_page(void *vaddr)
509{
510 free_page((unsigned long)vaddr);
511}
512
513static inline void *alloc_domain_mem(void)
514{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900515 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700516}
517
Kay, Allen M38717942008-09-09 18:37:29 +0300518static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700519{
520 kmem_cache_free(iommu_domain_cache, vaddr);
521}
522
523static inline void * alloc_devinfo_mem(void)
524{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900525 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700526}
527
528static inline void free_devinfo_mem(void *vaddr)
529{
530 kmem_cache_free(iommu_devinfo_cache, vaddr);
531}
532
533struct iova *alloc_iova_mem(void)
534{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900535 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700536}
537
538void free_iova_mem(struct iova *iova)
539{
540 kmem_cache_free(iommu_iova_cache, iova);
541}
542
Weidong Han1b573682008-12-08 15:34:06 +0800543
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700544static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800545{
546 unsigned long sagaw;
547 int agaw = -1;
548
549 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700550 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800551 agaw >= 0; agaw--) {
552 if (test_bit(agaw, &sagaw))
553 break;
554 }
555
556 return agaw;
557}
558
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700559/*
560 * Calculate max SAGAW for each iommu.
561 */
562int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
563{
564 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
565}
566
567/*
568 * calculate agaw for each iommu.
569 * "SAGAW" may be different across iommus, use a default agaw, and
570 * get a supported less agaw for iommus that don't support the default agaw.
571 */
572int iommu_calculate_agaw(struct intel_iommu *iommu)
573{
574 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
575}
576
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700577/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800578static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
579{
580 int iommu_id;
581
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700582 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800583 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700584 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800585
Mike Travis1b198bb2012-03-05 15:05:16 -0800586 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800587 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
588 return NULL;
589
590 return g_iommus[iommu_id];
591}
592
Weidong Han8e6040972008-12-08 15:49:06 +0800593static void domain_update_iommu_coherency(struct dmar_domain *domain)
594{
David Woodhoused0501962014-03-11 17:10:29 -0700595 struct dmar_drhd_unit *drhd;
596 struct intel_iommu *iommu;
597 int i, found = 0;
Weidong Han8e6040972008-12-08 15:49:06 +0800598
David Woodhoused0501962014-03-11 17:10:29 -0700599 domain->iommu_coherency = 1;
Weidong Han8e6040972008-12-08 15:49:06 +0800600
Mike Travis1b198bb2012-03-05 15:05:16 -0800601 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
David Woodhoused0501962014-03-11 17:10:29 -0700602 found = 1;
Weidong Han8e6040972008-12-08 15:49:06 +0800603 if (!ecap_coherent(g_iommus[i]->ecap)) {
604 domain->iommu_coherency = 0;
605 break;
606 }
Weidong Han8e6040972008-12-08 15:49:06 +0800607 }
David Woodhoused0501962014-03-11 17:10:29 -0700608 if (found)
609 return;
610
611 /* No hardware attached; use lowest common denominator */
612 rcu_read_lock();
613 for_each_active_iommu(iommu, drhd) {
614 if (!ecap_coherent(iommu->ecap)) {
615 domain->iommu_coherency = 0;
616 break;
617 }
618 }
619 rcu_read_unlock();
Weidong Han8e6040972008-12-08 15:49:06 +0800620}
621
Sheng Yang58c610b2009-03-18 15:33:05 +0800622static void domain_update_iommu_snooping(struct dmar_domain *domain)
623{
624 int i;
625
626 domain->iommu_snooping = 1;
627
Mike Travis1b198bb2012-03-05 15:05:16 -0800628 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800629 if (!ecap_sc_support(g_iommus[i]->ecap)) {
630 domain->iommu_snooping = 0;
631 break;
632 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800633 }
634}
635
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100636static void domain_update_iommu_superpage(struct dmar_domain *domain)
637{
Allen Kay8140a952011-10-14 12:32:17 -0700638 struct dmar_drhd_unit *drhd;
639 struct intel_iommu *iommu = NULL;
640 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100641
642 if (!intel_iommu_superpage) {
643 domain->iommu_superpage = 0;
644 return;
645 }
646
Allen Kay8140a952011-10-14 12:32:17 -0700647 /* set iommu_superpage to the smallest common denominator */
Jiang Liu0e242612014-02-19 14:07:34 +0800648 rcu_read_lock();
Allen Kay8140a952011-10-14 12:32:17 -0700649 for_each_active_iommu(iommu, drhd) {
650 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100651 if (!mask) {
652 break;
653 }
654 }
Jiang Liu0e242612014-02-19 14:07:34 +0800655 rcu_read_unlock();
656
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100657 domain->iommu_superpage = fls(mask);
658}
659
Sheng Yang58c610b2009-03-18 15:33:05 +0800660/* Some capabilities may be different across iommus */
661static void domain_update_iommu_cap(struct dmar_domain *domain)
662{
663 domain_update_iommu_coherency(domain);
664 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100665 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800666}
667
David Woodhouse156baca2014-03-09 14:00:57 -0700668static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800669{
670 struct dmar_drhd_unit *drhd = NULL;
Jiang Liub683b232014-02-19 14:07:32 +0800671 struct intel_iommu *iommu;
David Woodhouse156baca2014-03-09 14:00:57 -0700672 struct device *tmp;
673 struct pci_dev *ptmp, *pdev = NULL;
674 u16 segment;
Weidong Hanc7151a82008-12-08 22:51:37 +0800675 int i;
676
David Woodhouse156baca2014-03-09 14:00:57 -0700677 if (dev_is_pci(dev)) {
678 pdev = to_pci_dev(dev);
679 segment = pci_domain_nr(pdev->bus);
680 } else if (ACPI_COMPANION(dev))
681 dev = &ACPI_COMPANION(dev)->dev;
682
Jiang Liu0e242612014-02-19 14:07:34 +0800683 rcu_read_lock();
Jiang Liub683b232014-02-19 14:07:32 +0800684 for_each_active_iommu(iommu, drhd) {
David Woodhouse156baca2014-03-09 14:00:57 -0700685 if (pdev && segment != drhd->segment)
David Woodhouse276dbf992009-04-04 01:45:37 +0100686 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800687
Jiang Liub683b232014-02-19 14:07:32 +0800688 for_each_active_dev_scope(drhd->devices,
David Woodhouse156baca2014-03-09 14:00:57 -0700689 drhd->devices_cnt, i, tmp) {
690 if (tmp == dev) {
691 *bus = drhd->devices[i].bus;
692 *devfn = drhd->devices[i].devfn;
693 goto out;
694 }
695
696 if (!pdev || !dev_is_pci(tmp))
David Woodhouse832bd852014-03-07 15:08:36 +0000697 continue;
David Woodhouse156baca2014-03-09 14:00:57 -0700698
699 ptmp = to_pci_dev(tmp);
700 if (ptmp->subordinate &&
701 ptmp->subordinate->number <= pdev->bus->number &&
702 ptmp->subordinate->busn_res.end >= pdev->bus->number)
703 goto got_pdev;
David Woodhouse924b6232009-04-04 00:39:25 +0100704 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800705
David Woodhouse156baca2014-03-09 14:00:57 -0700706 if (pdev && drhd->include_all) {
707 got_pdev:
708 *bus = pdev->bus->number;
709 *devfn = pdev->devfn;
Jiang Liub683b232014-02-19 14:07:32 +0800710 goto out;
David Woodhouse156baca2014-03-09 14:00:57 -0700711 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800712 }
Jiang Liub683b232014-02-19 14:07:32 +0800713 iommu = NULL;
David Woodhouse156baca2014-03-09 14:00:57 -0700714 out:
Jiang Liu0e242612014-02-19 14:07:34 +0800715 rcu_read_unlock();
Weidong Hanc7151a82008-12-08 22:51:37 +0800716
Jiang Liub683b232014-02-19 14:07:32 +0800717 return iommu;
Weidong Hanc7151a82008-12-08 22:51:37 +0800718}
719
Weidong Han5331fe62008-12-08 23:00:00 +0800720static void domain_flush_cache(struct dmar_domain *domain,
721 void *addr, int size)
722{
723 if (!domain->iommu_coherency)
724 clflush_cache_range(addr, size);
725}
726
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700727/* Gets context entry for a given bus and devfn */
728static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
729 u8 bus, u8 devfn)
730{
731 struct root_entry *root;
732 struct context_entry *context;
733 unsigned long phy_addr;
734 unsigned long flags;
735
736 spin_lock_irqsave(&iommu->lock, flags);
737 root = &iommu->root_entry[bus];
738 context = get_context_addr_from_root(root);
739 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700740 context = (struct context_entry *)
741 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700742 if (!context) {
743 spin_unlock_irqrestore(&iommu->lock, flags);
744 return NULL;
745 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700746 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700747 phy_addr = virt_to_phys((void *)context);
748 set_root_value(root, phy_addr);
749 set_root_present(root);
750 __iommu_flush_cache(iommu, root, sizeof(*root));
751 }
752 spin_unlock_irqrestore(&iommu->lock, flags);
753 return &context[devfn];
754}
755
756static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
757{
758 struct root_entry *root;
759 struct context_entry *context;
760 int ret;
761 unsigned long flags;
762
763 spin_lock_irqsave(&iommu->lock, flags);
764 root = &iommu->root_entry[bus];
765 context = get_context_addr_from_root(root);
766 if (!context) {
767 ret = 0;
768 goto out;
769 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000770 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700771out:
772 spin_unlock_irqrestore(&iommu->lock, flags);
773 return ret;
774}
775
776static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
777{
778 struct root_entry *root;
779 struct context_entry *context;
780 unsigned long flags;
781
782 spin_lock_irqsave(&iommu->lock, flags);
783 root = &iommu->root_entry[bus];
784 context = get_context_addr_from_root(root);
785 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000786 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700787 __iommu_flush_cache(iommu, &context[devfn], \
788 sizeof(*context));
789 }
790 spin_unlock_irqrestore(&iommu->lock, flags);
791}
792
793static void free_context_table(struct intel_iommu *iommu)
794{
795 struct root_entry *root;
796 int i;
797 unsigned long flags;
798 struct context_entry *context;
799
800 spin_lock_irqsave(&iommu->lock, flags);
801 if (!iommu->root_entry) {
802 goto out;
803 }
804 for (i = 0; i < ROOT_ENTRY_NR; i++) {
805 root = &iommu->root_entry[i];
806 context = get_context_addr_from_root(root);
807 if (context)
808 free_pgtable_page(context);
809 }
810 free_pgtable_page(iommu->root_entry);
811 iommu->root_entry = NULL;
812out:
813 spin_unlock_irqrestore(&iommu->lock, flags);
814}
815
David Woodhouseb026fd22009-06-28 10:37:25 +0100816static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
David Woodhouse5cf0a762014-03-19 16:07:49 +0000817 unsigned long pfn, int *target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700818{
David Woodhouseb026fd22009-06-28 10:37:25 +0100819 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700820 struct dma_pte *parent, *pte = NULL;
821 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700822 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700823
824 BUG_ON(!domain->pgd);
Julian Stecklinaf9423602013-10-09 10:03:52 +0200825
826 if (addr_width < BITS_PER_LONG && pfn >> addr_width)
827 /* Address beyond IOMMU's addressing capabilities. */
828 return NULL;
829
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700830 parent = domain->pgd;
831
David Woodhouse5cf0a762014-03-19 16:07:49 +0000832 while (1) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700833 void *tmp_page;
834
David Woodhouseb026fd22009-06-28 10:37:25 +0100835 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700836 pte = &parent[offset];
David Woodhouse5cf0a762014-03-19 16:07:49 +0000837 if (!*target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100838 break;
David Woodhouse5cf0a762014-03-19 16:07:49 +0000839 if (level == *target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700840 break;
841
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000842 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100843 uint64_t pteval;
844
Suresh Siddha4c923d42009-10-02 11:01:24 -0700845 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700846
David Woodhouse206a73c2009-07-01 19:30:28 +0100847 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700848 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100849
David Woodhousec85994e2009-07-01 19:21:24 +0100850 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400851 pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
Yijing Wangeffad4b2014-05-26 20:13:47 +0800852 if (cmpxchg64(&pte->val, 0ULL, pteval))
David Woodhousec85994e2009-07-01 19:21:24 +0100853 /* Someone else set it while we were thinking; use theirs. */
854 free_pgtable_page(tmp_page);
Yijing Wangeffad4b2014-05-26 20:13:47 +0800855 else
David Woodhousec85994e2009-07-01 19:21:24 +0100856 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700857 }
David Woodhouse5cf0a762014-03-19 16:07:49 +0000858 if (level == 1)
859 break;
860
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000861 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700862 level--;
863 }
864
David Woodhouse5cf0a762014-03-19 16:07:49 +0000865 if (!*target_level)
866 *target_level = level;
867
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700868 return pte;
869}
870
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100871
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700872/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100873static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
874 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100875 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700876{
877 struct dma_pte *parent, *pte = NULL;
878 int total = agaw_to_level(domain->agaw);
879 int offset;
880
881 parent = domain->pgd;
882 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100883 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700884 pte = &parent[offset];
885 if (level == total)
886 return pte;
887
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100888 if (!dma_pte_present(pte)) {
889 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700890 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100891 }
892
Yijing Wange16922a2014-05-20 20:37:51 +0800893 if (dma_pte_superpage(pte)) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100894 *large_page = total;
895 return pte;
896 }
897
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000898 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700899 total--;
900 }
901 return NULL;
902}
903
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700904/* clear last level pte, a tlb flush should be followed */
David Woodhouse5cf0a762014-03-19 16:07:49 +0000905static void dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100906 unsigned long start_pfn,
907 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700908{
David Woodhouse04b18e62009-06-27 19:15:01 +0100909 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100910 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100911 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700912
David Woodhouse04b18e62009-06-27 19:15:01 +0100913 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100914 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700915 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100916
David Woodhouse04b18e62009-06-27 19:15:01 +0100917 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700918 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100919 large_page = 1;
920 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100921 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100922 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100923 continue;
924 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100925 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100926 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100927 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100928 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100929 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
930
David Woodhouse310a5ab2009-06-28 18:52:20 +0100931 domain_flush_cache(domain, first_pte,
932 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700933
934 } while (start_pfn && start_pfn <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700935}
936
Alex Williamson3269ee02013-06-15 10:27:19 -0600937static void dma_pte_free_level(struct dmar_domain *domain, int level,
938 struct dma_pte *pte, unsigned long pfn,
939 unsigned long start_pfn, unsigned long last_pfn)
940{
941 pfn = max(start_pfn, pfn);
942 pte = &pte[pfn_level_offset(pfn, level)];
943
944 do {
945 unsigned long level_pfn;
946 struct dma_pte *level_pte;
947
948 if (!dma_pte_present(pte) || dma_pte_superpage(pte))
949 goto next;
950
951 level_pfn = pfn & level_mask(level - 1);
952 level_pte = phys_to_virt(dma_pte_addr(pte));
953
954 if (level > 2)
955 dma_pte_free_level(domain, level - 1, level_pte,
956 level_pfn, start_pfn, last_pfn);
957
958 /* If range covers entire pagetable, free it */
959 if (!(start_pfn > level_pfn ||
Alex Williamson08336fd2014-01-21 15:48:18 -0800960 last_pfn < level_pfn + level_size(level) - 1)) {
Alex Williamson3269ee02013-06-15 10:27:19 -0600961 dma_clear_pte(pte);
962 domain_flush_cache(domain, pte, sizeof(*pte));
963 free_pgtable_page(level_pte);
964 }
965next:
966 pfn += level_size(level);
967 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
968}
969
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700970/* free page table pages. last level pte should already be cleared */
971static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100972 unsigned long start_pfn,
973 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700974{
David Woodhouse6660c632009-06-27 22:41:00 +0100975 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700976
David Woodhouse6660c632009-06-27 22:41:00 +0100977 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
978 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700979 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700980
David Woodhousef3a0a522009-06-30 03:40:07 +0100981 /* We don't need lock here; nobody else touches the iova range */
Alex Williamson3269ee02013-06-15 10:27:19 -0600982 dma_pte_free_level(domain, agaw_to_level(domain->agaw),
983 domain->pgd, 0, start_pfn, last_pfn);
David Woodhouse6660c632009-06-27 22:41:00 +0100984
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700985 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100986 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700987 free_pgtable_page(domain->pgd);
988 domain->pgd = NULL;
989 }
990}
991
David Woodhouseea8ea462014-03-05 17:09:32 +0000992/* When a page at a given level is being unlinked from its parent, we don't
993 need to *modify* it at all. All we need to do is make a list of all the
994 pages which can be freed just as soon as we've flushed the IOTLB and we
995 know the hardware page-walk will no longer touch them.
996 The 'pte' argument is the *parent* PTE, pointing to the page that is to
997 be freed. */
998static struct page *dma_pte_list_pagetables(struct dmar_domain *domain,
999 int level, struct dma_pte *pte,
1000 struct page *freelist)
1001{
1002 struct page *pg;
1003
1004 pg = pfn_to_page(dma_pte_addr(pte) >> PAGE_SHIFT);
1005 pg->freelist = freelist;
1006 freelist = pg;
1007
1008 if (level == 1)
1009 return freelist;
1010
Jiang Liuadeb25902014-04-09 10:20:39 +08001011 pte = page_address(pg);
1012 do {
David Woodhouseea8ea462014-03-05 17:09:32 +00001013 if (dma_pte_present(pte) && !dma_pte_superpage(pte))
1014 freelist = dma_pte_list_pagetables(domain, level - 1,
1015 pte, freelist);
Jiang Liuadeb25902014-04-09 10:20:39 +08001016 pte++;
1017 } while (!first_pte_in_page(pte));
David Woodhouseea8ea462014-03-05 17:09:32 +00001018
1019 return freelist;
1020}
1021
1022static struct page *dma_pte_clear_level(struct dmar_domain *domain, int level,
1023 struct dma_pte *pte, unsigned long pfn,
1024 unsigned long start_pfn,
1025 unsigned long last_pfn,
1026 struct page *freelist)
1027{
1028 struct dma_pte *first_pte = NULL, *last_pte = NULL;
1029
1030 pfn = max(start_pfn, pfn);
1031 pte = &pte[pfn_level_offset(pfn, level)];
1032
1033 do {
1034 unsigned long level_pfn;
1035
1036 if (!dma_pte_present(pte))
1037 goto next;
1038
1039 level_pfn = pfn & level_mask(level);
1040
1041 /* If range covers entire pagetable, free it */
1042 if (start_pfn <= level_pfn &&
1043 last_pfn >= level_pfn + level_size(level) - 1) {
1044 /* These suborbinate page tables are going away entirely. Don't
1045 bother to clear them; we're just going to *free* them. */
1046 if (level > 1 && !dma_pte_superpage(pte))
1047 freelist = dma_pte_list_pagetables(domain, level - 1, pte, freelist);
1048
1049 dma_clear_pte(pte);
1050 if (!first_pte)
1051 first_pte = pte;
1052 last_pte = pte;
1053 } else if (level > 1) {
1054 /* Recurse down into a level that isn't *entirely* obsolete */
1055 freelist = dma_pte_clear_level(domain, level - 1,
1056 phys_to_virt(dma_pte_addr(pte)),
1057 level_pfn, start_pfn, last_pfn,
1058 freelist);
1059 }
1060next:
1061 pfn += level_size(level);
1062 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
1063
1064 if (first_pte)
1065 domain_flush_cache(domain, first_pte,
1066 (void *)++last_pte - (void *)first_pte);
1067
1068 return freelist;
1069}
1070
1071/* We can't just free the pages because the IOMMU may still be walking
1072 the page tables, and may have cached the intermediate levels. The
1073 pages can only be freed after the IOTLB flush has been done. */
1074struct page *domain_unmap(struct dmar_domain *domain,
1075 unsigned long start_pfn,
1076 unsigned long last_pfn)
1077{
1078 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
1079 struct page *freelist = NULL;
1080
1081 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
1082 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
1083 BUG_ON(start_pfn > last_pfn);
1084
1085 /* we don't need lock here; nobody else touches the iova range */
1086 freelist = dma_pte_clear_level(domain, agaw_to_level(domain->agaw),
1087 domain->pgd, 0, start_pfn, last_pfn, NULL);
1088
1089 /* free pgd */
1090 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
1091 struct page *pgd_page = virt_to_page(domain->pgd);
1092 pgd_page->freelist = freelist;
1093 freelist = pgd_page;
1094
1095 domain->pgd = NULL;
1096 }
1097
1098 return freelist;
1099}
1100
1101void dma_free_pagelist(struct page *freelist)
1102{
1103 struct page *pg;
1104
1105 while ((pg = freelist)) {
1106 freelist = pg->freelist;
1107 free_pgtable_page(page_address(pg));
1108 }
1109}
1110
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001111/* iommu handling */
1112static int iommu_alloc_root_entry(struct intel_iommu *iommu)
1113{
1114 struct root_entry *root;
1115 unsigned long flags;
1116
Suresh Siddha4c923d42009-10-02 11:01:24 -07001117 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001118 if (!root)
1119 return -ENOMEM;
1120
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001121 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001122
1123 spin_lock_irqsave(&iommu->lock, flags);
1124 iommu->root_entry = root;
1125 spin_unlock_irqrestore(&iommu->lock, flags);
1126
1127 return 0;
1128}
1129
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001130static void iommu_set_root_entry(struct intel_iommu *iommu)
1131{
1132 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +01001133 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001134 unsigned long flag;
1135
1136 addr = iommu->root_entry;
1137
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001138 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001139 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
1140
David Woodhousec416daa2009-05-10 20:30:58 +01001141 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001142
1143 /* Make sure hardware complete it */
1144 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001145 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001146
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001147 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001148}
1149
1150static void iommu_flush_write_buffer(struct intel_iommu *iommu)
1151{
1152 u32 val;
1153 unsigned long flag;
1154
David Woodhouse9af88142009-02-13 23:18:03 +00001155 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001156 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001157
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001158 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +01001159 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001160
1161 /* Make sure hardware complete it */
1162 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001163 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001164
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001165 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001166}
1167
1168/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001169static void __iommu_flush_context(struct intel_iommu *iommu,
1170 u16 did, u16 source_id, u8 function_mask,
1171 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001172{
1173 u64 val = 0;
1174 unsigned long flag;
1175
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001176 switch (type) {
1177 case DMA_CCMD_GLOBAL_INVL:
1178 val = DMA_CCMD_GLOBAL_INVL;
1179 break;
1180 case DMA_CCMD_DOMAIN_INVL:
1181 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1182 break;
1183 case DMA_CCMD_DEVICE_INVL:
1184 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1185 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1186 break;
1187 default:
1188 BUG();
1189 }
1190 val |= DMA_CCMD_ICC;
1191
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001192 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001193 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1194
1195 /* Make sure hardware complete it */
1196 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1197 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1198
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001199 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001200}
1201
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001202/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001203static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1204 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001205{
1206 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1207 u64 val = 0, val_iva = 0;
1208 unsigned long flag;
1209
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001210 switch (type) {
1211 case DMA_TLB_GLOBAL_FLUSH:
1212 /* global flush doesn't need set IVA_REG */
1213 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1214 break;
1215 case DMA_TLB_DSI_FLUSH:
1216 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1217 break;
1218 case DMA_TLB_PSI_FLUSH:
1219 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
David Woodhouseea8ea462014-03-05 17:09:32 +00001220 /* IH bit is passed in as part of address */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001221 val_iva = size_order | addr;
1222 break;
1223 default:
1224 BUG();
1225 }
1226 /* Note: set drain read/write */
1227#if 0
1228 /*
1229 * This is probably to be super secure.. Looks like we can
1230 * ignore it without any impact.
1231 */
1232 if (cap_read_drain(iommu->cap))
1233 val |= DMA_TLB_READ_DRAIN;
1234#endif
1235 if (cap_write_drain(iommu->cap))
1236 val |= DMA_TLB_WRITE_DRAIN;
1237
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001238 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001239 /* Note: Only uses first TLB reg currently */
1240 if (val_iva)
1241 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1242 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1243
1244 /* Make sure hardware complete it */
1245 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1246 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1247
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001248 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001249
1250 /* check IOTLB invalidation granularity */
1251 if (DMA_TLB_IAIG(val) == 0)
1252 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1253 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1254 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001255 (unsigned long long)DMA_TLB_IIRG(type),
1256 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001257}
1258
David Woodhouse64ae8922014-03-09 12:52:30 -07001259static struct device_domain_info *
1260iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu,
1261 u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001262{
Yu Zhao93a23a72009-05-18 13:51:37 +08001263 int found = 0;
1264 unsigned long flags;
1265 struct device_domain_info *info;
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001266 struct pci_dev *pdev;
Yu Zhao93a23a72009-05-18 13:51:37 +08001267
1268 if (!ecap_dev_iotlb_support(iommu->ecap))
1269 return NULL;
1270
1271 if (!iommu->qi)
1272 return NULL;
1273
1274 spin_lock_irqsave(&device_domain_lock, flags);
1275 list_for_each_entry(info, &domain->devices, link)
1276 if (info->bus == bus && info->devfn == devfn) {
1277 found = 1;
1278 break;
1279 }
1280 spin_unlock_irqrestore(&device_domain_lock, flags);
1281
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001282 if (!found || !info->dev || !dev_is_pci(info->dev))
Yu Zhao93a23a72009-05-18 13:51:37 +08001283 return NULL;
1284
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001285 pdev = to_pci_dev(info->dev);
1286
1287 if (!pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ATS))
Yu Zhao93a23a72009-05-18 13:51:37 +08001288 return NULL;
1289
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001290 if (!dmar_find_matched_atsr_unit(pdev))
Yu Zhao93a23a72009-05-18 13:51:37 +08001291 return NULL;
1292
Yu Zhao93a23a72009-05-18 13:51:37 +08001293 return info;
1294}
1295
1296static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1297{
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001298 if (!info || !dev_is_pci(info->dev))
Yu Zhao93a23a72009-05-18 13:51:37 +08001299 return;
1300
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001301 pci_enable_ats(to_pci_dev(info->dev), VTD_PAGE_SHIFT);
Yu Zhao93a23a72009-05-18 13:51:37 +08001302}
1303
1304static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1305{
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001306 if (!info->dev || !dev_is_pci(info->dev) ||
1307 !pci_ats_enabled(to_pci_dev(info->dev)))
Yu Zhao93a23a72009-05-18 13:51:37 +08001308 return;
1309
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001310 pci_disable_ats(to_pci_dev(info->dev));
Yu Zhao93a23a72009-05-18 13:51:37 +08001311}
1312
1313static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1314 u64 addr, unsigned mask)
1315{
1316 u16 sid, qdep;
1317 unsigned long flags;
1318 struct device_domain_info *info;
1319
1320 spin_lock_irqsave(&device_domain_lock, flags);
1321 list_for_each_entry(info, &domain->devices, link) {
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001322 struct pci_dev *pdev;
1323 if (!info->dev || !dev_is_pci(info->dev))
1324 continue;
1325
1326 pdev = to_pci_dev(info->dev);
1327 if (!pci_ats_enabled(pdev))
Yu Zhao93a23a72009-05-18 13:51:37 +08001328 continue;
1329
1330 sid = info->bus << 8 | info->devfn;
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001331 qdep = pci_ats_queue_depth(pdev);
Yu Zhao93a23a72009-05-18 13:51:37 +08001332 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1333 }
1334 spin_unlock_irqrestore(&device_domain_lock, flags);
1335}
1336
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001337static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
David Woodhouseea8ea462014-03-05 17:09:32 +00001338 unsigned long pfn, unsigned int pages, int ih, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001339{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001340 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001341 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001342
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001343 BUG_ON(pages == 0);
1344
David Woodhouseea8ea462014-03-05 17:09:32 +00001345 if (ih)
1346 ih = 1 << 6;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001347 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001348 * Fallback to domain selective flush if no PSI support or the size is
1349 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001350 * PSI requires page size to be 2 ^ x, and the base address is naturally
1351 * aligned to the size
1352 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001353 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1354 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001355 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001356 else
David Woodhouseea8ea462014-03-05 17:09:32 +00001357 iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001358 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001359
1360 /*
Nadav Amit82653632010-04-01 13:24:40 +03001361 * In caching mode, changes of pages from non-present to present require
1362 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001363 */
Nadav Amit82653632010-04-01 13:24:40 +03001364 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001365 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001366}
1367
mark grossf8bab732008-02-08 04:18:38 -08001368static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1369{
1370 u32 pmen;
1371 unsigned long flags;
1372
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001373 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001374 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1375 pmen &= ~DMA_PMEN_EPM;
1376 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1377
1378 /* wait for the protected region status bit to clear */
1379 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1380 readl, !(pmen & DMA_PMEN_PRS), pmen);
1381
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001382 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001383}
1384
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001385static int iommu_enable_translation(struct intel_iommu *iommu)
1386{
1387 u32 sts;
1388 unsigned long flags;
1389
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001390 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001391 iommu->gcmd |= DMA_GCMD_TE;
1392 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001393
1394 /* Make sure hardware complete it */
1395 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001396 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001397
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001398 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001399 return 0;
1400}
1401
1402static int iommu_disable_translation(struct intel_iommu *iommu)
1403{
1404 u32 sts;
1405 unsigned long flag;
1406
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001407 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001408 iommu->gcmd &= ~DMA_GCMD_TE;
1409 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1410
1411 /* Make sure hardware complete it */
1412 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001413 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001414
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001415 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001416 return 0;
1417}
1418
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001419
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001420static int iommu_init_domains(struct intel_iommu *iommu)
1421{
1422 unsigned long ndomains;
1423 unsigned long nlongs;
1424
1425 ndomains = cap_ndoms(iommu->cap);
Jiang Liu852bdb02014-01-06 14:18:11 +08001426 pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
1427 iommu->seq_id, ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001428 nlongs = BITS_TO_LONGS(ndomains);
1429
Donald Dutile94a91b52009-08-20 16:51:34 -04001430 spin_lock_init(&iommu->lock);
1431
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001432 /* TBD: there might be 64K domains,
1433 * consider other allocation for future chip
1434 */
1435 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1436 if (!iommu->domain_ids) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001437 pr_err("IOMMU%d: allocating domain id array failed\n",
1438 iommu->seq_id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001439 return -ENOMEM;
1440 }
1441 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1442 GFP_KERNEL);
1443 if (!iommu->domains) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001444 pr_err("IOMMU%d: allocating domain array failed\n",
1445 iommu->seq_id);
1446 kfree(iommu->domain_ids);
1447 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001448 return -ENOMEM;
1449 }
1450
1451 /*
1452 * if Caching mode is set, then invalid translations are tagged
1453 * with domainid 0. Hence we need to pre-allocate it.
1454 */
1455 if (cap_caching_mode(iommu->cap))
1456 set_bit(0, iommu->domain_ids);
1457 return 0;
1458}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001459
Jiang Liua868e6b2014-01-06 14:18:20 +08001460static void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001461{
1462 struct dmar_domain *domain;
Jiang Liu5ced12a2014-01-06 14:18:22 +08001463 int i, count;
Weidong Hanc7151a82008-12-08 22:51:37 +08001464 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001465
Donald Dutile94a91b52009-08-20 16:51:34 -04001466 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001467 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Jiang Liua4eaa862014-02-19 14:07:30 +08001468 /*
1469 * Domain id 0 is reserved for invalid translation
1470 * if hardware supports caching mode.
1471 */
1472 if (cap_caching_mode(iommu->cap) && i == 0)
1473 continue;
1474
Donald Dutile94a91b52009-08-20 16:51:34 -04001475 domain = iommu->domains[i];
1476 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001477
Donald Dutile94a91b52009-08-20 16:51:34 -04001478 spin_lock_irqsave(&domain->iommu_lock, flags);
Jiang Liu5ced12a2014-01-06 14:18:22 +08001479 count = --domain->iommu_count;
1480 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001481 if (count == 0)
1482 domain_exit(domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001483 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001484 }
1485
1486 if (iommu->gcmd & DMA_GCMD_TE)
1487 iommu_disable_translation(iommu);
1488
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001489 kfree(iommu->domains);
1490 kfree(iommu->domain_ids);
Jiang Liua868e6b2014-01-06 14:18:20 +08001491 iommu->domains = NULL;
1492 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001493
Weidong Hand9630fe2008-12-08 11:06:32 +08001494 g_iommus[iommu->seq_id] = NULL;
1495
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001496 /* free context mapping */
1497 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001498}
1499
Jiang Liu92d03cc2014-02-19 14:07:28 +08001500static struct dmar_domain *alloc_domain(bool vm)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001501{
Jiang Liu92d03cc2014-02-19 14:07:28 +08001502 /* domain id for virtual machine, it won't be set in context */
1503 static atomic_t vm_domid = ATOMIC_INIT(0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001504 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001505
1506 domain = alloc_domain_mem();
1507 if (!domain)
1508 return NULL;
1509
Suresh Siddha4c923d42009-10-02 11:01:24 -07001510 domain->nid = -1;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001511 domain->iommu_count = 0;
Mike Travis1b198bb2012-03-05 15:05:16 -08001512 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001513 domain->flags = 0;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001514 spin_lock_init(&domain->iommu_lock);
1515 INIT_LIST_HEAD(&domain->devices);
1516 if (vm) {
1517 domain->id = atomic_inc_return(&vm_domid);
1518 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
1519 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001520
1521 return domain;
1522}
1523
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001524static int iommu_attach_domain(struct dmar_domain *domain,
1525 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001526{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001527 int num;
1528 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001529 unsigned long flags;
1530
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001531 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001532
1533 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001534
1535 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1536 if (num >= ndomains) {
1537 spin_unlock_irqrestore(&iommu->lock, flags);
1538 printk(KERN_ERR "IOMMU: no free domain ids\n");
1539 return -ENOMEM;
1540 }
1541
1542 domain->id = num;
Jiang Liu9ebd6822014-02-19 14:07:29 +08001543 domain->iommu_count++;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001544 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001545 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001546 iommu->domains[num] = domain;
1547 spin_unlock_irqrestore(&iommu->lock, flags);
1548
1549 return 0;
1550}
1551
1552static void iommu_detach_domain(struct dmar_domain *domain,
1553 struct intel_iommu *iommu)
1554{
1555 unsigned long flags;
1556 int num, ndomains;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001557
1558 spin_lock_irqsave(&iommu->lock, flags);
1559 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001560 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001561 if (iommu->domains[num] == domain) {
Jiang Liu92d03cc2014-02-19 14:07:28 +08001562 clear_bit(num, iommu->domain_ids);
1563 iommu->domains[num] = NULL;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001564 break;
1565 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001566 }
Weidong Han8c11e792008-12-08 15:29:22 +08001567 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001568}
1569
1570static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001571static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001572
Joseph Cihula51a63e62011-03-21 11:04:24 -07001573static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001574{
1575 struct pci_dev *pdev = NULL;
1576 struct iova *iova;
1577 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001578
David Millerf6611972008-02-06 01:36:23 -08001579 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001580
Mark Gross8a443df2008-03-04 14:59:31 -08001581 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1582 &reserved_rbtree_key);
1583
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001584 /* IOAPIC ranges shouldn't be accessed by DMA */
1585 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1586 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001587 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001588 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001589 return -ENODEV;
1590 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001591
1592 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1593 for_each_pci_dev(pdev) {
1594 struct resource *r;
1595
1596 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1597 r = &pdev->resource[i];
1598 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1599 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001600 iova = reserve_iova(&reserved_iova_list,
1601 IOVA_PFN(r->start),
1602 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001603 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001604 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001605 return -ENODEV;
1606 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001607 }
1608 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001609 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001610}
1611
1612static void domain_reserve_special_ranges(struct dmar_domain *domain)
1613{
1614 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1615}
1616
1617static inline int guestwidth_to_adjustwidth(int gaw)
1618{
1619 int agaw;
1620 int r = (gaw - 12) % 9;
1621
1622 if (r == 0)
1623 agaw = gaw;
1624 else
1625 agaw = gaw + 9 - r;
1626 if (agaw > 64)
1627 agaw = 64;
1628 return agaw;
1629}
1630
1631static int domain_init(struct dmar_domain *domain, int guest_width)
1632{
1633 struct intel_iommu *iommu;
1634 int adjust_width, agaw;
1635 unsigned long sagaw;
1636
David Millerf6611972008-02-06 01:36:23 -08001637 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001638 domain_reserve_special_ranges(domain);
1639
1640 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001641 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001642 if (guest_width > cap_mgaw(iommu->cap))
1643 guest_width = cap_mgaw(iommu->cap);
1644 domain->gaw = guest_width;
1645 adjust_width = guestwidth_to_adjustwidth(guest_width);
1646 agaw = width_to_agaw(adjust_width);
1647 sagaw = cap_sagaw(iommu->cap);
1648 if (!test_bit(agaw, &sagaw)) {
1649 /* hardware doesn't support it, choose a bigger one */
1650 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1651 agaw = find_next_bit(&sagaw, 5, agaw);
1652 if (agaw >= 5)
1653 return -ENODEV;
1654 }
1655 domain->agaw = agaw;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001656
Weidong Han8e6040972008-12-08 15:49:06 +08001657 if (ecap_coherent(iommu->ecap))
1658 domain->iommu_coherency = 1;
1659 else
1660 domain->iommu_coherency = 0;
1661
Sheng Yang58c610b2009-03-18 15:33:05 +08001662 if (ecap_sc_support(iommu->ecap))
1663 domain->iommu_snooping = 1;
1664 else
1665 domain->iommu_snooping = 0;
1666
David Woodhouse214e39a2014-03-19 10:38:49 +00001667 if (intel_iommu_superpage)
1668 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
1669 else
1670 domain->iommu_superpage = 0;
1671
Suresh Siddha4c923d42009-10-02 11:01:24 -07001672 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001673
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001674 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001675 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001676 if (!domain->pgd)
1677 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001678 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001679 return 0;
1680}
1681
1682static void domain_exit(struct dmar_domain *domain)
1683{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001684 struct dmar_drhd_unit *drhd;
1685 struct intel_iommu *iommu;
David Woodhouseea8ea462014-03-05 17:09:32 +00001686 struct page *freelist = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001687
1688 /* Domain 0 is reserved, so dont process it */
1689 if (!domain)
1690 return;
1691
Alex Williamson7b668352011-05-24 12:02:41 +01001692 /* Flush any lazy unmaps that may reference this domain */
1693 if (!intel_iommu_strict)
1694 flush_unmaps_timeout(0);
1695
Jiang Liu92d03cc2014-02-19 14:07:28 +08001696 /* remove associated devices */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001697 domain_remove_dev_info(domain);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001698
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001699 /* destroy iovas */
1700 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001701
David Woodhouseea8ea462014-03-05 17:09:32 +00001702 freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001703
Jiang Liu92d03cc2014-02-19 14:07:28 +08001704 /* clear attached or cached domains */
Jiang Liu0e242612014-02-19 14:07:34 +08001705 rcu_read_lock();
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001706 for_each_active_iommu(iommu, drhd)
Jiang Liu92d03cc2014-02-19 14:07:28 +08001707 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1708 test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001709 iommu_detach_domain(domain, iommu);
Jiang Liu0e242612014-02-19 14:07:34 +08001710 rcu_read_unlock();
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001711
David Woodhouseea8ea462014-03-05 17:09:32 +00001712 dma_free_pagelist(freelist);
1713
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001714 free_domain_mem(domain);
1715}
1716
David Woodhouse64ae8922014-03-09 12:52:30 -07001717static int domain_context_mapping_one(struct dmar_domain *domain,
1718 struct intel_iommu *iommu,
1719 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001720{
1721 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001722 unsigned long flags;
Weidong Hanea6606b2008-12-08 23:08:15 +08001723 struct dma_pte *pgd;
1724 unsigned long num;
1725 unsigned long ndomains;
1726 int id;
1727 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001728 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001729
1730 pr_debug("Set context mapping for %02x:%02x.%d\n",
1731 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001732
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001733 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001734 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1735 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001736
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001737 context = device_to_context_entry(iommu, bus, devfn);
1738 if (!context)
1739 return -ENOMEM;
1740 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001741 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001742 spin_unlock_irqrestore(&iommu->lock, flags);
1743 return 0;
1744 }
1745
Weidong Hanea6606b2008-12-08 23:08:15 +08001746 id = domain->id;
1747 pgd = domain->pgd;
1748
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001749 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1750 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001751 int found = 0;
1752
1753 /* find an available domain id for this device in iommu */
1754 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001755 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001756 if (iommu->domains[num] == domain) {
1757 id = num;
1758 found = 1;
1759 break;
1760 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001761 }
1762
1763 if (found == 0) {
1764 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1765 if (num >= ndomains) {
1766 spin_unlock_irqrestore(&iommu->lock, flags);
1767 printk(KERN_ERR "IOMMU: no free domain ids\n");
1768 return -EFAULT;
1769 }
1770
1771 set_bit(num, iommu->domain_ids);
1772 iommu->domains[num] = domain;
1773 id = num;
1774 }
1775
1776 /* Skip top levels of page tables for
1777 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001778 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001779 */
Chris Wright1672af12009-12-02 12:06:34 -08001780 if (translation != CONTEXT_TT_PASS_THROUGH) {
1781 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1782 pgd = phys_to_virt(dma_pte_addr(pgd));
1783 if (!dma_pte_present(pgd)) {
1784 spin_unlock_irqrestore(&iommu->lock, flags);
1785 return -ENOMEM;
1786 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001787 }
1788 }
1789 }
1790
1791 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001792
Yu Zhao93a23a72009-05-18 13:51:37 +08001793 if (translation != CONTEXT_TT_PASS_THROUGH) {
David Woodhouse64ae8922014-03-09 12:52:30 -07001794 info = iommu_support_dev_iotlb(domain, iommu, bus, devfn);
Yu Zhao93a23a72009-05-18 13:51:37 +08001795 translation = info ? CONTEXT_TT_DEV_IOTLB :
1796 CONTEXT_TT_MULTI_LEVEL;
1797 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001798 /*
1799 * In pass through mode, AW must be programmed to indicate the largest
1800 * AGAW value supported by hardware. And ASR is ignored by hardware.
1801 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001802 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001803 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001804 else {
1805 context_set_address_root(context, virt_to_phys(pgd));
1806 context_set_address_width(context, iommu->agaw);
1807 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001808
1809 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001810 context_set_fault_enable(context);
1811 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001812 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001813
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001814 /*
1815 * It's a non-present to present mapping. If hardware doesn't cache
1816 * non-present entry we only need to flush the write-buffer. If the
1817 * _does_ cache non-present entries, then it does so in the special
1818 * domain #0, which we have to flush:
1819 */
1820 if (cap_caching_mode(iommu->cap)) {
1821 iommu->flush.flush_context(iommu, 0,
1822 (((u16)bus) << 8) | devfn,
1823 DMA_CCMD_MASK_NOBIT,
1824 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001825 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001826 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001827 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001828 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001829 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001830 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001831
1832 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001833 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001834 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001835 if (domain->iommu_count == 1)
1836 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001837 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001838 }
1839 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001840 return 0;
1841}
1842
1843static int
David Woodhousee1f167f2014-03-09 15:24:46 -07001844domain_context_mapping(struct dmar_domain *domain, struct device *dev,
1845 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001846{
1847 int ret;
David Woodhousee1f167f2014-03-09 15:24:46 -07001848 struct pci_dev *pdev, *tmp, *parent;
David Woodhouse64ae8922014-03-09 12:52:30 -07001849 struct intel_iommu *iommu;
David Woodhouse156baca2014-03-09 14:00:57 -07001850 u8 bus, devfn;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001851
David Woodhousee1f167f2014-03-09 15:24:46 -07001852 iommu = device_to_iommu(dev, &bus, &devfn);
David Woodhouse64ae8922014-03-09 12:52:30 -07001853 if (!iommu)
1854 return -ENODEV;
1855
David Woodhouse156baca2014-03-09 14:00:57 -07001856 ret = domain_context_mapping_one(domain, iommu, bus, devfn,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001857 translation);
David Woodhousee1f167f2014-03-09 15:24:46 -07001858 if (ret || !dev_is_pci(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001859 return ret;
1860
1861 /* dependent device mapping */
David Woodhousee1f167f2014-03-09 15:24:46 -07001862 pdev = to_pci_dev(dev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001863 tmp = pci_find_upstream_pcie_bridge(pdev);
1864 if (!tmp)
1865 return 0;
1866 /* Secondary interface's bus number and devfn 0 */
1867 parent = pdev->bus->self;
1868 while (parent != tmp) {
David Woodhouse64ae8922014-03-09 12:52:30 -07001869 ret = domain_context_mapping_one(domain, iommu,
David Woodhouse276dbf992009-04-04 01:45:37 +01001870 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001871 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001872 if (ret)
1873 return ret;
1874 parent = parent->bus->self;
1875 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001876 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
David Woodhouse64ae8922014-03-09 12:52:30 -07001877 return domain_context_mapping_one(domain, iommu,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001878 tmp->subordinate->number, 0,
1879 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001880 else /* this is a legacy PCI bridge */
David Woodhouse64ae8922014-03-09 12:52:30 -07001881 return domain_context_mapping_one(domain, iommu,
David Woodhouse276dbf992009-04-04 01:45:37 +01001882 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001883 tmp->devfn,
1884 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001885}
1886
David Woodhousee1f167f2014-03-09 15:24:46 -07001887static int domain_context_mapped(struct device *dev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001888{
1889 int ret;
David Woodhousee1f167f2014-03-09 15:24:46 -07001890 struct pci_dev *pdev, *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001891 struct intel_iommu *iommu;
David Woodhouse156baca2014-03-09 14:00:57 -07001892 u8 bus, devfn;
Weidong Han5331fe62008-12-08 23:00:00 +08001893
David Woodhousee1f167f2014-03-09 15:24:46 -07001894 iommu = device_to_iommu(dev, &bus, &devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001895 if (!iommu)
1896 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001897
David Woodhouse156baca2014-03-09 14:00:57 -07001898 ret = device_context_mapped(iommu, bus, devfn);
David Woodhousee1f167f2014-03-09 15:24:46 -07001899 if (!ret || !dev_is_pci(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001900 return ret;
David Woodhousee1f167f2014-03-09 15:24:46 -07001901
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001902 /* dependent device mapping */
David Woodhousee1f167f2014-03-09 15:24:46 -07001903 pdev = to_pci_dev(dev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001904 tmp = pci_find_upstream_pcie_bridge(pdev);
1905 if (!tmp)
1906 return ret;
1907 /* Secondary interface's bus number and devfn 0 */
1908 parent = pdev->bus->self;
1909 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001910 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001911 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001912 if (!ret)
1913 return ret;
1914 parent = parent->bus->self;
1915 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001916 if (pci_is_pcie(tmp))
David Woodhouse276dbf992009-04-04 01:45:37 +01001917 return device_context_mapped(iommu, tmp->subordinate->number,
1918 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001919 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001920 return device_context_mapped(iommu, tmp->bus->number,
1921 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001922}
1923
Fenghua Yuf5329592009-08-04 15:09:37 -07001924/* Returns a number of VTD pages, but aligned to MM page size */
1925static inline unsigned long aligned_nrpages(unsigned long host_addr,
1926 size_t size)
1927{
1928 host_addr &= ~PAGE_MASK;
1929 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1930}
1931
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001932/* Return largest possible superpage level for a given mapping */
1933static inline int hardware_largepage_caps(struct dmar_domain *domain,
1934 unsigned long iov_pfn,
1935 unsigned long phy_pfn,
1936 unsigned long pages)
1937{
1938 int support, level = 1;
1939 unsigned long pfnmerge;
1940
1941 support = domain->iommu_superpage;
1942
1943 /* To use a large page, the virtual *and* physical addresses
1944 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1945 of them will mean we have to use smaller pages. So just
1946 merge them and check both at once. */
1947 pfnmerge = iov_pfn | phy_pfn;
1948
1949 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1950 pages >>= VTD_STRIDE_SHIFT;
1951 if (!pages)
1952 break;
1953 pfnmerge >>= VTD_STRIDE_SHIFT;
1954 level++;
1955 support--;
1956 }
1957 return level;
1958}
1959
David Woodhouse9051aa02009-06-29 12:30:54 +01001960static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1961 struct scatterlist *sg, unsigned long phys_pfn,
1962 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001963{
1964 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001965 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001966 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001967 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001968 unsigned int largepage_lvl = 0;
1969 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001970
1971 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1972
1973 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1974 return -EINVAL;
1975
1976 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1977
David Woodhouse9051aa02009-06-29 12:30:54 +01001978 if (sg)
1979 sg_res = 0;
1980 else {
1981 sg_res = nr_pages + 1;
1982 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1983 }
1984
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001985 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001986 uint64_t tmp;
1987
David Woodhousee1605492009-06-29 11:17:38 +01001988 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001989 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001990 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1991 sg->dma_length = sg->length;
1992 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001993 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001994 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001995
David Woodhousee1605492009-06-29 11:17:38 +01001996 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001997 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1998
David Woodhouse5cf0a762014-03-19 16:07:49 +00001999 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, &largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01002000 if (!pte)
2001 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002002 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00002003 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002004 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00002005 /* Ensure that old small page tables are removed to make room
2006 for superpage, if they exist. */
2007 dma_pte_clear_range(domain, iov_pfn,
2008 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
2009 dma_pte_free_pagetable(domain, iov_pfn,
2010 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
2011 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002012 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00002013 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002014
David Woodhousee1605492009-06-29 11:17:38 +01002015 }
2016 /* We don't need lock here, nobody else
2017 * touches the iova range
2018 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01002019 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01002020 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01002021 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01002022 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
2023 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01002024 if (dumps) {
2025 dumps--;
2026 debug_dma_dump_mappings(NULL);
2027 }
2028 WARN_ON(1);
2029 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002030
2031 lvl_pages = lvl_to_nr_pages(largepage_lvl);
2032
2033 BUG_ON(nr_pages < lvl_pages);
2034 BUG_ON(sg_res < lvl_pages);
2035
2036 nr_pages -= lvl_pages;
2037 iov_pfn += lvl_pages;
2038 phys_pfn += lvl_pages;
2039 pteval += lvl_pages * VTD_PAGE_SIZE;
2040 sg_res -= lvl_pages;
2041
2042 /* If the next PTE would be the first in a new page, then we
2043 need to flush the cache on the entries we've just written.
2044 And then we'll need to recalculate 'pte', so clear it and
2045 let it get set again in the if (!pte) block above.
2046
2047 If we're done (!nr_pages) we need to flush the cache too.
2048
2049 Also if we've been setting superpages, we may need to
2050 recalculate 'pte' and switch back to smaller pages for the
2051 end of the mapping, if the trailing size is not enough to
2052 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01002053 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002054 if (!nr_pages || first_pte_in_page(pte) ||
2055 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01002056 domain_flush_cache(domain, first_pte,
2057 (void *)pte - (void *)first_pte);
2058 pte = NULL;
2059 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002060
2061 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01002062 sg = sg_next(sg);
2063 }
2064 return 0;
2065}
2066
David Woodhouse9051aa02009-06-29 12:30:54 +01002067static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
2068 struct scatterlist *sg, unsigned long nr_pages,
2069 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002070{
David Woodhouse9051aa02009-06-29 12:30:54 +01002071 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
2072}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002073
David Woodhouse9051aa02009-06-29 12:30:54 +01002074static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
2075 unsigned long phys_pfn, unsigned long nr_pages,
2076 int prot)
2077{
2078 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002079}
2080
Weidong Hanc7151a82008-12-08 22:51:37 +08002081static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002082{
Weidong Hanc7151a82008-12-08 22:51:37 +08002083 if (!iommu)
2084 return;
Weidong Han8c11e792008-12-08 15:29:22 +08002085
2086 clear_context_table(iommu, bus, devfn);
2087 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002088 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002089 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002090}
2091
David Woodhouse109b9b02012-05-25 17:43:02 +01002092static inline void unlink_domain_info(struct device_domain_info *info)
2093{
2094 assert_spin_locked(&device_domain_lock);
2095 list_del(&info->link);
2096 list_del(&info->global);
2097 if (info->dev)
David Woodhouse0bcb3e22014-03-06 17:12:03 +00002098 info->dev->archdata.iommu = NULL;
David Woodhouse109b9b02012-05-25 17:43:02 +01002099}
2100
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002101static void domain_remove_dev_info(struct dmar_domain *domain)
2102{
Yijing Wang3a74ca02014-05-20 20:37:47 +08002103 struct device_domain_info *info, *tmp;
Jiang Liu92d03cc2014-02-19 14:07:28 +08002104 unsigned long flags, flags2;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002105
2106 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wang3a74ca02014-05-20 20:37:47 +08002107 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
David Woodhouse109b9b02012-05-25 17:43:02 +01002108 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002109 spin_unlock_irqrestore(&device_domain_lock, flags);
2110
Yu Zhao93a23a72009-05-18 13:51:37 +08002111 iommu_disable_dev_iotlb(info);
David Woodhouse7c7faa12014-03-09 13:33:06 -07002112 iommu_detach_dev(info->iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002113
Jiang Liu92d03cc2014-02-19 14:07:28 +08002114 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
David Woodhouse7c7faa12014-03-09 13:33:06 -07002115 iommu_detach_dependent_devices(info->iommu, info->dev);
Jiang Liu92d03cc2014-02-19 14:07:28 +08002116 /* clear this iommu in iommu_bmp, update iommu count
2117 * and capabilities
2118 */
2119 spin_lock_irqsave(&domain->iommu_lock, flags2);
David Woodhouse7c7faa12014-03-09 13:33:06 -07002120 if (test_and_clear_bit(info->iommu->seq_id,
Jiang Liu92d03cc2014-02-19 14:07:28 +08002121 domain->iommu_bmp)) {
2122 domain->iommu_count--;
2123 domain_update_iommu_cap(domain);
2124 }
2125 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
2126 }
2127
2128 free_devinfo_mem(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002129 spin_lock_irqsave(&device_domain_lock, flags);
2130 }
2131 spin_unlock_irqrestore(&device_domain_lock, flags);
2132}
2133
2134/*
2135 * find_domain
David Woodhouse1525a292014-03-06 16:19:30 +00002136 * Note: we use struct device->archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002137 */
David Woodhouse1525a292014-03-06 16:19:30 +00002138static struct dmar_domain *find_domain(struct device *dev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002139{
2140 struct device_domain_info *info;
2141
2142 /* No lock here, assumes no domain exit in normal case */
David Woodhouse1525a292014-03-06 16:19:30 +00002143 info = dev->archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002144 if (info)
2145 return info->domain;
2146 return NULL;
2147}
2148
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002149static inline struct device_domain_info *
Jiang Liu745f2582014-02-19 14:07:26 +08002150dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
2151{
2152 struct device_domain_info *info;
2153
2154 list_for_each_entry(info, &device_domain_list, global)
David Woodhouse41e80dca2014-03-09 13:55:54 -07002155 if (info->iommu->segment == segment && info->bus == bus &&
Jiang Liu745f2582014-02-19 14:07:26 +08002156 info->devfn == devfn)
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002157 return info;
Jiang Liu745f2582014-02-19 14:07:26 +08002158
2159 return NULL;
2160}
2161
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002162static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu,
David Woodhouse41e80dca2014-03-09 13:55:54 -07002163 int bus, int devfn,
David Woodhouseb718cd32014-03-09 13:11:33 -07002164 struct device *dev,
2165 struct dmar_domain *domain)
Jiang Liu745f2582014-02-19 14:07:26 +08002166{
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002167 struct dmar_domain *found = NULL;
Jiang Liu745f2582014-02-19 14:07:26 +08002168 struct device_domain_info *info;
2169 unsigned long flags;
2170
2171 info = alloc_devinfo_mem();
2172 if (!info)
David Woodhouseb718cd32014-03-09 13:11:33 -07002173 return NULL;
Jiang Liu745f2582014-02-19 14:07:26 +08002174
Jiang Liu745f2582014-02-19 14:07:26 +08002175 info->bus = bus;
2176 info->devfn = devfn;
2177 info->dev = dev;
2178 info->domain = domain;
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002179 info->iommu = iommu;
Jiang Liu745f2582014-02-19 14:07:26 +08002180 if (!dev)
2181 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
2182
2183 spin_lock_irqsave(&device_domain_lock, flags);
2184 if (dev)
David Woodhouse0bcb3e22014-03-06 17:12:03 +00002185 found = find_domain(dev);
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002186 else {
2187 struct device_domain_info *info2;
David Woodhouse41e80dca2014-03-09 13:55:54 -07002188 info2 = dmar_search_domain_by_dev_info(iommu->segment, bus, devfn);
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002189 if (info2)
2190 found = info2->domain;
2191 }
Jiang Liu745f2582014-02-19 14:07:26 +08002192 if (found) {
2193 spin_unlock_irqrestore(&device_domain_lock, flags);
2194 free_devinfo_mem(info);
David Woodhouseb718cd32014-03-09 13:11:33 -07002195 /* Caller must free the original domain */
2196 return found;
Jiang Liu745f2582014-02-19 14:07:26 +08002197 }
2198
David Woodhouseb718cd32014-03-09 13:11:33 -07002199 list_add(&info->link, &domain->devices);
2200 list_add(&info->global, &device_domain_list);
2201 if (dev)
2202 dev->archdata.iommu = info;
2203 spin_unlock_irqrestore(&device_domain_lock, flags);
2204
2205 return domain;
Jiang Liu745f2582014-02-19 14:07:26 +08002206}
2207
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002208/* domain is initialized */
David Woodhouse146922e2014-03-09 15:44:17 -07002209static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002210{
Jiang Liue85bb5d2014-02-19 14:07:27 +08002211 struct dmar_domain *domain, *free = NULL;
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002212 struct intel_iommu *iommu = NULL;
2213 struct device_domain_info *info;
David Woodhouse146922e2014-03-09 15:44:17 -07002214 struct pci_dev *dev_tmp = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002215 unsigned long flags;
David Woodhouse146922e2014-03-09 15:44:17 -07002216 u8 bus, devfn, bridge_bus, bridge_devfn;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002217
David Woodhouse146922e2014-03-09 15:44:17 -07002218 domain = find_domain(dev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002219 if (domain)
2220 return domain;
2221
David Woodhouse146922e2014-03-09 15:44:17 -07002222 if (dev_is_pci(dev)) {
2223 struct pci_dev *pdev = to_pci_dev(dev);
2224 u16 segment;
David Woodhouse276dbf992009-04-04 01:45:37 +01002225
David Woodhouse146922e2014-03-09 15:44:17 -07002226 segment = pci_domain_nr(pdev->bus);
2227 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
2228 if (dev_tmp) {
2229 if (pci_is_pcie(dev_tmp)) {
2230 bridge_bus = dev_tmp->subordinate->number;
2231 bridge_devfn = 0;
2232 } else {
2233 bridge_bus = dev_tmp->bus->number;
2234 bridge_devfn = dev_tmp->devfn;
2235 }
2236 spin_lock_irqsave(&device_domain_lock, flags);
David Woodhouse9f05d3f2014-04-14 22:01:30 -07002237 info = dmar_search_domain_by_dev_info(segment,
2238 bridge_bus,
2239 bridge_devfn);
David Woodhouse146922e2014-03-09 15:44:17 -07002240 if (info) {
2241 iommu = info->iommu;
2242 domain = info->domain;
2243 }
2244 spin_unlock_irqrestore(&device_domain_lock, flags);
2245 /* pcie-pci bridge already has a domain, uses it */
2246 if (info)
2247 goto found_domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002248 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002249 }
2250
David Woodhouse146922e2014-03-09 15:44:17 -07002251 iommu = device_to_iommu(dev, &bus, &devfn);
2252 if (!iommu)
2253 goto error;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002254
David Woodhouse146922e2014-03-09 15:44:17 -07002255 /* Allocate and initialize new domain for the device */
Jiang Liu92d03cc2014-02-19 14:07:28 +08002256 domain = alloc_domain(false);
Jiang Liu745f2582014-02-19 14:07:26 +08002257 if (!domain)
2258 goto error;
2259 if (iommu_attach_domain(domain, iommu)) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002260 free_domain_mem(domain);
Dan Carpenter14d40562014-03-28 11:29:50 +03002261 domain = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002262 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002263 }
Jiang Liue85bb5d2014-02-19 14:07:27 +08002264 free = domain;
2265 if (domain_init(domain, gaw))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002266 goto error;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002267
2268 /* register pcie-to-pci device */
2269 if (dev_tmp) {
David Woodhouse146922e2014-03-09 15:44:17 -07002270 domain = dmar_insert_dev_info(iommu, bridge_bus, bridge_devfn,
2271 NULL, domain);
David Woodhouseb718cd32014-03-09 13:11:33 -07002272 if (!domain)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002273 goto error;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002274 }
2275
2276found_domain:
David Woodhouse146922e2014-03-09 15:44:17 -07002277 domain = dmar_insert_dev_info(iommu, bus, devfn, dev, domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002278error:
David Woodhouseb718cd32014-03-09 13:11:33 -07002279 if (free != domain)
Jiang Liue85bb5d2014-02-19 14:07:27 +08002280 domain_exit(free);
David Woodhouseb718cd32014-03-09 13:11:33 -07002281
2282 return domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002283}
2284
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002285static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002286#define IDENTMAP_ALL 1
2287#define IDENTMAP_GFX 2
2288#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002289
David Woodhouseb2132032009-06-26 18:50:28 +01002290static int iommu_domain_identity_map(struct dmar_domain *domain,
2291 unsigned long long start,
2292 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002293{
David Woodhousec5395d52009-06-28 16:35:56 +01002294 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2295 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002296
David Woodhousec5395d52009-06-28 16:35:56 +01002297 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2298 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002299 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002300 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002301 }
2302
David Woodhousec5395d52009-06-28 16:35:56 +01002303 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2304 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002305 /*
2306 * RMRR range might have overlap with physical memory range,
2307 * clear it first
2308 */
David Woodhousec5395d52009-06-28 16:35:56 +01002309 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002310
David Woodhousec5395d52009-06-28 16:35:56 +01002311 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2312 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002313 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002314}
2315
David Woodhouse0b9d9752014-03-09 15:48:15 -07002316static int iommu_prepare_identity_map(struct device *dev,
David Woodhouseb2132032009-06-26 18:50:28 +01002317 unsigned long long start,
2318 unsigned long long end)
2319{
2320 struct dmar_domain *domain;
2321 int ret;
2322
David Woodhouse0b9d9752014-03-09 15:48:15 -07002323 domain = get_domain_for_dev(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002324 if (!domain)
2325 return -ENOMEM;
2326
David Woodhouse19943b02009-08-04 16:19:20 +01002327 /* For _hardware_ passthrough, don't bother. But for software
2328 passthrough, we do it anyway -- it may indicate a memory
2329 range which is reserved in E820, so which didn't get set
2330 up to start with in si_domain */
2331 if (domain == si_domain && hw_pass_through) {
2332 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
David Woodhouse0b9d9752014-03-09 15:48:15 -07002333 dev_name(dev), start, end);
David Woodhouse19943b02009-08-04 16:19:20 +01002334 return 0;
2335 }
2336
2337 printk(KERN_INFO
2338 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
David Woodhouse0b9d9752014-03-09 15:48:15 -07002339 dev_name(dev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002340
David Woodhouse5595b522009-12-02 09:21:55 +00002341 if (end < start) {
2342 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2343 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2344 dmi_get_system_info(DMI_BIOS_VENDOR),
2345 dmi_get_system_info(DMI_BIOS_VERSION),
2346 dmi_get_system_info(DMI_PRODUCT_VERSION));
2347 ret = -EIO;
2348 goto error;
2349 }
2350
David Woodhouse2ff729f2009-08-26 14:25:41 +01002351 if (end >> agaw_to_width(domain->agaw)) {
2352 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2353 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2354 agaw_to_width(domain->agaw),
2355 dmi_get_system_info(DMI_BIOS_VENDOR),
2356 dmi_get_system_info(DMI_BIOS_VERSION),
2357 dmi_get_system_info(DMI_PRODUCT_VERSION));
2358 ret = -EIO;
2359 goto error;
2360 }
David Woodhouse19943b02009-08-04 16:19:20 +01002361
David Woodhouseb2132032009-06-26 18:50:28 +01002362 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002363 if (ret)
2364 goto error;
2365
2366 /* context entry init */
David Woodhouse0b9d9752014-03-09 15:48:15 -07002367 ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002368 if (ret)
2369 goto error;
2370
2371 return 0;
2372
2373 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002374 domain_exit(domain);
2375 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002376}
2377
2378static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
David Woodhouse0b9d9752014-03-09 15:48:15 -07002379 struct device *dev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002380{
David Woodhouse0b9d9752014-03-09 15:48:15 -07002381 if (dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002382 return 0;
David Woodhouse0b9d9752014-03-09 15:48:15 -07002383 return iommu_prepare_identity_map(dev, rmrr->base_address,
2384 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002385}
2386
Suresh Siddhad3f13812011-08-23 17:05:25 -07002387#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002388static inline void iommu_prepare_isa(void)
2389{
2390 struct pci_dev *pdev;
2391 int ret;
2392
2393 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2394 if (!pdev)
2395 return;
2396
David Woodhousec7ab48d2009-06-26 19:10:36 +01002397 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse0b9d9752014-03-09 15:48:15 -07002398 ret = iommu_prepare_identity_map(&pdev->dev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002399
2400 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002401 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2402 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002403
Yijing Wang9b27e822014-05-20 20:37:52 +08002404 pci_dev_put(pdev);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002405}
2406#else
2407static inline void iommu_prepare_isa(void)
2408{
2409 return;
2410}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002411#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002412
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002413static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002414
Matt Kraai071e1372009-08-23 22:30:22 -07002415static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002416{
2417 struct dmar_drhd_unit *drhd;
2418 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002419 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002420
Jiang Liu92d03cc2014-02-19 14:07:28 +08002421 si_domain = alloc_domain(false);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002422 if (!si_domain)
2423 return -EFAULT;
2424
Jiang Liu92d03cc2014-02-19 14:07:28 +08002425 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2426
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002427 for_each_active_iommu(iommu, drhd) {
2428 ret = iommu_attach_domain(si_domain, iommu);
2429 if (ret) {
2430 domain_exit(si_domain);
2431 return -EFAULT;
2432 }
2433 }
2434
2435 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2436 domain_exit(si_domain);
2437 return -EFAULT;
2438 }
2439
Jiang Liu9544c002014-01-06 14:18:13 +08002440 pr_debug("IOMMU: identity mapping domain is domain %d\n",
2441 si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002442
David Woodhouse19943b02009-08-04 16:19:20 +01002443 if (hw)
2444 return 0;
2445
David Woodhousec7ab48d2009-06-26 19:10:36 +01002446 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002447 unsigned long start_pfn, end_pfn;
2448 int i;
2449
2450 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2451 ret = iommu_domain_identity_map(si_domain,
2452 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2453 if (ret)
2454 return ret;
2455 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002456 }
2457
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002458 return 0;
2459}
2460
David Woodhouse9b226622014-03-09 14:03:28 -07002461static int identity_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002462{
2463 struct device_domain_info *info;
2464
2465 if (likely(!iommu_identity_mapping))
2466 return 0;
2467
David Woodhouse9b226622014-03-09 14:03:28 -07002468 info = dev->archdata.iommu;
Mike Traviscb452a42011-05-28 13:15:03 -05002469 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2470 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002471
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002472 return 0;
2473}
2474
2475static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5913c9b2014-03-09 16:27:31 -07002476 struct device *dev, int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002477{
David Woodhouse0ac72662014-03-09 13:19:22 -07002478 struct dmar_domain *ndomain;
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002479 struct intel_iommu *iommu;
David Woodhouse156baca2014-03-09 14:00:57 -07002480 u8 bus, devfn;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002481 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002482
David Woodhouse5913c9b2014-03-09 16:27:31 -07002483 iommu = device_to_iommu(dev, &bus, &devfn);
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002484 if (!iommu)
2485 return -ENODEV;
2486
David Woodhouse5913c9b2014-03-09 16:27:31 -07002487 ndomain = dmar_insert_dev_info(iommu, bus, devfn, dev, domain);
David Woodhouse0ac72662014-03-09 13:19:22 -07002488 if (ndomain != domain)
2489 return -EBUSY;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002490
David Woodhouse5913c9b2014-03-09 16:27:31 -07002491 ret = domain_context_mapping(domain, dev, translation);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002492 if (ret) {
David Woodhouse5913c9b2014-03-09 16:27:31 -07002493 domain_remove_one_dev_info(domain, dev);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002494 return ret;
2495 }
2496
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002497 return 0;
2498}
2499
David Woodhouse0b9d9752014-03-09 15:48:15 -07002500static bool device_has_rmrr(struct device *dev)
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002501{
2502 struct dmar_rmrr_unit *rmrr;
David Woodhouse832bd852014-03-07 15:08:36 +00002503 struct device *tmp;
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002504 int i;
2505
Jiang Liu0e242612014-02-19 14:07:34 +08002506 rcu_read_lock();
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002507 for_each_rmrr_units(rmrr) {
Jiang Liub683b232014-02-19 14:07:32 +08002508 /*
2509 * Return TRUE if this RMRR contains the device that
2510 * is passed in.
2511 */
2512 for_each_active_dev_scope(rmrr->devices,
2513 rmrr->devices_cnt, i, tmp)
David Woodhouse0b9d9752014-03-09 15:48:15 -07002514 if (tmp == dev) {
Jiang Liu0e242612014-02-19 14:07:34 +08002515 rcu_read_unlock();
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002516 return true;
Jiang Liub683b232014-02-19 14:07:32 +08002517 }
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002518 }
Jiang Liu0e242612014-02-19 14:07:34 +08002519 rcu_read_unlock();
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002520 return false;
2521}
2522
David Woodhouse3bdb2592014-03-09 16:03:08 -07002523static int iommu_should_identity_map(struct device *dev, int startup)
David Woodhouse6941af22009-07-04 18:24:27 +01002524{
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002525
David Woodhouse3bdb2592014-03-09 16:03:08 -07002526 if (dev_is_pci(dev)) {
2527 struct pci_dev *pdev = to_pci_dev(dev);
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002528
David Woodhouse3bdb2592014-03-09 16:03:08 -07002529 /*
2530 * We want to prevent any device associated with an RMRR from
2531 * getting placed into the SI Domain. This is done because
2532 * problems exist when devices are moved in and out of domains
2533 * and their respective RMRR info is lost. We exempt USB devices
2534 * from this process due to their usage of RMRRs that are known
2535 * to not be needed after BIOS hand-off to OS.
2536 */
2537 if (device_has_rmrr(dev) &&
2538 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2539 return 0;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002540
David Woodhouse3bdb2592014-03-09 16:03:08 -07002541 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2542 return 1;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002543
David Woodhouse3bdb2592014-03-09 16:03:08 -07002544 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2545 return 1;
2546
2547 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2548 return 0;
2549
2550 /*
2551 * We want to start off with all devices in the 1:1 domain, and
2552 * take them out later if we find they can't access all of memory.
2553 *
2554 * However, we can't do this for PCI devices behind bridges,
2555 * because all PCI devices behind the same bridge will end up
2556 * with the same source-id on their transactions.
2557 *
2558 * Practically speaking, we can't change things around for these
2559 * devices at run-time, because we can't be sure there'll be no
2560 * DMA transactions in flight for any of their siblings.
2561 *
2562 * So PCI devices (unless they're on the root bus) as well as
2563 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2564 * the 1:1 domain, just in _case_ one of their siblings turns out
2565 * not to be able to map all of memory.
2566 */
2567 if (!pci_is_pcie(pdev)) {
2568 if (!pci_is_root_bus(pdev->bus))
2569 return 0;
2570 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2571 return 0;
2572 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
2573 return 0;
2574 } else {
2575 if (device_has_rmrr(dev))
2576 return 0;
2577 }
David Woodhouse6941af22009-07-04 18:24:27 +01002578
David Woodhouse3dfc8132009-07-04 19:11:08 +01002579 /*
David Woodhouse3dfc8132009-07-04 19:11:08 +01002580 * At boot time, we don't yet know if devices will be 64-bit capable.
David Woodhouse3bdb2592014-03-09 16:03:08 -07002581 * Assume that they will — if they turn out not to be, then we can
David Woodhouse3dfc8132009-07-04 19:11:08 +01002582 * take them out of the 1:1 domain later.
2583 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002584 if (!startup) {
2585 /*
2586 * If the device's dma_mask is less than the system's memory
2587 * size then this is not a candidate for identity mapping.
2588 */
David Woodhouse3bdb2592014-03-09 16:03:08 -07002589 u64 dma_mask = *dev->dma_mask;
Chris Wright8fcc5372011-05-28 13:15:02 -05002590
David Woodhouse3bdb2592014-03-09 16:03:08 -07002591 if (dev->coherent_dma_mask &&
2592 dev->coherent_dma_mask < dma_mask)
2593 dma_mask = dev->coherent_dma_mask;
Chris Wright8fcc5372011-05-28 13:15:02 -05002594
David Woodhouse3bdb2592014-03-09 16:03:08 -07002595 return dma_mask >= dma_get_required_mask(dev);
Chris Wright8fcc5372011-05-28 13:15:02 -05002596 }
David Woodhouse6941af22009-07-04 18:24:27 +01002597
2598 return 1;
2599}
2600
David Woodhousecf04eee2014-03-21 16:49:04 +00002601static int __init dev_prepare_static_identity_mapping(struct device *dev, int hw)
2602{
2603 int ret;
2604
2605 if (!iommu_should_identity_map(dev, 1))
2606 return 0;
2607
2608 ret = domain_add_dev_info(si_domain, dev,
2609 hw ? CONTEXT_TT_PASS_THROUGH :
2610 CONTEXT_TT_MULTI_LEVEL);
2611 if (!ret)
2612 pr_info("IOMMU: %s identity mapping for device %s\n",
2613 hw ? "hardware" : "software", dev_name(dev));
2614 else if (ret == -ENODEV)
2615 /* device not associated with an iommu */
2616 ret = 0;
2617
2618 return ret;
2619}
2620
2621
Matt Kraai071e1372009-08-23 22:30:22 -07002622static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002623{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002624 struct pci_dev *pdev = NULL;
David Woodhousecf04eee2014-03-21 16:49:04 +00002625 struct dmar_drhd_unit *drhd;
2626 struct intel_iommu *iommu;
2627 struct device *dev;
2628 int i;
2629 int ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002630
David Woodhouse19943b02009-08-04 16:19:20 +01002631 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002632 if (ret)
2633 return -EFAULT;
2634
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002635 for_each_pci_dev(pdev) {
David Woodhousecf04eee2014-03-21 16:49:04 +00002636 ret = dev_prepare_static_identity_mapping(&pdev->dev, hw);
2637 if (ret)
2638 return ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002639 }
2640
David Woodhousecf04eee2014-03-21 16:49:04 +00002641 for_each_active_iommu(iommu, drhd)
2642 for_each_active_dev_scope(drhd->devices, drhd->devices_cnt, i, dev) {
2643 struct acpi_device_physical_node *pn;
2644 struct acpi_device *adev;
2645
2646 if (dev->bus != &acpi_bus_type)
2647 continue;
2648
2649 adev= to_acpi_device(dev);
2650 mutex_lock(&adev->physical_node_lock);
2651 list_for_each_entry(pn, &adev->physical_node_list, node) {
2652 ret = dev_prepare_static_identity_mapping(pn->dev, hw);
2653 if (ret)
2654 break;
2655 }
2656 mutex_unlock(&adev->physical_node_lock);
2657 if (ret)
2658 return ret;
2659 }
2660
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002661 return 0;
2662}
2663
Joseph Cihulab7792602011-05-03 00:08:37 -07002664static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002665{
2666 struct dmar_drhd_unit *drhd;
2667 struct dmar_rmrr_unit *rmrr;
David Woodhouse832bd852014-03-07 15:08:36 +00002668 struct device *dev;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002669 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002670 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002671
2672 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002673 * for each drhd
2674 * allocate root
2675 * initialize and program root entry to not present
2676 * endfor
2677 */
2678 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002679 /*
2680 * lock not needed as this is only incremented in the single
2681 * threaded kernel __init code path all other access are read
2682 * only
2683 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002684 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2685 g_num_of_iommus++;
2686 continue;
2687 }
2688 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2689 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002690 }
2691
Weidong Hand9630fe2008-12-08 11:06:32 +08002692 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2693 GFP_KERNEL);
2694 if (!g_iommus) {
2695 printk(KERN_ERR "Allocating global iommu array failed\n");
2696 ret = -ENOMEM;
2697 goto error;
2698 }
2699
mark gross80b20dd2008-04-18 13:53:58 -07002700 deferred_flush = kzalloc(g_num_of_iommus *
2701 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2702 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002703 ret = -ENOMEM;
Jiang Liu989d51f2014-02-19 14:07:21 +08002704 goto free_g_iommus;
mark gross5e0d2a62008-03-04 15:22:08 -08002705 }
2706
Jiang Liu7c919772014-01-06 14:18:18 +08002707 for_each_active_iommu(iommu, drhd) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002708 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002709
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002710 ret = iommu_init_domains(iommu);
2711 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002712 goto free_iommu;
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002713
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002714 /*
2715 * TBD:
2716 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002717 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002718 */
2719 ret = iommu_alloc_root_entry(iommu);
2720 if (ret) {
2721 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002722 goto free_iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002723 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002724 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002725 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002726 }
2727
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002728 /*
2729 * Start from the sane iommu hardware state.
2730 */
Jiang Liu7c919772014-01-06 14:18:18 +08002731 for_each_active_iommu(iommu, drhd) {
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002732 /*
2733 * If the queued invalidation is already initialized by us
2734 * (for example, while enabling interrupt-remapping) then
2735 * we got the things already rolling from a sane state.
2736 */
2737 if (iommu->qi)
2738 continue;
2739
2740 /*
2741 * Clear any previous faults.
2742 */
2743 dmar_fault(-1, iommu);
2744 /*
2745 * Disable queued invalidation if supported and already enabled
2746 * before OS handover.
2747 */
2748 dmar_disable_qi(iommu);
2749 }
2750
Jiang Liu7c919772014-01-06 14:18:18 +08002751 for_each_active_iommu(iommu, drhd) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002752 if (dmar_enable_qi(iommu)) {
2753 /*
2754 * Queued Invalidate not enabled, use Register Based
2755 * Invalidate
2756 */
2757 iommu->flush.flush_context = __iommu_flush_context;
2758 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002759 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002760 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002761 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002762 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002763 } else {
2764 iommu->flush.flush_context = qi_flush_context;
2765 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002766 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002767 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002768 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002769 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002770 }
2771 }
2772
David Woodhouse19943b02009-08-04 16:19:20 +01002773 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002774 iommu_identity_mapping |= IDENTMAP_ALL;
2775
Suresh Siddhad3f13812011-08-23 17:05:25 -07002776#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002777 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002778#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002779
2780 check_tylersburg_isoch();
2781
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002782 /*
2783 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002784 * identity mappings for rmrr, gfx, and isa and may fall back to static
2785 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002786 */
David Woodhouse19943b02009-08-04 16:19:20 +01002787 if (iommu_identity_mapping) {
2788 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2789 if (ret) {
2790 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002791 goto free_iommu;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002792 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002793 }
David Woodhouse19943b02009-08-04 16:19:20 +01002794 /*
2795 * For each rmrr
2796 * for each dev attached to rmrr
2797 * do
2798 * locate drhd for dev, alloc domain for dev
2799 * allocate free domain
2800 * allocate page table entries for rmrr
2801 * if context not allocated for bus
2802 * allocate and init context
2803 * set present in root table for this bus
2804 * init context with domain, translation etc
2805 * endfor
2806 * endfor
2807 */
2808 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2809 for_each_rmrr_units(rmrr) {
Jiang Liub683b232014-02-19 14:07:32 +08002810 /* some BIOS lists non-exist devices in DMAR table. */
2811 for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
David Woodhouse832bd852014-03-07 15:08:36 +00002812 i, dev) {
David Woodhouse0b9d9752014-03-09 15:48:15 -07002813 ret = iommu_prepare_rmrr_dev(rmrr, dev);
David Woodhouse19943b02009-08-04 16:19:20 +01002814 if (ret)
2815 printk(KERN_ERR
2816 "IOMMU: mapping reserved region failed\n");
2817 }
2818 }
2819
2820 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002821
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002822 /*
2823 * for each drhd
2824 * enable fault log
2825 * global invalidate context cache
2826 * global invalidate iotlb
2827 * enable translation
2828 */
Jiang Liu7c919772014-01-06 14:18:18 +08002829 for_each_iommu(iommu, drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002830 if (drhd->ignored) {
2831 /*
2832 * we always have to disable PMRs or DMA may fail on
2833 * this device
2834 */
2835 if (force_on)
Jiang Liu7c919772014-01-06 14:18:18 +08002836 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002837 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002838 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002839
2840 iommu_flush_write_buffer(iommu);
2841
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002842 ret = dmar_set_interrupt(iommu);
2843 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002844 goto free_iommu;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002845
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002846 iommu_set_root_entry(iommu);
2847
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002848 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002849 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002850
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002851 ret = iommu_enable_translation(iommu);
2852 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002853 goto free_iommu;
David Woodhouseb94996c2009-09-19 15:28:12 -07002854
2855 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002856 }
2857
2858 return 0;
Jiang Liu989d51f2014-02-19 14:07:21 +08002859
2860free_iommu:
Jiang Liu7c919772014-01-06 14:18:18 +08002861 for_each_active_iommu(iommu, drhd)
Jiang Liua868e6b2014-01-06 14:18:20 +08002862 free_dmar_iommu(iommu);
Jiang Liu9bdc5312014-01-06 14:18:27 +08002863 kfree(deferred_flush);
Jiang Liu989d51f2014-02-19 14:07:21 +08002864free_g_iommus:
Weidong Hand9630fe2008-12-08 11:06:32 +08002865 kfree(g_iommus);
Jiang Liu989d51f2014-02-19 14:07:21 +08002866error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002867 return ret;
2868}
2869
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002870/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002871static struct iova *intel_alloc_iova(struct device *dev,
2872 struct dmar_domain *domain,
2873 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002874{
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002875 struct iova *iova = NULL;
2876
David Woodhouse875764d2009-06-28 21:20:51 +01002877 /* Restrict dma_mask to the width that the iommu can handle */
2878 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2879
2880 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002881 /*
2882 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002883 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002884 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002885 */
David Woodhouse875764d2009-06-28 21:20:51 +01002886 iova = alloc_iova(&domain->iovad, nrpages,
2887 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2888 if (iova)
2889 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002890 }
David Woodhouse875764d2009-06-28 21:20:51 +01002891 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2892 if (unlikely(!iova)) {
2893 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
David Woodhouse207e3592014-03-09 16:12:32 -07002894 nrpages, dev_name(dev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002895 return NULL;
2896 }
2897
2898 return iova;
2899}
2900
David Woodhoused4b709f2014-03-09 16:07:40 -07002901static struct dmar_domain *__get_valid_domain_for_dev(struct device *dev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002902{
2903 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002904 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002905
David Woodhoused4b709f2014-03-09 16:07:40 -07002906 domain = get_domain_for_dev(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002907 if (!domain) {
David Woodhoused4b709f2014-03-09 16:07:40 -07002908 printk(KERN_ERR "Allocating domain for %s failed",
2909 dev_name(dev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002910 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002911 }
2912
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002913 /* make sure context mapping is ok */
David Woodhoused4b709f2014-03-09 16:07:40 -07002914 if (unlikely(!domain_context_mapped(dev))) {
2915 ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002916 if (ret) {
David Woodhoused4b709f2014-03-09 16:07:40 -07002917 printk(KERN_ERR "Domain context map for %s failed",
2918 dev_name(dev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002919 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002920 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002921 }
2922
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002923 return domain;
2924}
2925
David Woodhoused4b709f2014-03-09 16:07:40 -07002926static inline struct dmar_domain *get_valid_domain_for_dev(struct device *dev)
David Woodhouse147202a2009-07-07 19:43:20 +01002927{
2928 struct device_domain_info *info;
2929
2930 /* No lock here, assumes no domain exit in normal case */
David Woodhoused4b709f2014-03-09 16:07:40 -07002931 info = dev->archdata.iommu;
David Woodhouse147202a2009-07-07 19:43:20 +01002932 if (likely(info))
2933 return info->domain;
2934
2935 return __get_valid_domain_for_dev(dev);
2936}
2937
David Woodhouse3d891942014-03-06 15:59:26 +00002938static int iommu_dummy(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002939{
David Woodhouse3d891942014-03-06 15:59:26 +00002940 return dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002941}
2942
David Woodhouseecb509e2014-03-09 16:29:55 -07002943/* Check if the dev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002944static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002945{
2946 int found;
2947
David Woodhouse3d891942014-03-06 15:59:26 +00002948 if (iommu_dummy(dev))
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002949 return 1;
2950
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002951 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002952 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002953
David Woodhouse9b226622014-03-09 14:03:28 -07002954 found = identity_mapping(dev);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002955 if (found) {
David Woodhouseecb509e2014-03-09 16:29:55 -07002956 if (iommu_should_identity_map(dev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002957 return 1;
2958 else {
2959 /*
2960 * 32 bit DMA is removed from si_domain and fall back
2961 * to non-identity mapping.
2962 */
David Woodhousebf9c9ed2014-03-09 16:19:13 -07002963 domain_remove_one_dev_info(si_domain, dev);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002964 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
David Woodhouseecb509e2014-03-09 16:29:55 -07002965 dev_name(dev));
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002966 return 0;
2967 }
2968 } else {
2969 /*
2970 * In case of a detached 64 bit DMA device from vm, the device
2971 * is put into si_domain for identity mapping.
2972 */
David Woodhouseecb509e2014-03-09 16:29:55 -07002973 if (iommu_should_identity_map(dev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002974 int ret;
David Woodhouse5913c9b2014-03-09 16:27:31 -07002975 ret = domain_add_dev_info(si_domain, dev,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002976 hw_pass_through ?
2977 CONTEXT_TT_PASS_THROUGH :
2978 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002979 if (!ret) {
2980 printk(KERN_INFO "64bit %s uses identity mapping\n",
David Woodhouseecb509e2014-03-09 16:29:55 -07002981 dev_name(dev));
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002982 return 1;
2983 }
2984 }
2985 }
2986
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002987 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002988}
2989
David Woodhouse5040a912014-03-09 16:14:00 -07002990static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002991 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002992{
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002993 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002994 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002995 struct iova *iova;
2996 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002997 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002998 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002999 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003000
3001 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003002
David Woodhouse5040a912014-03-09 16:14:00 -07003003 if (iommu_no_mapping(dev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02003004 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003005
David Woodhouse5040a912014-03-09 16:14:00 -07003006 domain = get_valid_domain_for_dev(dev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003007 if (!domain)
3008 return 0;
3009
Weidong Han8c11e792008-12-08 15:29:22 +08003010 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01003011 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003012
David Woodhouse5040a912014-03-09 16:14:00 -07003013 iova = intel_alloc_iova(dev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003014 if (!iova)
3015 goto error;
3016
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003017 /*
3018 * Check if DMAR supports zero-length reads on write only
3019 * mappings..
3020 */
3021 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003022 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003023 prot |= DMA_PTE_READ;
3024 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3025 prot |= DMA_PTE_WRITE;
3026 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02003027 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003028 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02003029 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003030 * is not a big problem
3031 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01003032 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07003033 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003034 if (ret)
3035 goto error;
3036
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003037 /* it's a non-present to present mapping. Only flush if caching mode */
3038 if (cap_caching_mode(iommu->cap))
David Woodhouseea8ea462014-03-05 17:09:32 +00003039 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 0, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003040 else
Weidong Han8c11e792008-12-08 15:29:22 +08003041 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003042
David Woodhouse03d6a242009-06-28 15:33:46 +01003043 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
3044 start_paddr += paddr & ~PAGE_MASK;
3045 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003046
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003047error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003048 if (iova)
3049 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00003050 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
David Woodhouse5040a912014-03-09 16:14:00 -07003051 dev_name(dev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003052 return 0;
3053}
3054
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003055static dma_addr_t intel_map_page(struct device *dev, struct page *page,
3056 unsigned long offset, size_t size,
3057 enum dma_data_direction dir,
3058 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003059{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003060 return __intel_map_single(dev, page_to_phys(page) + offset, size,
David Woodhouse46333e32014-03-10 20:01:21 -07003061 dir, *dev->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003062}
3063
mark gross5e0d2a62008-03-04 15:22:08 -08003064static void flush_unmaps(void)
3065{
mark gross80b20dd2008-04-18 13:53:58 -07003066 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08003067
mark gross5e0d2a62008-03-04 15:22:08 -08003068 timer_on = 0;
3069
3070 /* just flush them all */
3071 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08003072 struct intel_iommu *iommu = g_iommus[i];
3073 if (!iommu)
3074 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07003075
Yu Zhao9dd2fe82009-05-18 13:51:36 +08003076 if (!deferred_flush[i].next)
3077 continue;
3078
Nadav Amit78d5f0f2010-04-08 23:00:41 +03003079 /* In caching mode, global flushes turn emulation expensive */
3080 if (!cap_caching_mode(iommu->cap))
3081 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08003082 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08003083 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08003084 unsigned long mask;
3085 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03003086 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08003087
Nadav Amit78d5f0f2010-04-08 23:00:41 +03003088 /* On real hardware multiple invalidations are expensive */
3089 if (cap_caching_mode(iommu->cap))
3090 iommu_flush_iotlb_psi(iommu, domain->id,
David Woodhouseea8ea462014-03-05 17:09:32 +00003091 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1,
3092 !deferred_flush[i].freelist[j], 0);
Nadav Amit78d5f0f2010-04-08 23:00:41 +03003093 else {
3094 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
3095 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
3096 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
3097 }
Yu Zhao93a23a72009-05-18 13:51:37 +08003098 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
David Woodhouseea8ea462014-03-05 17:09:32 +00003099 if (deferred_flush[i].freelist[j])
3100 dma_free_pagelist(deferred_flush[i].freelist[j]);
mark gross80b20dd2008-04-18 13:53:58 -07003101 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08003102 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08003103 }
3104
mark gross5e0d2a62008-03-04 15:22:08 -08003105 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08003106}
3107
3108static void flush_unmaps_timeout(unsigned long data)
3109{
mark gross80b20dd2008-04-18 13:53:58 -07003110 unsigned long flags;
3111
3112 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08003113 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07003114 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08003115}
3116
David Woodhouseea8ea462014-03-05 17:09:32 +00003117static void add_unmap(struct dmar_domain *dom, struct iova *iova, struct page *freelist)
mark gross5e0d2a62008-03-04 15:22:08 -08003118{
3119 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07003120 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08003121 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08003122
3123 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07003124 if (list_size == HIGH_WATER_MARK)
3125 flush_unmaps();
3126
Weidong Han8c11e792008-12-08 15:29:22 +08003127 iommu = domain_get_iommu(dom);
3128 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07003129
mark gross80b20dd2008-04-18 13:53:58 -07003130 next = deferred_flush[iommu_id].next;
3131 deferred_flush[iommu_id].domain[next] = dom;
3132 deferred_flush[iommu_id].iova[next] = iova;
David Woodhouseea8ea462014-03-05 17:09:32 +00003133 deferred_flush[iommu_id].freelist[next] = freelist;
mark gross80b20dd2008-04-18 13:53:58 -07003134 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08003135
3136 if (!timer_on) {
3137 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
3138 timer_on = 1;
3139 }
3140 list_size++;
3141 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
3142}
3143
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003144static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
3145 size_t size, enum dma_data_direction dir,
3146 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003147{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003148 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003149 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003150 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003151 struct intel_iommu *iommu;
David Woodhouseea8ea462014-03-05 17:09:32 +00003152 struct page *freelist;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003153
David Woodhouse73676832009-07-04 14:08:36 +01003154 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003155 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003156
David Woodhouse1525a292014-03-06 16:19:30 +00003157 domain = find_domain(dev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003158 BUG_ON(!domain);
3159
Weidong Han8c11e792008-12-08 15:29:22 +08003160 iommu = domain_get_iommu(domain);
3161
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003162 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01003163 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
3164 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003165 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003166
David Woodhoused794dc92009-06-28 00:27:49 +01003167 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3168 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003169
David Woodhoused794dc92009-06-28 00:27:49 +01003170 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
David Woodhouse207e3592014-03-09 16:12:32 -07003171 dev_name(dev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003172
David Woodhouseea8ea462014-03-05 17:09:32 +00003173 freelist = domain_unmap(domain, start_pfn, last_pfn);
David Woodhoused794dc92009-06-28 00:27:49 +01003174
mark gross5e0d2a62008-03-04 15:22:08 -08003175 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01003176 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
David Woodhouseea8ea462014-03-05 17:09:32 +00003177 last_pfn - start_pfn + 1, !freelist, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08003178 /* free iova */
3179 __free_iova(&domain->iovad, iova);
David Woodhouseea8ea462014-03-05 17:09:32 +00003180 dma_free_pagelist(freelist);
mark gross5e0d2a62008-03-04 15:22:08 -08003181 } else {
David Woodhouseea8ea462014-03-05 17:09:32 +00003182 add_unmap(domain, iova, freelist);
mark gross5e0d2a62008-03-04 15:22:08 -08003183 /*
3184 * queue up the release of the unmap to save the 1/6th of the
3185 * cpu used up by the iotlb flush operation...
3186 */
mark gross5e0d2a62008-03-04 15:22:08 -08003187 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003188}
3189
David Woodhouse5040a912014-03-09 16:14:00 -07003190static void *intel_alloc_coherent(struct device *dev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003191 dma_addr_t *dma_handle, gfp_t flags,
3192 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003193{
Akinobu Mita36746432014-06-04 16:06:51 -07003194 struct page *page = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003195 int order;
3196
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003197 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003198 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07003199
David Woodhouse5040a912014-03-09 16:14:00 -07003200 if (!iommu_no_mapping(dev))
Alex Williamsone8bb9102009-11-04 15:59:34 -07003201 flags &= ~(GFP_DMA | GFP_DMA32);
David Woodhouse5040a912014-03-09 16:14:00 -07003202 else if (dev->coherent_dma_mask < dma_get_required_mask(dev)) {
3203 if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
Alex Williamsone8bb9102009-11-04 15:59:34 -07003204 flags |= GFP_DMA;
3205 else
3206 flags |= GFP_DMA32;
3207 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003208
Akinobu Mita36746432014-06-04 16:06:51 -07003209 if (flags & __GFP_WAIT) {
3210 unsigned int count = size >> PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003211
Akinobu Mita36746432014-06-04 16:06:51 -07003212 page = dma_alloc_from_contiguous(dev, count, order);
3213 if (page && iommu_no_mapping(dev) &&
3214 page_to_phys(page) + size > dev->coherent_dma_mask) {
3215 dma_release_from_contiguous(dev, page, count);
3216 page = NULL;
3217 }
3218 }
3219
3220 if (!page)
3221 page = alloc_pages(flags, order);
3222 if (!page)
3223 return NULL;
3224 memset(page_address(page), 0, size);
3225
3226 *dma_handle = __intel_map_single(dev, page_to_phys(page), size,
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003227 DMA_BIDIRECTIONAL,
David Woodhouse5040a912014-03-09 16:14:00 -07003228 dev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003229 if (*dma_handle)
Akinobu Mita36746432014-06-04 16:06:51 -07003230 return page_address(page);
3231 if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
3232 __free_pages(page, order);
3233
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003234 return NULL;
3235}
3236
David Woodhouse5040a912014-03-09 16:14:00 -07003237static void intel_free_coherent(struct device *dev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003238 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003239{
3240 int order;
Akinobu Mita36746432014-06-04 16:06:51 -07003241 struct page *page = virt_to_page(vaddr);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003242
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003243 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003244 order = get_order(size);
3245
David Woodhouse5040a912014-03-09 16:14:00 -07003246 intel_unmap_page(dev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Akinobu Mita36746432014-06-04 16:06:51 -07003247 if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
3248 __free_pages(page, order);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003249}
3250
David Woodhouse5040a912014-03-09 16:14:00 -07003251static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist,
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003252 int nelems, enum dma_data_direction dir,
3253 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003254{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003255 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003256 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003257 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003258 struct intel_iommu *iommu;
David Woodhouseea8ea462014-03-05 17:09:32 +00003259 struct page *freelist;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003260
David Woodhouse5040a912014-03-09 16:14:00 -07003261 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003262 return;
3263
David Woodhouse5040a912014-03-09 16:14:00 -07003264 domain = find_domain(dev);
Weidong Han8c11e792008-12-08 15:29:22 +08003265 BUG_ON(!domain);
3266
3267 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003268
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003269 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003270 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3271 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003272 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003273
David Woodhoused794dc92009-06-28 00:27:49 +01003274 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3275 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003276
David Woodhouseea8ea462014-03-05 17:09:32 +00003277 freelist = domain_unmap(domain, start_pfn, last_pfn);
David Woodhoused794dc92009-06-28 00:27:49 +01003278
David Woodhouseacea0012009-07-14 01:55:11 +01003279 if (intel_iommu_strict) {
3280 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
David Woodhouseea8ea462014-03-05 17:09:32 +00003281 last_pfn - start_pfn + 1, !freelist, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003282 /* free iova */
3283 __free_iova(&domain->iovad, iova);
David Woodhouseea8ea462014-03-05 17:09:32 +00003284 dma_free_pagelist(freelist);
David Woodhouseacea0012009-07-14 01:55:11 +01003285 } else {
David Woodhouseea8ea462014-03-05 17:09:32 +00003286 add_unmap(domain, iova, freelist);
David Woodhouseacea0012009-07-14 01:55:11 +01003287 /*
3288 * queue up the release of the unmap to save the 1/6th of the
3289 * cpu used up by the iotlb flush operation...
3290 */
3291 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003292}
3293
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003294static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003295 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003296{
3297 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003298 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003299
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003300 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003301 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003302 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003303 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003304 }
3305 return nelems;
3306}
3307
David Woodhouse5040a912014-03-09 16:14:00 -07003308static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nelems,
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003309 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003310{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003311 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003312 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003313 size_t size = 0;
3314 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003315 struct iova *iova = NULL;
3316 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003317 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003318 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003319 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003320
3321 BUG_ON(dir == DMA_NONE);
David Woodhouse5040a912014-03-09 16:14:00 -07003322 if (iommu_no_mapping(dev))
3323 return intel_nontranslate_map_sg(dev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003324
David Woodhouse5040a912014-03-09 16:14:00 -07003325 domain = get_valid_domain_for_dev(dev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003326 if (!domain)
3327 return 0;
3328
Weidong Han8c11e792008-12-08 15:29:22 +08003329 iommu = domain_get_iommu(domain);
3330
David Woodhouseb536d242009-06-28 14:49:31 +01003331 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003332 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003333
David Woodhouse5040a912014-03-09 16:14:00 -07003334 iova = intel_alloc_iova(dev, domain, dma_to_mm_pfn(size),
3335 *dev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003336 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003337 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003338 return 0;
3339 }
3340
3341 /*
3342 * Check if DMAR supports zero-length reads on write only
3343 * mappings..
3344 */
3345 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003346 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003347 prot |= DMA_PTE_READ;
3348 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3349 prot |= DMA_PTE_WRITE;
3350
David Woodhouseb536d242009-06-28 14:49:31 +01003351 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003352
Fenghua Yuf5329592009-08-04 15:09:37 -07003353 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003354 if (unlikely(ret)) {
3355 /* clear the page */
3356 dma_pte_clear_range(domain, start_vpfn,
3357 start_vpfn + size - 1);
3358 /* free page tables */
3359 dma_pte_free_pagetable(domain, start_vpfn,
3360 start_vpfn + size - 1);
3361 /* free iova */
3362 __free_iova(&domain->iovad, iova);
3363 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003364 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003365
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003366 /* it's a non-present to present mapping. Only flush if caching mode */
3367 if (cap_caching_mode(iommu->cap))
David Woodhouseea8ea462014-03-05 17:09:32 +00003368 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 0, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003369 else
Weidong Han8c11e792008-12-08 15:29:22 +08003370 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003371
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003372 return nelems;
3373}
3374
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003375static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3376{
3377 return !dma_addr;
3378}
3379
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003380struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003381 .alloc = intel_alloc_coherent,
3382 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003383 .map_sg = intel_map_sg,
3384 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003385 .map_page = intel_map_page,
3386 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003387 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003388};
3389
3390static inline int iommu_domain_cache_init(void)
3391{
3392 int ret = 0;
3393
3394 iommu_domain_cache = kmem_cache_create("iommu_domain",
3395 sizeof(struct dmar_domain),
3396 0,
3397 SLAB_HWCACHE_ALIGN,
3398
3399 NULL);
3400 if (!iommu_domain_cache) {
3401 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3402 ret = -ENOMEM;
3403 }
3404
3405 return ret;
3406}
3407
3408static inline int iommu_devinfo_cache_init(void)
3409{
3410 int ret = 0;
3411
3412 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3413 sizeof(struct device_domain_info),
3414 0,
3415 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003416 NULL);
3417 if (!iommu_devinfo_cache) {
3418 printk(KERN_ERR "Couldn't create devinfo cache\n");
3419 ret = -ENOMEM;
3420 }
3421
3422 return ret;
3423}
3424
3425static inline int iommu_iova_cache_init(void)
3426{
3427 int ret = 0;
3428
3429 iommu_iova_cache = kmem_cache_create("iommu_iova",
3430 sizeof(struct iova),
3431 0,
3432 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003433 NULL);
3434 if (!iommu_iova_cache) {
3435 printk(KERN_ERR "Couldn't create iova cache\n");
3436 ret = -ENOMEM;
3437 }
3438
3439 return ret;
3440}
3441
3442static int __init iommu_init_mempool(void)
3443{
3444 int ret;
3445 ret = iommu_iova_cache_init();
3446 if (ret)
3447 return ret;
3448
3449 ret = iommu_domain_cache_init();
3450 if (ret)
3451 goto domain_error;
3452
3453 ret = iommu_devinfo_cache_init();
3454 if (!ret)
3455 return ret;
3456
3457 kmem_cache_destroy(iommu_domain_cache);
3458domain_error:
3459 kmem_cache_destroy(iommu_iova_cache);
3460
3461 return -ENOMEM;
3462}
3463
3464static void __init iommu_exit_mempool(void)
3465{
3466 kmem_cache_destroy(iommu_devinfo_cache);
3467 kmem_cache_destroy(iommu_domain_cache);
3468 kmem_cache_destroy(iommu_iova_cache);
3469
3470}
3471
Dan Williams556ab452010-07-23 15:47:56 -07003472static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3473{
3474 struct dmar_drhd_unit *drhd;
3475 u32 vtbar;
3476 int rc;
3477
3478 /* We know that this device on this chipset has its own IOMMU.
3479 * If we find it under a different IOMMU, then the BIOS is lying
3480 * to us. Hope that the IOMMU for this device is actually
3481 * disabled, and it needs no translation...
3482 */
3483 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3484 if (rc) {
3485 /* "can't" happen */
3486 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3487 return;
3488 }
3489 vtbar &= 0xffff0000;
3490
3491 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3492 drhd = dmar_find_matched_drhd_unit(pdev);
3493 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3494 TAINT_FIRMWARE_WORKAROUND,
3495 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3496 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3497}
3498DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3499
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003500static void __init init_no_remapping_devices(void)
3501{
3502 struct dmar_drhd_unit *drhd;
David Woodhouse832bd852014-03-07 15:08:36 +00003503 struct device *dev;
Jiang Liub683b232014-02-19 14:07:32 +08003504 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003505
3506 for_each_drhd_unit(drhd) {
3507 if (!drhd->include_all) {
Jiang Liub683b232014-02-19 14:07:32 +08003508 for_each_active_dev_scope(drhd->devices,
3509 drhd->devices_cnt, i, dev)
3510 break;
David Woodhouse832bd852014-03-07 15:08:36 +00003511 /* ignore DMAR unit if no devices exist */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003512 if (i == drhd->devices_cnt)
3513 drhd->ignored = 1;
3514 }
3515 }
3516
Jiang Liu7c919772014-01-06 14:18:18 +08003517 for_each_active_drhd_unit(drhd) {
Jiang Liu7c919772014-01-06 14:18:18 +08003518 if (drhd->include_all)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003519 continue;
3520
Jiang Liub683b232014-02-19 14:07:32 +08003521 for_each_active_dev_scope(drhd->devices,
3522 drhd->devices_cnt, i, dev)
David Woodhouse832bd852014-03-07 15:08:36 +00003523 if (!dev_is_pci(dev) || !IS_GFX_DEVICE(to_pci_dev(dev)))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003524 break;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003525 if (i < drhd->devices_cnt)
3526 continue;
3527
David Woodhousec0771df2011-10-14 20:59:46 +01003528 /* This IOMMU has *only* gfx devices. Either bypass it or
3529 set the gfx_mapped flag, as appropriate */
3530 if (dmar_map_gfx) {
3531 intel_iommu_gfx_mapped = 1;
3532 } else {
3533 drhd->ignored = 1;
Jiang Liub683b232014-02-19 14:07:32 +08003534 for_each_active_dev_scope(drhd->devices,
3535 drhd->devices_cnt, i, dev)
David Woodhouse832bd852014-03-07 15:08:36 +00003536 dev->archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003537 }
3538 }
3539}
3540
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003541#ifdef CONFIG_SUSPEND
3542static int init_iommu_hw(void)
3543{
3544 struct dmar_drhd_unit *drhd;
3545 struct intel_iommu *iommu = NULL;
3546
3547 for_each_active_iommu(iommu, drhd)
3548 if (iommu->qi)
3549 dmar_reenable_qi(iommu);
3550
Joseph Cihulab7792602011-05-03 00:08:37 -07003551 for_each_iommu(iommu, drhd) {
3552 if (drhd->ignored) {
3553 /*
3554 * we always have to disable PMRs or DMA may fail on
3555 * this device
3556 */
3557 if (force_on)
3558 iommu_disable_protect_mem_regions(iommu);
3559 continue;
3560 }
3561
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003562 iommu_flush_write_buffer(iommu);
3563
3564 iommu_set_root_entry(iommu);
3565
3566 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003567 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003568 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003569 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003570 if (iommu_enable_translation(iommu))
3571 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003572 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003573 }
3574
3575 return 0;
3576}
3577
3578static void iommu_flush_all(void)
3579{
3580 struct dmar_drhd_unit *drhd;
3581 struct intel_iommu *iommu;
3582
3583 for_each_active_iommu(iommu, drhd) {
3584 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003585 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003586 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003587 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003588 }
3589}
3590
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003591static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003592{
3593 struct dmar_drhd_unit *drhd;
3594 struct intel_iommu *iommu = NULL;
3595 unsigned long flag;
3596
3597 for_each_active_iommu(iommu, drhd) {
3598 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3599 GFP_ATOMIC);
3600 if (!iommu->iommu_state)
3601 goto nomem;
3602 }
3603
3604 iommu_flush_all();
3605
3606 for_each_active_iommu(iommu, drhd) {
3607 iommu_disable_translation(iommu);
3608
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003609 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003610
3611 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3612 readl(iommu->reg + DMAR_FECTL_REG);
3613 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3614 readl(iommu->reg + DMAR_FEDATA_REG);
3615 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3616 readl(iommu->reg + DMAR_FEADDR_REG);
3617 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3618 readl(iommu->reg + DMAR_FEUADDR_REG);
3619
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003620 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003621 }
3622 return 0;
3623
3624nomem:
3625 for_each_active_iommu(iommu, drhd)
3626 kfree(iommu->iommu_state);
3627
3628 return -ENOMEM;
3629}
3630
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003631static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003632{
3633 struct dmar_drhd_unit *drhd;
3634 struct intel_iommu *iommu = NULL;
3635 unsigned long flag;
3636
3637 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003638 if (force_on)
3639 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3640 else
3641 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003642 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003643 }
3644
3645 for_each_active_iommu(iommu, drhd) {
3646
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003647 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003648
3649 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3650 iommu->reg + DMAR_FECTL_REG);
3651 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3652 iommu->reg + DMAR_FEDATA_REG);
3653 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3654 iommu->reg + DMAR_FEADDR_REG);
3655 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3656 iommu->reg + DMAR_FEUADDR_REG);
3657
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003658 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003659 }
3660
3661 for_each_active_iommu(iommu, drhd)
3662 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003663}
3664
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003665static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003666 .resume = iommu_resume,
3667 .suspend = iommu_suspend,
3668};
3669
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003670static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003671{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003672 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003673}
3674
3675#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003676static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003677#endif /* CONFIG_PM */
3678
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003679
3680int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3681{
3682 struct acpi_dmar_reserved_memory *rmrr;
3683 struct dmar_rmrr_unit *rmrru;
3684
3685 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3686 if (!rmrru)
3687 return -ENOMEM;
3688
3689 rmrru->hdr = header;
3690 rmrr = (struct acpi_dmar_reserved_memory *)header;
3691 rmrru->base_address = rmrr->base_address;
3692 rmrru->end_address = rmrr->end_address;
Jiang Liu2e455282014-02-19 14:07:36 +08003693 rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
3694 ((void *)rmrr) + rmrr->header.length,
3695 &rmrru->devices_cnt);
3696 if (rmrru->devices_cnt && rmrru->devices == NULL) {
3697 kfree(rmrru);
3698 return -ENOMEM;
3699 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003700
Jiang Liu2e455282014-02-19 14:07:36 +08003701 list_add(&rmrru->list, &dmar_rmrr_units);
3702
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003703 return 0;
3704}
3705
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003706int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3707{
3708 struct acpi_dmar_atsr *atsr;
3709 struct dmar_atsr_unit *atsru;
3710
3711 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3712 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3713 if (!atsru)
3714 return -ENOMEM;
3715
3716 atsru->hdr = hdr;
3717 atsru->include_all = atsr->flags & 0x1;
Jiang Liu2e455282014-02-19 14:07:36 +08003718 if (!atsru->include_all) {
3719 atsru->devices = dmar_alloc_dev_scope((void *)(atsr + 1),
3720 (void *)atsr + atsr->header.length,
3721 &atsru->devices_cnt);
3722 if (atsru->devices_cnt && atsru->devices == NULL) {
3723 kfree(atsru);
3724 return -ENOMEM;
3725 }
3726 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003727
Jiang Liu0e242612014-02-19 14:07:34 +08003728 list_add_rcu(&atsru->list, &dmar_atsr_units);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003729
3730 return 0;
3731}
3732
Jiang Liu9bdc5312014-01-06 14:18:27 +08003733static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
3734{
3735 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
3736 kfree(atsru);
3737}
3738
3739static void intel_iommu_free_dmars(void)
3740{
3741 struct dmar_rmrr_unit *rmrru, *rmrr_n;
3742 struct dmar_atsr_unit *atsru, *atsr_n;
3743
3744 list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
3745 list_del(&rmrru->list);
3746 dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
3747 kfree(rmrru);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003748 }
3749
Jiang Liu9bdc5312014-01-06 14:18:27 +08003750 list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
3751 list_del(&atsru->list);
3752 intel_iommu_free_atsr(atsru);
3753 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003754}
3755
3756int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3757{
Jiang Liub683b232014-02-19 14:07:32 +08003758 int i, ret = 1;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003759 struct pci_bus *bus;
David Woodhouse832bd852014-03-07 15:08:36 +00003760 struct pci_dev *bridge = NULL;
3761 struct device *tmp;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003762 struct acpi_dmar_atsr *atsr;
3763 struct dmar_atsr_unit *atsru;
3764
3765 dev = pci_physfn(dev);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003766 for (bus = dev->bus; bus; bus = bus->parent) {
Jiang Liub5f82dd2014-02-19 14:07:31 +08003767 bridge = bus->self;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003768 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003769 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003770 return 0;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003771 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003772 break;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003773 }
Jiang Liub5f82dd2014-02-19 14:07:31 +08003774 if (!bridge)
3775 return 0;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003776
Jiang Liu0e242612014-02-19 14:07:34 +08003777 rcu_read_lock();
Jiang Liub5f82dd2014-02-19 14:07:31 +08003778 list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
3779 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3780 if (atsr->segment != pci_domain_nr(dev->bus))
3781 continue;
3782
Jiang Liub683b232014-02-19 14:07:32 +08003783 for_each_dev_scope(atsru->devices, atsru->devices_cnt, i, tmp)
David Woodhouse832bd852014-03-07 15:08:36 +00003784 if (tmp == &bridge->dev)
Jiang Liub683b232014-02-19 14:07:32 +08003785 goto out;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003786
3787 if (atsru->include_all)
Jiang Liub683b232014-02-19 14:07:32 +08003788 goto out;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003789 }
Jiang Liub683b232014-02-19 14:07:32 +08003790 ret = 0;
3791out:
Jiang Liu0e242612014-02-19 14:07:34 +08003792 rcu_read_unlock();
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003793
Jiang Liub683b232014-02-19 14:07:32 +08003794 return ret;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003795}
3796
Jiang Liu59ce0512014-02-19 14:07:35 +08003797int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
3798{
3799 int ret = 0;
3800 struct dmar_rmrr_unit *rmrru;
3801 struct dmar_atsr_unit *atsru;
3802 struct acpi_dmar_atsr *atsr;
3803 struct acpi_dmar_reserved_memory *rmrr;
3804
3805 if (!intel_iommu_enabled && system_state != SYSTEM_BOOTING)
3806 return 0;
3807
3808 list_for_each_entry(rmrru, &dmar_rmrr_units, list) {
3809 rmrr = container_of(rmrru->hdr,
3810 struct acpi_dmar_reserved_memory, header);
3811 if (info->event == BUS_NOTIFY_ADD_DEVICE) {
3812 ret = dmar_insert_dev_scope(info, (void *)(rmrr + 1),
3813 ((void *)rmrr) + rmrr->header.length,
3814 rmrr->segment, rmrru->devices,
3815 rmrru->devices_cnt);
Jiang Liu27e24952014-06-20 15:08:06 +08003816 if(ret < 0)
Jiang Liu59ce0512014-02-19 14:07:35 +08003817 return ret;
3818 } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
Jiang Liu27e24952014-06-20 15:08:06 +08003819 dmar_remove_dev_scope(info, rmrr->segment,
3820 rmrru->devices, rmrru->devices_cnt);
Jiang Liu59ce0512014-02-19 14:07:35 +08003821 }
3822 }
3823
3824 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3825 if (atsru->include_all)
3826 continue;
3827
3828 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3829 if (info->event == BUS_NOTIFY_ADD_DEVICE) {
3830 ret = dmar_insert_dev_scope(info, (void *)(atsr + 1),
3831 (void *)atsr + atsr->header.length,
3832 atsr->segment, atsru->devices,
3833 atsru->devices_cnt);
3834 if (ret > 0)
3835 break;
3836 else if(ret < 0)
3837 return ret;
3838 } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
3839 if (dmar_remove_dev_scope(info, atsr->segment,
3840 atsru->devices, atsru->devices_cnt))
3841 break;
3842 }
3843 }
3844
3845 return 0;
3846}
3847
Fenghua Yu99dcade2009-11-11 07:23:06 -08003848/*
3849 * Here we only respond to action of unbound device from driver.
3850 *
3851 * Added device is not attached to its DMAR domain here yet. That will happen
3852 * when mapping the device to iova.
3853 */
3854static int device_notifier(struct notifier_block *nb,
3855 unsigned long action, void *data)
3856{
3857 struct device *dev = data;
Fenghua Yu99dcade2009-11-11 07:23:06 -08003858 struct dmar_domain *domain;
3859
David Woodhouse3d891942014-03-06 15:59:26 +00003860 if (iommu_dummy(dev))
David Woodhouse44cd6132009-12-02 10:18:30 +00003861 return 0;
3862
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003863 if (action != BUS_NOTIFY_UNBOUND_DRIVER &&
3864 action != BUS_NOTIFY_DEL_DEVICE)
3865 return 0;
3866
David Woodhouse1525a292014-03-06 16:19:30 +00003867 domain = find_domain(dev);
Fenghua Yu99dcade2009-11-11 07:23:06 -08003868 if (!domain)
3869 return 0;
3870
Jiang Liu3a5670e2014-02-19 14:07:33 +08003871 down_read(&dmar_global_lock);
David Woodhousebf9c9ed2014-03-09 16:19:13 -07003872 domain_remove_one_dev_info(domain, dev);
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003873 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3874 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3875 list_empty(&domain->devices))
3876 domain_exit(domain);
Jiang Liu3a5670e2014-02-19 14:07:33 +08003877 up_read(&dmar_global_lock);
Alex Williamsona97590e2011-03-04 14:52:16 -07003878
Fenghua Yu99dcade2009-11-11 07:23:06 -08003879 return 0;
3880}
3881
3882static struct notifier_block device_nb = {
3883 .notifier_call = device_notifier,
3884};
3885
Jiang Liu75f05562014-02-19 14:07:37 +08003886static int intel_iommu_memory_notifier(struct notifier_block *nb,
3887 unsigned long val, void *v)
3888{
3889 struct memory_notify *mhp = v;
3890 unsigned long long start, end;
3891 unsigned long start_vpfn, last_vpfn;
3892
3893 switch (val) {
3894 case MEM_GOING_ONLINE:
3895 start = mhp->start_pfn << PAGE_SHIFT;
3896 end = ((mhp->start_pfn + mhp->nr_pages) << PAGE_SHIFT) - 1;
3897 if (iommu_domain_identity_map(si_domain, start, end)) {
3898 pr_warn("dmar: failed to build identity map for [%llx-%llx]\n",
3899 start, end);
3900 return NOTIFY_BAD;
3901 }
3902 break;
3903
3904 case MEM_OFFLINE:
3905 case MEM_CANCEL_ONLINE:
3906 start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
3907 last_vpfn = mm_to_dma_pfn(mhp->start_pfn + mhp->nr_pages - 1);
3908 while (start_vpfn <= last_vpfn) {
3909 struct iova *iova;
3910 struct dmar_drhd_unit *drhd;
3911 struct intel_iommu *iommu;
David Woodhouseea8ea462014-03-05 17:09:32 +00003912 struct page *freelist;
Jiang Liu75f05562014-02-19 14:07:37 +08003913
3914 iova = find_iova(&si_domain->iovad, start_vpfn);
3915 if (iova == NULL) {
3916 pr_debug("dmar: failed get IOVA for PFN %lx\n",
3917 start_vpfn);
3918 break;
3919 }
3920
3921 iova = split_and_remove_iova(&si_domain->iovad, iova,
3922 start_vpfn, last_vpfn);
3923 if (iova == NULL) {
3924 pr_warn("dmar: failed to split IOVA PFN [%lx-%lx]\n",
3925 start_vpfn, last_vpfn);
3926 return NOTIFY_BAD;
3927 }
3928
David Woodhouseea8ea462014-03-05 17:09:32 +00003929 freelist = domain_unmap(si_domain, iova->pfn_lo,
3930 iova->pfn_hi);
3931
Jiang Liu75f05562014-02-19 14:07:37 +08003932 rcu_read_lock();
3933 for_each_active_iommu(iommu, drhd)
3934 iommu_flush_iotlb_psi(iommu, si_domain->id,
3935 iova->pfn_lo,
David Woodhouseea8ea462014-03-05 17:09:32 +00003936 iova->pfn_hi - iova->pfn_lo + 1,
3937 !freelist, 0);
Jiang Liu75f05562014-02-19 14:07:37 +08003938 rcu_read_unlock();
David Woodhouseea8ea462014-03-05 17:09:32 +00003939 dma_free_pagelist(freelist);
Jiang Liu75f05562014-02-19 14:07:37 +08003940
3941 start_vpfn = iova->pfn_hi + 1;
3942 free_iova_mem(iova);
3943 }
3944 break;
3945 }
3946
3947 return NOTIFY_OK;
3948}
3949
3950static struct notifier_block intel_iommu_memory_nb = {
3951 .notifier_call = intel_iommu_memory_notifier,
3952 .priority = 0
3953};
3954
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003955int __init intel_iommu_init(void)
3956{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003957 int ret = -ENODEV;
Takao Indoh3a93c842013-04-23 17:35:03 +09003958 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +08003959 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003960
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003961 /* VT-d is required for a TXT/tboot launch, so enforce that */
3962 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003963
Jiang Liu3a5670e2014-02-19 14:07:33 +08003964 if (iommu_init_mempool()) {
3965 if (force_on)
3966 panic("tboot: Failed to initialize iommu memory\n");
3967 return -ENOMEM;
3968 }
3969
3970 down_write(&dmar_global_lock);
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003971 if (dmar_table_init()) {
3972 if (force_on)
3973 panic("tboot: Failed to initialize DMAR table\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003974 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003975 }
3976
Takao Indoh3a93c842013-04-23 17:35:03 +09003977 /*
3978 * Disable translation if already enabled prior to OS handover.
3979 */
Jiang Liu7c919772014-01-06 14:18:18 +08003980 for_each_active_iommu(iommu, drhd)
Takao Indoh3a93c842013-04-23 17:35:03 +09003981 if (iommu->gcmd & DMA_GCMD_TE)
3982 iommu_disable_translation(iommu);
Takao Indoh3a93c842013-04-23 17:35:03 +09003983
Suresh Siddhac2c72862011-08-23 17:05:19 -07003984 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003985 if (force_on)
3986 panic("tboot: Failed to initialize DMAR device scope\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003987 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003988 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003989
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003990 if (no_iommu || dmar_disabled)
Jiang Liu9bdc5312014-01-06 14:18:27 +08003991 goto out_free_dmar;
Suresh Siddha2ae21012008-07-10 11:16:43 -07003992
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003993 if (list_empty(&dmar_rmrr_units))
3994 printk(KERN_INFO "DMAR: No RMRR found\n");
3995
3996 if (list_empty(&dmar_atsr_units))
3997 printk(KERN_INFO "DMAR: No ATSR found\n");
3998
Joseph Cihula51a63e62011-03-21 11:04:24 -07003999 if (dmar_init_reserved_ranges()) {
4000 if (force_on)
4001 panic("tboot: Failed to reserve iommu ranges\n");
Jiang Liu3a5670e2014-02-19 14:07:33 +08004002 goto out_free_reserved_range;
Joseph Cihula51a63e62011-03-21 11:04:24 -07004003 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004004
4005 init_no_remapping_devices();
4006
Joseph Cihulab7792602011-05-03 00:08:37 -07004007 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004008 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07004009 if (force_on)
4010 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004011 printk(KERN_ERR "IOMMU: dmar init failed\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08004012 goto out_free_reserved_range;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004013 }
Jiang Liu3a5670e2014-02-19 14:07:33 +08004014 up_write(&dmar_global_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004015 printk(KERN_INFO
4016 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
4017
mark gross5e0d2a62008-03-04 15:22:08 -08004018 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09004019#ifdef CONFIG_SWIOTLB
4020 swiotlb = 0;
4021#endif
David Woodhouse19943b02009-08-04 16:19:20 +01004022 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07004023
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01004024 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004025
Joerg Roedel4236d97d2011-09-06 17:56:07 +02004026 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Fenghua Yu99dcade2009-11-11 07:23:06 -08004027 bus_register_notifier(&pci_bus_type, &device_nb);
Jiang Liu75f05562014-02-19 14:07:37 +08004028 if (si_domain && !hw_pass_through)
4029 register_memory_notifier(&intel_iommu_memory_nb);
Fenghua Yu99dcade2009-11-11 07:23:06 -08004030
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02004031 intel_iommu_enabled = 1;
4032
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004033 return 0;
Jiang Liu9bdc5312014-01-06 14:18:27 +08004034
4035out_free_reserved_range:
4036 put_iova_domain(&reserved_iova_list);
Jiang Liu9bdc5312014-01-06 14:18:27 +08004037out_free_dmar:
4038 intel_iommu_free_dmars();
Jiang Liu3a5670e2014-02-19 14:07:33 +08004039 up_write(&dmar_global_lock);
4040 iommu_exit_mempool();
Jiang Liu9bdc5312014-01-06 14:18:27 +08004041 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004042}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07004043
Han, Weidong3199aa62009-02-26 17:31:12 +08004044static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
David Woodhouse0bcb3e22014-03-06 17:12:03 +00004045 struct device *dev)
Han, Weidong3199aa62009-02-26 17:31:12 +08004046{
David Woodhouse0bcb3e22014-03-06 17:12:03 +00004047 struct pci_dev *tmp, *parent, *pdev;
Han, Weidong3199aa62009-02-26 17:31:12 +08004048
David Woodhouse0bcb3e22014-03-06 17:12:03 +00004049 if (!iommu || !dev || !dev_is_pci(dev))
Han, Weidong3199aa62009-02-26 17:31:12 +08004050 return;
4051
David Woodhouse0bcb3e22014-03-06 17:12:03 +00004052 pdev = to_pci_dev(dev);
4053
Han, Weidong3199aa62009-02-26 17:31:12 +08004054 /* dependent device detach */
4055 tmp = pci_find_upstream_pcie_bridge(pdev);
4056 /* Secondary interface's bus number and devfn 0 */
4057 if (tmp) {
4058 parent = pdev->bus->self;
4059 while (parent != tmp) {
4060 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01004061 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08004062 parent = parent->bus->self;
4063 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05004064 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08004065 iommu_detach_dev(iommu,
4066 tmp->subordinate->number, 0);
4067 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01004068 iommu_detach_dev(iommu, tmp->bus->number,
4069 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08004070 }
4071}
4072
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004073static void domain_remove_one_dev_info(struct dmar_domain *domain,
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004074 struct device *dev)
Weidong Hanc7151a82008-12-08 22:51:37 +08004075{
Yijing Wangbca2b912013-10-31 17:26:04 +08004076 struct device_domain_info *info, *tmp;
Weidong Hanc7151a82008-12-08 22:51:37 +08004077 struct intel_iommu *iommu;
4078 unsigned long flags;
4079 int found = 0;
David Woodhouse156baca2014-03-09 14:00:57 -07004080 u8 bus, devfn;
Weidong Hanc7151a82008-12-08 22:51:37 +08004081
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004082 iommu = device_to_iommu(dev, &bus, &devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08004083 if (!iommu)
4084 return;
4085
4086 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wangbca2b912013-10-31 17:26:04 +08004087 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004088 if (info->iommu == iommu && info->bus == bus &&
4089 info->devfn == devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01004090 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08004091 spin_unlock_irqrestore(&device_domain_lock, flags);
4092
Yu Zhao93a23a72009-05-18 13:51:37 +08004093 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08004094 iommu_detach_dev(iommu, info->bus, info->devfn);
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004095 iommu_detach_dependent_devices(iommu, dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08004096 free_devinfo_mem(info);
4097
4098 spin_lock_irqsave(&device_domain_lock, flags);
4099
4100 if (found)
4101 break;
4102 else
4103 continue;
4104 }
4105
4106 /* if there is no other devices under the same iommu
4107 * owned by this domain, clear this iommu in iommu_bmp
4108 * update iommu count and coherency
4109 */
David Woodhouse8bbc4412014-03-09 13:52:37 -07004110 if (info->iommu == iommu)
Weidong Hanc7151a82008-12-08 22:51:37 +08004111 found = 1;
4112 }
4113
Roland Dreier3e7abe22011-07-20 06:22:21 -07004114 spin_unlock_irqrestore(&device_domain_lock, flags);
4115
Weidong Hanc7151a82008-12-08 22:51:37 +08004116 if (found == 0) {
4117 unsigned long tmp_flags;
4118 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08004119 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08004120 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08004121 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08004122 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07004123
Alex Williamson9b4554b2011-05-24 12:19:04 -04004124 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
4125 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
4126 spin_lock_irqsave(&iommu->lock, tmp_flags);
4127 clear_bit(domain->id, iommu->domain_ids);
4128 iommu->domains[domain->id] = NULL;
4129 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
4130 }
Weidong Hanc7151a82008-12-08 22:51:37 +08004131 }
Weidong Hanc7151a82008-12-08 22:51:37 +08004132}
4133
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004134static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08004135{
4136 int adjust_width;
4137
4138 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08004139 domain_reserve_special_ranges(domain);
4140
4141 /* calculate AGAW */
4142 domain->gaw = guest_width;
4143 adjust_width = guestwidth_to_adjustwidth(guest_width);
4144 domain->agaw = width_to_agaw(adjust_width);
4145
Weidong Han5e98c4b2008-12-08 23:03:27 +08004146 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08004147 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004148 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004149 domain->max_addr = 0;
Weidong Han5e98c4b2008-12-08 23:03:27 +08004150
4151 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07004152 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08004153 if (!domain->pgd)
4154 return -ENOMEM;
4155 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
4156 return 0;
4157}
4158
Joerg Roedel5d450802008-12-03 14:52:32 +01004159static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03004160{
Joerg Roedel5d450802008-12-03 14:52:32 +01004161 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03004162
Jiang Liu92d03cc2014-02-19 14:07:28 +08004163 dmar_domain = alloc_domain(true);
Joerg Roedel5d450802008-12-03 14:52:32 +01004164 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03004165 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01004166 "intel_iommu_domain_init: dmar_domain == NULL\n");
4167 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03004168 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004169 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03004170 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01004171 "intel_iommu_domain_init() failed\n");
Jiang Liu92d03cc2014-02-19 14:07:28 +08004172 domain_exit(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01004173 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03004174 }
Allen Kay8140a952011-10-14 12:32:17 -07004175 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01004176 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004177
Joerg Roedel8a0e7152012-01-26 19:40:54 +01004178 domain->geometry.aperture_start = 0;
4179 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
4180 domain->geometry.force_aperture = true;
4181
Joerg Roedel5d450802008-12-03 14:52:32 +01004182 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004183}
Kay, Allen M38717942008-09-09 18:37:29 +03004184
Joerg Roedel5d450802008-12-03 14:52:32 +01004185static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03004186{
Joerg Roedel5d450802008-12-03 14:52:32 +01004187 struct dmar_domain *dmar_domain = domain->priv;
4188
4189 domain->priv = NULL;
Jiang Liu92d03cc2014-02-19 14:07:28 +08004190 domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03004191}
Kay, Allen M38717942008-09-09 18:37:29 +03004192
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004193static int intel_iommu_attach_device(struct iommu_domain *domain,
4194 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004195{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004196 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004197 struct intel_iommu *iommu;
4198 int addr_width;
David Woodhouse156baca2014-03-09 14:00:57 -07004199 u8 bus, devfn;
Kay, Allen M38717942008-09-09 18:37:29 +03004200
David Woodhouse7207d8f2014-03-09 16:31:06 -07004201 /* normally dev is not mapped */
4202 if (unlikely(domain_context_mapped(dev))) {
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004203 struct dmar_domain *old_domain;
4204
David Woodhouse1525a292014-03-06 16:19:30 +00004205 old_domain = find_domain(dev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004206 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004207 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
4208 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004209 domain_remove_one_dev_info(old_domain, dev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004210 else
4211 domain_remove_dev_info(old_domain);
4212 }
4213 }
4214
David Woodhouse156baca2014-03-09 14:00:57 -07004215 iommu = device_to_iommu(dev, &bus, &devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004216 if (!iommu)
4217 return -ENODEV;
4218
4219 /* check if this iommu agaw is sufficient for max mapped address */
4220 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01004221 if (addr_width > cap_mgaw(iommu->cap))
4222 addr_width = cap_mgaw(iommu->cap);
4223
4224 if (dmar_domain->max_addr > (1LL << addr_width)) {
4225 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004226 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01004227 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004228 return -EFAULT;
4229 }
Tom Lyona99c47a2010-05-17 08:20:45 +01004230 dmar_domain->gaw = addr_width;
4231
4232 /*
4233 * Knock out extra levels of page tables if necessary
4234 */
4235 while (iommu->agaw < dmar_domain->agaw) {
4236 struct dma_pte *pte;
4237
4238 pte = dmar_domain->pgd;
4239 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08004240 dmar_domain->pgd = (struct dma_pte *)
4241 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01004242 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01004243 }
4244 dmar_domain->agaw--;
4245 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004246
David Woodhouse5913c9b2014-03-09 16:27:31 -07004247 return domain_add_dev_info(dmar_domain, dev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004248}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004249
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004250static void intel_iommu_detach_device(struct iommu_domain *domain,
4251 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004252{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004253 struct dmar_domain *dmar_domain = domain->priv;
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004254
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004255 domain_remove_one_dev_info(dmar_domain, dev);
Kay, Allen M38717942008-09-09 18:37:29 +03004256}
Kay, Allen M38717942008-09-09 18:37:29 +03004257
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004258static int intel_iommu_map(struct iommu_domain *domain,
4259 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004260 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03004261{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004262 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004263 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004264 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004265 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004266
Joerg Roedeldde57a22008-12-03 15:04:09 +01004267 if (iommu_prot & IOMMU_READ)
4268 prot |= DMA_PTE_READ;
4269 if (iommu_prot & IOMMU_WRITE)
4270 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08004271 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4272 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004273
David Woodhouse163cc522009-06-28 00:51:17 +01004274 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004275 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004276 u64 end;
4277
4278 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01004279 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004280 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004281 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004282 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004283 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004284 return -EFAULT;
4285 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004286 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004287 }
David Woodhousead051222009-06-28 14:22:28 +01004288 /* Round up size to next multiple of PAGE_SIZE, if it and
4289 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004290 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004291 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4292 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004293 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004294}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004295
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004296static size_t intel_iommu_unmap(struct iommu_domain *domain,
David Woodhouseea8ea462014-03-05 17:09:32 +00004297 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004298{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004299 struct dmar_domain *dmar_domain = domain->priv;
David Woodhouseea8ea462014-03-05 17:09:32 +00004300 struct page *freelist = NULL;
4301 struct intel_iommu *iommu;
4302 unsigned long start_pfn, last_pfn;
4303 unsigned int npages;
4304 int iommu_id, num, ndomains, level = 0;
Sheng Yang4b99d352009-07-08 11:52:52 +01004305
David Woodhouse5cf0a762014-03-19 16:07:49 +00004306 /* Cope with horrid API which requires us to unmap more than the
4307 size argument if it happens to be a large-page mapping. */
4308 if (!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level))
4309 BUG();
4310
4311 if (size < VTD_PAGE_SIZE << level_to_offset_bits(level))
4312 size = VTD_PAGE_SIZE << level_to_offset_bits(level);
4313
David Woodhouseea8ea462014-03-05 17:09:32 +00004314 start_pfn = iova >> VTD_PAGE_SHIFT;
4315 last_pfn = (iova + size - 1) >> VTD_PAGE_SHIFT;
4316
4317 freelist = domain_unmap(dmar_domain, start_pfn, last_pfn);
4318
4319 npages = last_pfn - start_pfn + 1;
4320
4321 for_each_set_bit(iommu_id, dmar_domain->iommu_bmp, g_num_of_iommus) {
4322 iommu = g_iommus[iommu_id];
4323
4324 /*
4325 * find bit position of dmar_domain
4326 */
4327 ndomains = cap_ndoms(iommu->cap);
4328 for_each_set_bit(num, iommu->domain_ids, ndomains) {
4329 if (iommu->domains[num] == dmar_domain)
4330 iommu_flush_iotlb_psi(iommu, num, start_pfn,
4331 npages, !freelist, 0);
4332 }
4333
4334 }
4335
4336 dma_free_pagelist(freelist);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004337
David Woodhouse163cc522009-06-28 00:51:17 +01004338 if (dmar_domain->max_addr == iova + size)
4339 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004340
David Woodhouse5cf0a762014-03-19 16:07:49 +00004341 return size;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004342}
Kay, Allen M38717942008-09-09 18:37:29 +03004343
Joerg Roedeld14d6572008-12-03 15:06:57 +01004344static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
Varun Sethibb5547a2013-03-29 01:23:58 +05304345 dma_addr_t iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004346{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004347 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004348 struct dma_pte *pte;
David Woodhouse5cf0a762014-03-19 16:07:49 +00004349 int level = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004350 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004351
David Woodhouse5cf0a762014-03-19 16:07:49 +00004352 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
Kay, Allen M38717942008-09-09 18:37:29 +03004353 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004354 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004355
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004356 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004357}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004358
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004359static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4360 unsigned long cap)
4361{
4362 struct dmar_domain *dmar_domain = domain->priv;
4363
4364 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4365 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004366 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004367 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004368
4369 return 0;
4370}
4371
Alex Williamson783f1572012-05-30 14:19:43 -06004372#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4373
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004374static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004375{
4376 struct pci_dev *pdev = to_pci_dev(dev);
Alex Williamson3da4af02012-11-13 10:22:03 -07004377 struct pci_dev *bridge, *dma_pdev = NULL;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004378 struct iommu_group *group;
4379 int ret;
David Woodhouse156baca2014-03-09 14:00:57 -07004380 u8 bus, devfn;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004381
David Woodhouse156baca2014-03-09 14:00:57 -07004382 if (!device_to_iommu(dev, &bus, &devfn))
Alex Williamson70ae6f02011-10-21 15:56:11 -04004383 return -ENODEV;
4384
4385 bridge = pci_find_upstream_pcie_bridge(pdev);
4386 if (bridge) {
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004387 if (pci_is_pcie(bridge))
4388 dma_pdev = pci_get_domain_bus_and_slot(
4389 pci_domain_nr(pdev->bus),
4390 bridge->subordinate->number, 0);
Alex Williamson3da4af02012-11-13 10:22:03 -07004391 if (!dma_pdev)
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004392 dma_pdev = pci_dev_get(bridge);
4393 } else
4394 dma_pdev = pci_dev_get(pdev);
4395
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004396 /* Account for quirked devices */
Alex Williamson783f1572012-05-30 14:19:43 -06004397 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4398
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004399 /*
4400 * If it's a multifunction device that does not support our
Alex Williamsonc14d2692013-05-30 12:39:18 -06004401 * required ACS flags, add to the same group as lowest numbered
4402 * function that also does not suport the required ACS flags.
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004403 */
Alex Williamson783f1572012-05-30 14:19:43 -06004404 if (dma_pdev->multifunction &&
Alex Williamsonc14d2692013-05-30 12:39:18 -06004405 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
4406 u8 i, slot = PCI_SLOT(dma_pdev->devfn);
4407
4408 for (i = 0; i < 8; i++) {
4409 struct pci_dev *tmp;
4410
4411 tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
4412 if (!tmp)
4413 continue;
4414
4415 if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
4416 swap_pci_ref(&dma_pdev, tmp);
4417 break;
4418 }
4419 pci_dev_put(tmp);
4420 }
4421 }
Alex Williamson783f1572012-05-30 14:19:43 -06004422
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004423 /*
4424 * Devices on the root bus go through the iommu. If that's not us,
4425 * find the next upstream device and test ACS up to the root bus.
4426 * Finding the next device may require skipping virtual buses.
4427 */
Alex Williamson783f1572012-05-30 14:19:43 -06004428 while (!pci_is_root_bus(dma_pdev->bus)) {
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004429 struct pci_bus *bus = dma_pdev->bus;
4430
4431 while (!bus->self) {
4432 if (!pci_is_root_bus(bus))
4433 bus = bus->parent;
4434 else
4435 goto root_bus;
4436 }
4437
4438 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
Alex Williamson783f1572012-05-30 14:19:43 -06004439 break;
4440
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004441 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
Alex Williamson70ae6f02011-10-21 15:56:11 -04004442 }
4443
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004444root_bus:
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004445 group = iommu_group_get(&dma_pdev->dev);
4446 pci_dev_put(dma_pdev);
4447 if (!group) {
4448 group = iommu_group_alloc();
4449 if (IS_ERR(group))
4450 return PTR_ERR(group);
4451 }
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004452
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004453 ret = iommu_group_add_device(group, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004454
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004455 iommu_group_put(group);
4456 return ret;
4457}
4458
4459static void intel_iommu_remove_device(struct device *dev)
4460{
4461 iommu_group_remove_device(dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004462}
4463
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004464static struct iommu_ops intel_iommu_ops = {
4465 .domain_init = intel_iommu_domain_init,
4466 .domain_destroy = intel_iommu_domain_destroy,
4467 .attach_dev = intel_iommu_attach_device,
4468 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004469 .map = intel_iommu_map,
4470 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004471 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004472 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004473 .add_device = intel_iommu_add_device,
4474 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004475 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004476};
David Woodhouse9af88142009-02-13 23:18:03 +00004477
Daniel Vetter94526182013-01-20 23:50:13 +01004478static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4479{
4480 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4481 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4482 dmar_map_gfx = 0;
4483}
4484
4485DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4486DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4487DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4488DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4489DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4490DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4491DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4492
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004493static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004494{
4495 /*
4496 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004497 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004498 */
4499 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4500 rwbf_quirk = 1;
4501}
4502
4503DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004504DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4505DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4506DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4507DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4508DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4509DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004510
Adam Jacksoneecfd572010-08-25 21:17:34 +01004511#define GGC 0x52
4512#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4513#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4514#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4515#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4516#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4517#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4518#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4519#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4520
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004521static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004522{
4523 unsigned short ggc;
4524
Adam Jacksoneecfd572010-08-25 21:17:34 +01004525 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004526 return;
4527
Adam Jacksoneecfd572010-08-25 21:17:34 +01004528 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004529 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4530 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004531 } else if (dmar_map_gfx) {
4532 /* we have to ensure the gfx device is idle before we flush */
4533 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4534 intel_iommu_strict = 1;
4535 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004536}
4537DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4538DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4539DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4540DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4541
David Woodhousee0fc7e02009-09-30 09:12:17 -07004542/* On Tylersburg chipsets, some BIOSes have been known to enable the
4543 ISOCH DMAR unit for the Azalia sound device, but not give it any
4544 TLB entries, which causes it to deadlock. Check for that. We do
4545 this in a function called from init_dmars(), instead of in a PCI
4546 quirk, because we don't want to print the obnoxious "BIOS broken"
4547 message if VT-d is actually disabled.
4548*/
4549static void __init check_tylersburg_isoch(void)
4550{
4551 struct pci_dev *pdev;
4552 uint32_t vtisochctrl;
4553
4554 /* If there's no Azalia in the system anyway, forget it. */
4555 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4556 if (!pdev)
4557 return;
4558 pci_dev_put(pdev);
4559
4560 /* System Management Registers. Might be hidden, in which case
4561 we can't do the sanity check. But that's OK, because the
4562 known-broken BIOSes _don't_ actually hide it, so far. */
4563 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4564 if (!pdev)
4565 return;
4566
4567 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4568 pci_dev_put(pdev);
4569 return;
4570 }
4571
4572 pci_dev_put(pdev);
4573
4574 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4575 if (vtisochctrl & 1)
4576 return;
4577
4578 /* Drop all bits other than the number of TLB entries */
4579 vtisochctrl &= 0x1c;
4580
4581 /* If we have the recommended number of TLB entries (16), fine. */
4582 if (vtisochctrl == 0x10)
4583 return;
4584
4585 /* Zero TLB entries? You get to ride the short bus to school. */
4586 if (!vtisochctrl) {
4587 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4588 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4589 dmi_get_system_info(DMI_BIOS_VENDOR),
4590 dmi_get_system_info(DMI_BIOS_VERSION),
4591 dmi_get_system_info(DMI_PRODUCT_VERSION));
4592 iommu_identity_mapping |= IDENTMAP_AZALIA;
4593 return;
4594 }
4595
4596 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4597 vtisochctrl);
4598}