blob: 67b114e784bc74bcbfd7928bb6f6e3ba9f9a85e9 [file] [log] [blame]
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001/*
2 * Copyright (c) 2006, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
mark gross98bcef52008-02-23 15:23:35 -080017 * Copyright (C) 2006-2008 Intel Corporation
18 * Author: Ashok Raj <ashok.raj@intel.com>
19 * Author: Shaohua Li <shaohua.li@intel.com>
20 * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Fenghua Yu5b6985c2008-10-16 18:02:32 -070021 * Author: Fenghua Yu <fenghua.yu@intel.com>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070022 */
23
24#include <linux/init.h>
25#include <linux/bitmap.h>
mark gross5e0d2a62008-03-04 15:22:08 -080026#include <linux/debugfs.h>
Paul Gortmaker54485c32011-10-29 10:26:25 -040027#include <linux/export.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070028#include <linux/slab.h>
29#include <linux/irq.h>
30#include <linux/interrupt.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070031#include <linux/spinlock.h>
32#include <linux/pci.h>
33#include <linux/dmar.h>
34#include <linux/dma-mapping.h>
35#include <linux/mempool.h>
mark gross5e0d2a62008-03-04 15:22:08 -080036#include <linux/timer.h>
Kay, Allen M38717942008-09-09 18:37:29 +030037#include <linux/iova.h>
Joerg Roedel5d450802008-12-03 14:52:32 +010038#include <linux/iommu.h>
Kay, Allen M38717942008-09-09 18:37:29 +030039#include <linux/intel-iommu.h>
Rafael J. Wysocki134fac32011-03-23 22:16:14 +010040#include <linux/syscore_ops.h>
Shane Wang69575d32009-09-01 18:25:07 -070041#include <linux/tboot.h>
Stephen Rothwelladb2fe02009-08-31 15:24:23 +100042#include <linux/dmi.h>
Joerg Roedel5cdede22011-04-04 15:55:18 +020043#include <linux/pci-ats.h>
Tejun Heo0ee332c2011-12-08 10:22:09 -080044#include <linux/memblock.h>
Suresh Siddha8a8f4222012-03-30 11:47:08 -070045#include <asm/irq_remapping.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070046#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090047#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070048
Joerg Roedel078e1ee2012-09-26 12:44:43 +020049#include "irq_remapping.h"
Varun Sethi61e015a2013-04-23 10:05:24 +053050#include "pci.h"
Joerg Roedel078e1ee2012-09-26 12:44:43 +020051
Fenghua Yu5b6985c2008-10-16 18:02:32 -070052#define ROOT_SIZE VTD_PAGE_SIZE
53#define CONTEXT_SIZE VTD_PAGE_SIZE
54
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070055#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
56#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070057#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070058
59#define IOAPIC_RANGE_START (0xfee00000)
60#define IOAPIC_RANGE_END (0xfeefffff)
61#define IOVA_START_ADDR (0x1000)
62
63#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
64
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070065#define MAX_AGAW_WIDTH 64
Jiang Liu5c645b32014-01-06 14:18:12 +080066#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070067
David Woodhouse2ebe3152009-09-19 07:34:04 -070068#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
69#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
70
71/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
72 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
73#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
74 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
75#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070076
Mark McLoughlinf27be032008-11-20 15:49:43 +000077#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070078#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070079#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080080
Andrew Mortondf08cdc2010-09-22 13:05:11 -070081/* page table handling */
82#define LEVEL_STRIDE (9)
83#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
84
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +020085/*
86 * This bitmap is used to advertise the page sizes our hardware support
87 * to the IOMMU core, which will then use this information to split
88 * physically contiguous memory regions it is mapping into page sizes
89 * that we support.
90 *
91 * Traditionally the IOMMU core just handed us the mappings directly,
92 * after making sure the size is an order of a 4KiB page and that the
93 * mapping has natural alignment.
94 *
95 * To retain this behavior, we currently advertise that we support
96 * all page sizes that are an order of 4KiB.
97 *
98 * If at some point we'd like to utilize the IOMMU core's new behavior,
99 * we could change this to advertise the real page sizes we support.
100 */
101#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
102
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700103static inline int agaw_to_level(int agaw)
104{
105 return agaw + 2;
106}
107
108static inline int agaw_to_width(int agaw)
109{
Jiang Liu5c645b32014-01-06 14:18:12 +0800110 return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700111}
112
113static inline int width_to_agaw(int width)
114{
Jiang Liu5c645b32014-01-06 14:18:12 +0800115 return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700116}
117
118static inline unsigned int level_to_offset_bits(int level)
119{
120 return (level - 1) * LEVEL_STRIDE;
121}
122
123static inline int pfn_level_offset(unsigned long pfn, int level)
124{
125 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
126}
127
128static inline unsigned long level_mask(int level)
129{
130 return -1UL << level_to_offset_bits(level);
131}
132
133static inline unsigned long level_size(int level)
134{
135 return 1UL << level_to_offset_bits(level);
136}
137
138static inline unsigned long align_to_level(unsigned long pfn, int level)
139{
140 return (pfn + level_size(level) - 1) & level_mask(level);
141}
David Woodhousefd18de52009-05-10 23:57:41 +0100142
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100143static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
144{
Jiang Liu5c645b32014-01-06 14:18:12 +0800145 return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100146}
147
David Woodhousedd4e8312009-06-27 16:21:20 +0100148/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
149 are never going to work. */
150static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
151{
152 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
153}
154
155static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
156{
157 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
158}
159static inline unsigned long page_to_dma_pfn(struct page *pg)
160{
161 return mm_to_dma_pfn(page_to_pfn(pg));
162}
163static inline unsigned long virt_to_dma_pfn(void *p)
164{
165 return page_to_dma_pfn(virt_to_page(p));
166}
167
Weidong Hand9630fe2008-12-08 11:06:32 +0800168/* global iommu list, set NULL for ignored DMAR units */
169static struct intel_iommu **g_iommus;
170
David Woodhousee0fc7e02009-09-30 09:12:17 -0700171static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000172static int rwbf_quirk;
173
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000174/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700175 * set to 1 to panic kernel if can't successfully enable VT-d
176 * (used when kernel is launched w/ TXT)
177 */
178static int force_on = 0;
179
180/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000181 * 0: Present
182 * 1-11: Reserved
183 * 12-63: Context Ptr (12 - (haw-1))
184 * 64-127: Reserved
185 */
186struct root_entry {
187 u64 val;
188 u64 rsvd1;
189};
190#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
191static inline bool root_present(struct root_entry *root)
192{
193 return (root->val & 1);
194}
195static inline void set_root_present(struct root_entry *root)
196{
197 root->val |= 1;
198}
199static inline void set_root_value(struct root_entry *root, unsigned long value)
200{
201 root->val |= value & VTD_PAGE_MASK;
202}
203
204static inline struct context_entry *
205get_context_addr_from_root(struct root_entry *root)
206{
207 return (struct context_entry *)
208 (root_present(root)?phys_to_virt(
209 root->val & VTD_PAGE_MASK) :
210 NULL);
211}
212
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000213/*
214 * low 64 bits:
215 * 0: present
216 * 1: fault processing disable
217 * 2-3: translation type
218 * 12-63: address space root
219 * high 64 bits:
220 * 0-2: address width
221 * 3-6: aval
222 * 8-23: domain id
223 */
224struct context_entry {
225 u64 lo;
226 u64 hi;
227};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000228
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000229static inline bool context_present(struct context_entry *context)
230{
231 return (context->lo & 1);
232}
233static inline void context_set_present(struct context_entry *context)
234{
235 context->lo |= 1;
236}
237
238static inline void context_set_fault_enable(struct context_entry *context)
239{
240 context->lo &= (((u64)-1) << 2) | 1;
241}
242
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000243static inline void context_set_translation_type(struct context_entry *context,
244 unsigned long value)
245{
246 context->lo &= (((u64)-1) << 4) | 3;
247 context->lo |= (value & 3) << 2;
248}
249
250static inline void context_set_address_root(struct context_entry *context,
251 unsigned long value)
252{
253 context->lo |= value & VTD_PAGE_MASK;
254}
255
256static inline void context_set_address_width(struct context_entry *context,
257 unsigned long value)
258{
259 context->hi |= value & 7;
260}
261
262static inline void context_set_domain_id(struct context_entry *context,
263 unsigned long value)
264{
265 context->hi |= (value & ((1 << 16) - 1)) << 8;
266}
267
268static inline void context_clear_entry(struct context_entry *context)
269{
270 context->lo = 0;
271 context->hi = 0;
272}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000273
Mark McLoughlin622ba122008-11-20 15:49:46 +0000274/*
275 * 0: readable
276 * 1: writable
277 * 2-6: reserved
278 * 7: super page
Sheng Yang9cf066972009-03-18 15:33:07 +0800279 * 8-10: available
280 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000281 * 12-63: Host physcial address
282 */
283struct dma_pte {
284 u64 val;
285};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000286
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000287static inline void dma_clear_pte(struct dma_pte *pte)
288{
289 pte->val = 0;
290}
291
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000292static inline u64 dma_pte_addr(struct dma_pte *pte)
293{
David Woodhousec85994e2009-07-01 19:21:24 +0100294#ifdef CONFIG_64BIT
295 return pte->val & VTD_PAGE_MASK;
296#else
297 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100298 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100299#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000300}
301
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000302static inline bool dma_pte_present(struct dma_pte *pte)
303{
304 return (pte->val & 3) != 0;
305}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000306
Allen Kay4399c8b2011-10-14 12:32:46 -0700307static inline bool dma_pte_superpage(struct dma_pte *pte)
308{
309 return (pte->val & (1 << 7));
310}
311
David Woodhouse75e6bf92009-07-02 11:21:16 +0100312static inline int first_pte_in_page(struct dma_pte *pte)
313{
314 return !((unsigned long)pte & ~VTD_PAGE_MASK);
315}
316
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700317/*
318 * This domain is a statically identity mapping domain.
319 * 1. This domain creats a static 1:1 mapping to all usable memory.
320 * 2. It maps to each iommu if successful.
321 * 3. Each iommu mapps to this domain if successful.
322 */
David Woodhouse19943b02009-08-04 16:19:20 +0100323static struct dmar_domain *si_domain;
324static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700325
Weidong Han3b5410e2008-12-08 09:17:15 +0800326/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100327#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800328
Weidong Han1ce28fe2008-12-08 16:35:39 +0800329/* domain represents a virtual machine, more than one devices
330 * across iommus may be owned in one domain, e.g. kvm guest.
331 */
332#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
333
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700334/* si_domain contains mulitple devices */
335#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
336
Mike Travis1b198bb2012-03-05 15:05:16 -0800337/* define the limit of IOMMUs supported in each domain */
338#ifdef CONFIG_X86
339# define IOMMU_UNITS_SUPPORTED MAX_IO_APICS
340#else
341# define IOMMU_UNITS_SUPPORTED 64
342#endif
343
Mark McLoughlin99126f72008-11-20 15:49:47 +0000344struct dmar_domain {
345 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700346 int nid; /* node id */
Mike Travis1b198bb2012-03-05 15:05:16 -0800347 DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
348 /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000349
350 struct list_head devices; /* all devices' list */
351 struct iova_domain iovad; /* iova's that belong to this domain */
352
353 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000354 int gaw; /* max guest address width */
355
356 /* adjusted guest address width, 0 is level 2 30-bit */
357 int agaw;
358
Weidong Han3b5410e2008-12-08 09:17:15 +0800359 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800360
361 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800362 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800363 int iommu_count; /* reference count of iommu */
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100364 int iommu_superpage;/* Level of superpages supported:
365 0 == 4KiB (no superpages), 1 == 2MiB,
366 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
Weidong Hanc7151a82008-12-08 22:51:37 +0800367 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800368 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000369};
370
Mark McLoughlina647dac2008-11-20 15:49:48 +0000371/* PCI domain-device relationship */
372struct device_domain_info {
373 struct list_head link; /* link to domain siblings */
374 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100375 int segment; /* PCI domain */
376 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000377 u8 devfn; /* PCI devfn number */
Stefan Assmann45e829e2009-12-03 06:49:24 -0500378 struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800379 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000380 struct dmar_domain *domain; /* pointer to domain */
381};
382
Jiang Liub94e4112014-02-19 14:07:25 +0800383struct dmar_rmrr_unit {
384 struct list_head list; /* list of rmrr units */
385 struct acpi_dmar_header *hdr; /* ACPI header */
386 u64 base_address; /* reserved base address*/
387 u64 end_address; /* reserved end address */
388 struct pci_dev **devices; /* target devices */
389 int devices_cnt; /* target device count */
390};
391
392struct dmar_atsr_unit {
393 struct list_head list; /* list of ATSR units */
394 struct acpi_dmar_header *hdr; /* ACPI header */
395 struct pci_dev **devices; /* target devices */
396 int devices_cnt; /* target device count */
397 u8 include_all:1; /* include all ports */
398};
399
400static LIST_HEAD(dmar_atsr_units);
401static LIST_HEAD(dmar_rmrr_units);
402
403#define for_each_rmrr_units(rmrr) \
404 list_for_each_entry(rmrr, &dmar_rmrr_units, list)
405
mark gross5e0d2a62008-03-04 15:22:08 -0800406static void flush_unmaps_timeout(unsigned long data);
407
Jiang Liub707cb02014-01-06 14:18:26 +0800408static DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
mark gross5e0d2a62008-03-04 15:22:08 -0800409
mark gross80b20dd2008-04-18 13:53:58 -0700410#define HIGH_WATER_MARK 250
411struct deferred_flush_tables {
412 int next;
413 struct iova *iova[HIGH_WATER_MARK];
414 struct dmar_domain *domain[HIGH_WATER_MARK];
415};
416
417static struct deferred_flush_tables *deferred_flush;
418
mark gross5e0d2a62008-03-04 15:22:08 -0800419/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800420static int g_num_of_iommus;
421
422static DEFINE_SPINLOCK(async_umap_flush_lock);
423static LIST_HEAD(unmaps_to_do);
424
425static int timer_on;
426static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800427
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700428static void domain_remove_dev_info(struct dmar_domain *domain);
Jiang Liub94e4112014-02-19 14:07:25 +0800429static void domain_remove_one_dev_info(struct dmar_domain *domain,
430 struct pci_dev *pdev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700431
Suresh Siddhad3f13812011-08-23 17:05:25 -0700432#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800433int dmar_disabled = 0;
434#else
435int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700436#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800437
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200438int intel_iommu_enabled = 0;
439EXPORT_SYMBOL_GPL(intel_iommu_enabled);
440
David Woodhouse2d9e6672010-06-15 10:57:57 +0100441static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700442static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800443static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100444static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700445
David Woodhousec0771df2011-10-14 20:59:46 +0100446int intel_iommu_gfx_mapped;
447EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
448
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700449#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
450static DEFINE_SPINLOCK(device_domain_lock);
451static LIST_HEAD(device_domain_list);
452
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100453static struct iommu_ops intel_iommu_ops;
454
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700455static int __init intel_iommu_setup(char *str)
456{
457 if (!str)
458 return -EINVAL;
459 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800460 if (!strncmp(str, "on", 2)) {
461 dmar_disabled = 0;
462 printk(KERN_INFO "Intel-IOMMU: enabled\n");
463 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700464 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800465 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700466 } else if (!strncmp(str, "igfx_off", 8)) {
467 dmar_map_gfx = 0;
468 printk(KERN_INFO
469 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700470 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800471 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700472 "Intel-IOMMU: Forcing DAC for PCI devices\n");
473 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800474 } else if (!strncmp(str, "strict", 6)) {
475 printk(KERN_INFO
476 "Intel-IOMMU: disable batched IOTLB flush\n");
477 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100478 } else if (!strncmp(str, "sp_off", 6)) {
479 printk(KERN_INFO
480 "Intel-IOMMU: disable supported super page\n");
481 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700482 }
483
484 str += strcspn(str, ",");
485 while (*str == ',')
486 str++;
487 }
488 return 0;
489}
490__setup("intel_iommu=", intel_iommu_setup);
491
492static struct kmem_cache *iommu_domain_cache;
493static struct kmem_cache *iommu_devinfo_cache;
494static struct kmem_cache *iommu_iova_cache;
495
Suresh Siddha4c923d42009-10-02 11:01:24 -0700496static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700497{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700498 struct page *page;
499 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700500
Suresh Siddha4c923d42009-10-02 11:01:24 -0700501 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
502 if (page)
503 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700504 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700505}
506
507static inline void free_pgtable_page(void *vaddr)
508{
509 free_page((unsigned long)vaddr);
510}
511
512static inline void *alloc_domain_mem(void)
513{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900514 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700515}
516
Kay, Allen M38717942008-09-09 18:37:29 +0300517static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700518{
519 kmem_cache_free(iommu_domain_cache, vaddr);
520}
521
522static inline void * alloc_devinfo_mem(void)
523{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900524 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700525}
526
527static inline void free_devinfo_mem(void *vaddr)
528{
529 kmem_cache_free(iommu_devinfo_cache, vaddr);
530}
531
532struct iova *alloc_iova_mem(void)
533{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900534 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700535}
536
537void free_iova_mem(struct iova *iova)
538{
539 kmem_cache_free(iommu_iova_cache, iova);
540}
541
Weidong Han1b573682008-12-08 15:34:06 +0800542
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700543static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800544{
545 unsigned long sagaw;
546 int agaw = -1;
547
548 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700549 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800550 agaw >= 0; agaw--) {
551 if (test_bit(agaw, &sagaw))
552 break;
553 }
554
555 return agaw;
556}
557
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700558/*
559 * Calculate max SAGAW for each iommu.
560 */
561int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
562{
563 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
564}
565
566/*
567 * calculate agaw for each iommu.
568 * "SAGAW" may be different across iommus, use a default agaw, and
569 * get a supported less agaw for iommus that don't support the default agaw.
570 */
571int iommu_calculate_agaw(struct intel_iommu *iommu)
572{
573 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
574}
575
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700576/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800577static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
578{
579 int iommu_id;
580
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700581 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800582 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700583 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800584
Mike Travis1b198bb2012-03-05 15:05:16 -0800585 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800586 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
587 return NULL;
588
589 return g_iommus[iommu_id];
590}
591
Weidong Han8e6040972008-12-08 15:49:06 +0800592static void domain_update_iommu_coherency(struct dmar_domain *domain)
593{
594 int i;
595
Alex Williamson2e12bc22011-11-11 17:26:44 -0700596 i = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
597
598 domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0;
Weidong Han8e6040972008-12-08 15:49:06 +0800599
Mike Travis1b198bb2012-03-05 15:05:16 -0800600 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e6040972008-12-08 15:49:06 +0800601 if (!ecap_coherent(g_iommus[i]->ecap)) {
602 domain->iommu_coherency = 0;
603 break;
604 }
Weidong Han8e6040972008-12-08 15:49:06 +0800605 }
606}
607
Sheng Yang58c610b2009-03-18 15:33:05 +0800608static void domain_update_iommu_snooping(struct dmar_domain *domain)
609{
610 int i;
611
612 domain->iommu_snooping = 1;
613
Mike Travis1b198bb2012-03-05 15:05:16 -0800614 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800615 if (!ecap_sc_support(g_iommus[i]->ecap)) {
616 domain->iommu_snooping = 0;
617 break;
618 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800619 }
620}
621
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100622static void domain_update_iommu_superpage(struct dmar_domain *domain)
623{
Allen Kay8140a952011-10-14 12:32:17 -0700624 struct dmar_drhd_unit *drhd;
625 struct intel_iommu *iommu = NULL;
626 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100627
628 if (!intel_iommu_superpage) {
629 domain->iommu_superpage = 0;
630 return;
631 }
632
Allen Kay8140a952011-10-14 12:32:17 -0700633 /* set iommu_superpage to the smallest common denominator */
634 for_each_active_iommu(iommu, drhd) {
635 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100636 if (!mask) {
637 break;
638 }
639 }
640 domain->iommu_superpage = fls(mask);
641}
642
Sheng Yang58c610b2009-03-18 15:33:05 +0800643/* Some capabilities may be different across iommus */
644static void domain_update_iommu_cap(struct dmar_domain *domain)
645{
646 domain_update_iommu_coherency(domain);
647 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100648 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800649}
650
David Woodhouse276dbf992009-04-04 01:45:37 +0100651static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800652{
653 struct dmar_drhd_unit *drhd = NULL;
654 int i;
655
Jiang Liu7c919772014-01-06 14:18:18 +0800656 for_each_active_drhd_unit(drhd) {
David Woodhouse276dbf992009-04-04 01:45:37 +0100657 if (segment != drhd->segment)
658 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800659
David Woodhouse924b6232009-04-04 00:39:25 +0100660 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000661 if (drhd->devices[i] &&
662 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800663 drhd->devices[i]->devfn == devfn)
664 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700665 if (drhd->devices[i] &&
666 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100667 drhd->devices[i]->subordinate->number <= bus &&
Yinghai Lub918c622012-05-17 18:51:11 -0700668 drhd->devices[i]->subordinate->busn_res.end >= bus)
David Woodhouse924b6232009-04-04 00:39:25 +0100669 return drhd->iommu;
670 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800671
672 if (drhd->include_all)
673 return drhd->iommu;
674 }
675
676 return NULL;
677}
678
Weidong Han5331fe62008-12-08 23:00:00 +0800679static void domain_flush_cache(struct dmar_domain *domain,
680 void *addr, int size)
681{
682 if (!domain->iommu_coherency)
683 clflush_cache_range(addr, size);
684}
685
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700686/* Gets context entry for a given bus and devfn */
687static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
688 u8 bus, u8 devfn)
689{
690 struct root_entry *root;
691 struct context_entry *context;
692 unsigned long phy_addr;
693 unsigned long flags;
694
695 spin_lock_irqsave(&iommu->lock, flags);
696 root = &iommu->root_entry[bus];
697 context = get_context_addr_from_root(root);
698 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700699 context = (struct context_entry *)
700 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700701 if (!context) {
702 spin_unlock_irqrestore(&iommu->lock, flags);
703 return NULL;
704 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700705 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700706 phy_addr = virt_to_phys((void *)context);
707 set_root_value(root, phy_addr);
708 set_root_present(root);
709 __iommu_flush_cache(iommu, root, sizeof(*root));
710 }
711 spin_unlock_irqrestore(&iommu->lock, flags);
712 return &context[devfn];
713}
714
715static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
716{
717 struct root_entry *root;
718 struct context_entry *context;
719 int ret;
720 unsigned long flags;
721
722 spin_lock_irqsave(&iommu->lock, flags);
723 root = &iommu->root_entry[bus];
724 context = get_context_addr_from_root(root);
725 if (!context) {
726 ret = 0;
727 goto out;
728 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000729 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700730out:
731 spin_unlock_irqrestore(&iommu->lock, flags);
732 return ret;
733}
734
735static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
736{
737 struct root_entry *root;
738 struct context_entry *context;
739 unsigned long flags;
740
741 spin_lock_irqsave(&iommu->lock, flags);
742 root = &iommu->root_entry[bus];
743 context = get_context_addr_from_root(root);
744 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000745 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700746 __iommu_flush_cache(iommu, &context[devfn], \
747 sizeof(*context));
748 }
749 spin_unlock_irqrestore(&iommu->lock, flags);
750}
751
752static void free_context_table(struct intel_iommu *iommu)
753{
754 struct root_entry *root;
755 int i;
756 unsigned long flags;
757 struct context_entry *context;
758
759 spin_lock_irqsave(&iommu->lock, flags);
760 if (!iommu->root_entry) {
761 goto out;
762 }
763 for (i = 0; i < ROOT_ENTRY_NR; i++) {
764 root = &iommu->root_entry[i];
765 context = get_context_addr_from_root(root);
766 if (context)
767 free_pgtable_page(context);
768 }
769 free_pgtable_page(iommu->root_entry);
770 iommu->root_entry = NULL;
771out:
772 spin_unlock_irqrestore(&iommu->lock, flags);
773}
774
David Woodhouseb026fd22009-06-28 10:37:25 +0100775static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
Allen Kay4399c8b2011-10-14 12:32:46 -0700776 unsigned long pfn, int target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700777{
David Woodhouseb026fd22009-06-28 10:37:25 +0100778 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700779 struct dma_pte *parent, *pte = NULL;
780 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700781 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700782
783 BUG_ON(!domain->pgd);
Julian Stecklinaf9423602013-10-09 10:03:52 +0200784
785 if (addr_width < BITS_PER_LONG && pfn >> addr_width)
786 /* Address beyond IOMMU's addressing capabilities. */
787 return NULL;
788
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700789 parent = domain->pgd;
790
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700791 while (level > 0) {
792 void *tmp_page;
793
David Woodhouseb026fd22009-06-28 10:37:25 +0100794 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700795 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700796 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100797 break;
798 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700799 break;
800
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000801 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100802 uint64_t pteval;
803
Suresh Siddha4c923d42009-10-02 11:01:24 -0700804 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700805
David Woodhouse206a73c12009-07-01 19:30:28 +0100806 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700807 return NULL;
David Woodhouse206a73c12009-07-01 19:30:28 +0100808
David Woodhousec85994e2009-07-01 19:21:24 +0100809 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400810 pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
David Woodhousec85994e2009-07-01 19:21:24 +0100811 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
812 /* Someone else set it while we were thinking; use theirs. */
813 free_pgtable_page(tmp_page);
814 } else {
815 dma_pte_addr(pte);
816 domain_flush_cache(domain, pte, sizeof(*pte));
817 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700818 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000819 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700820 level--;
821 }
822
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700823 return pte;
824}
825
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100826
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700827/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100828static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
829 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100830 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700831{
832 struct dma_pte *parent, *pte = NULL;
833 int total = agaw_to_level(domain->agaw);
834 int offset;
835
836 parent = domain->pgd;
837 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100838 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700839 pte = &parent[offset];
840 if (level == total)
841 return pte;
842
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100843 if (!dma_pte_present(pte)) {
844 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700845 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100846 }
847
848 if (pte->val & DMA_PTE_LARGE_PAGE) {
849 *large_page = total;
850 return pte;
851 }
852
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000853 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700854 total--;
855 }
856 return NULL;
857}
858
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700859/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700860static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100861 unsigned long start_pfn,
862 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700863{
David Woodhouse04b18e62009-06-27 19:15:01 +0100864 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100865 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100866 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700867
David Woodhouse04b18e62009-06-27 19:15:01 +0100868 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100869 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700870 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100871
David Woodhouse04b18e62009-06-27 19:15:01 +0100872 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700873 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100874 large_page = 1;
875 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100876 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100877 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100878 continue;
879 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100880 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100881 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100882 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100883 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100884 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
885
David Woodhouse310a5ab2009-06-28 18:52:20 +0100886 domain_flush_cache(domain, first_pte,
887 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700888
889 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700890
Jiang Liu5c645b32014-01-06 14:18:12 +0800891 return min_t(int, (large_page - 1) * 9, MAX_AGAW_PFN_WIDTH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700892}
893
Alex Williamson3269ee02013-06-15 10:27:19 -0600894static void dma_pte_free_level(struct dmar_domain *domain, int level,
895 struct dma_pte *pte, unsigned long pfn,
896 unsigned long start_pfn, unsigned long last_pfn)
897{
898 pfn = max(start_pfn, pfn);
899 pte = &pte[pfn_level_offset(pfn, level)];
900
901 do {
902 unsigned long level_pfn;
903 struct dma_pte *level_pte;
904
905 if (!dma_pte_present(pte) || dma_pte_superpage(pte))
906 goto next;
907
908 level_pfn = pfn & level_mask(level - 1);
909 level_pte = phys_to_virt(dma_pte_addr(pte));
910
911 if (level > 2)
912 dma_pte_free_level(domain, level - 1, level_pte,
913 level_pfn, start_pfn, last_pfn);
914
915 /* If range covers entire pagetable, free it */
916 if (!(start_pfn > level_pfn ||
Alex Williamson08336fd2014-01-21 15:48:18 -0800917 last_pfn < level_pfn + level_size(level) - 1)) {
Alex Williamson3269ee02013-06-15 10:27:19 -0600918 dma_clear_pte(pte);
919 domain_flush_cache(domain, pte, sizeof(*pte));
920 free_pgtable_page(level_pte);
921 }
922next:
923 pfn += level_size(level);
924 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
925}
926
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700927/* free page table pages. last level pte should already be cleared */
928static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100929 unsigned long start_pfn,
930 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700931{
David Woodhouse6660c632009-06-27 22:41:00 +0100932 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700933
David Woodhouse6660c632009-06-27 22:41:00 +0100934 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
935 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700936 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700937
David Woodhousef3a0a522009-06-30 03:40:07 +0100938 /* We don't need lock here; nobody else touches the iova range */
Alex Williamson3269ee02013-06-15 10:27:19 -0600939 dma_pte_free_level(domain, agaw_to_level(domain->agaw),
940 domain->pgd, 0, start_pfn, last_pfn);
David Woodhouse6660c632009-06-27 22:41:00 +0100941
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700942 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100943 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700944 free_pgtable_page(domain->pgd);
945 domain->pgd = NULL;
946 }
947}
948
949/* iommu handling */
950static int iommu_alloc_root_entry(struct intel_iommu *iommu)
951{
952 struct root_entry *root;
953 unsigned long flags;
954
Suresh Siddha4c923d42009-10-02 11:01:24 -0700955 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700956 if (!root)
957 return -ENOMEM;
958
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700959 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700960
961 spin_lock_irqsave(&iommu->lock, flags);
962 iommu->root_entry = root;
963 spin_unlock_irqrestore(&iommu->lock, flags);
964
965 return 0;
966}
967
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700968static void iommu_set_root_entry(struct intel_iommu *iommu)
969{
970 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100971 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700972 unsigned long flag;
973
974 addr = iommu->root_entry;
975
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200976 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700977 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
978
David Woodhousec416daa2009-05-10 20:30:58 +0100979 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700980
981 /* Make sure hardware complete it */
982 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100983 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700984
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200985 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700986}
987
988static void iommu_flush_write_buffer(struct intel_iommu *iommu)
989{
990 u32 val;
991 unsigned long flag;
992
David Woodhouse9af88142009-02-13 23:18:03 +0000993 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700994 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700995
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200996 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +0100997 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700998
999 /* Make sure hardware complete it */
1000 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001001 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001002
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001003 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001004}
1005
1006/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001007static void __iommu_flush_context(struct intel_iommu *iommu,
1008 u16 did, u16 source_id, u8 function_mask,
1009 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001010{
1011 u64 val = 0;
1012 unsigned long flag;
1013
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001014 switch (type) {
1015 case DMA_CCMD_GLOBAL_INVL:
1016 val = DMA_CCMD_GLOBAL_INVL;
1017 break;
1018 case DMA_CCMD_DOMAIN_INVL:
1019 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1020 break;
1021 case DMA_CCMD_DEVICE_INVL:
1022 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1023 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1024 break;
1025 default:
1026 BUG();
1027 }
1028 val |= DMA_CCMD_ICC;
1029
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001030 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001031 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1032
1033 /* Make sure hardware complete it */
1034 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1035 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1036
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001037 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001038}
1039
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001040/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001041static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1042 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001043{
1044 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1045 u64 val = 0, val_iva = 0;
1046 unsigned long flag;
1047
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001048 switch (type) {
1049 case DMA_TLB_GLOBAL_FLUSH:
1050 /* global flush doesn't need set IVA_REG */
1051 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1052 break;
1053 case DMA_TLB_DSI_FLUSH:
1054 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1055 break;
1056 case DMA_TLB_PSI_FLUSH:
1057 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1058 /* Note: always flush non-leaf currently */
1059 val_iva = size_order | addr;
1060 break;
1061 default:
1062 BUG();
1063 }
1064 /* Note: set drain read/write */
1065#if 0
1066 /*
1067 * This is probably to be super secure.. Looks like we can
1068 * ignore it without any impact.
1069 */
1070 if (cap_read_drain(iommu->cap))
1071 val |= DMA_TLB_READ_DRAIN;
1072#endif
1073 if (cap_write_drain(iommu->cap))
1074 val |= DMA_TLB_WRITE_DRAIN;
1075
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001076 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001077 /* Note: Only uses first TLB reg currently */
1078 if (val_iva)
1079 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1080 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1081
1082 /* Make sure hardware complete it */
1083 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1084 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1085
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001086 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001087
1088 /* check IOTLB invalidation granularity */
1089 if (DMA_TLB_IAIG(val) == 0)
1090 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1091 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1092 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001093 (unsigned long long)DMA_TLB_IIRG(type),
1094 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001095}
1096
Yu Zhao93a23a72009-05-18 13:51:37 +08001097static struct device_domain_info *iommu_support_dev_iotlb(
1098 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001099{
Yu Zhao93a23a72009-05-18 13:51:37 +08001100 int found = 0;
1101 unsigned long flags;
1102 struct device_domain_info *info;
1103 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1104
1105 if (!ecap_dev_iotlb_support(iommu->ecap))
1106 return NULL;
1107
1108 if (!iommu->qi)
1109 return NULL;
1110
1111 spin_lock_irqsave(&device_domain_lock, flags);
1112 list_for_each_entry(info, &domain->devices, link)
1113 if (info->bus == bus && info->devfn == devfn) {
1114 found = 1;
1115 break;
1116 }
1117 spin_unlock_irqrestore(&device_domain_lock, flags);
1118
1119 if (!found || !info->dev)
1120 return NULL;
1121
1122 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1123 return NULL;
1124
1125 if (!dmar_find_matched_atsr_unit(info->dev))
1126 return NULL;
1127
1128 info->iommu = iommu;
1129
1130 return info;
1131}
1132
1133static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1134{
1135 if (!info)
1136 return;
1137
1138 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1139}
1140
1141static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1142{
1143 if (!info->dev || !pci_ats_enabled(info->dev))
1144 return;
1145
1146 pci_disable_ats(info->dev);
1147}
1148
1149static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1150 u64 addr, unsigned mask)
1151{
1152 u16 sid, qdep;
1153 unsigned long flags;
1154 struct device_domain_info *info;
1155
1156 spin_lock_irqsave(&device_domain_lock, flags);
1157 list_for_each_entry(info, &domain->devices, link) {
1158 if (!info->dev || !pci_ats_enabled(info->dev))
1159 continue;
1160
1161 sid = info->bus << 8 | info->devfn;
1162 qdep = pci_ats_queue_depth(info->dev);
1163 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1164 }
1165 spin_unlock_irqrestore(&device_domain_lock, flags);
1166}
1167
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001168static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001169 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001170{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001171 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001172 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001173
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001174 BUG_ON(pages == 0);
1175
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001176 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001177 * Fallback to domain selective flush if no PSI support or the size is
1178 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001179 * PSI requires page size to be 2 ^ x, and the base address is naturally
1180 * aligned to the size
1181 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001182 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1183 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001184 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001185 else
1186 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1187 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001188
1189 /*
Nadav Amit82653632010-04-01 13:24:40 +03001190 * In caching mode, changes of pages from non-present to present require
1191 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001192 */
Nadav Amit82653632010-04-01 13:24:40 +03001193 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001194 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001195}
1196
mark grossf8bab732008-02-08 04:18:38 -08001197static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1198{
1199 u32 pmen;
1200 unsigned long flags;
1201
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001202 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001203 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1204 pmen &= ~DMA_PMEN_EPM;
1205 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1206
1207 /* wait for the protected region status bit to clear */
1208 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1209 readl, !(pmen & DMA_PMEN_PRS), pmen);
1210
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001211 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001212}
1213
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001214static int iommu_enable_translation(struct intel_iommu *iommu)
1215{
1216 u32 sts;
1217 unsigned long flags;
1218
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001219 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001220 iommu->gcmd |= DMA_GCMD_TE;
1221 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001222
1223 /* Make sure hardware complete it */
1224 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001225 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001226
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001227 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001228 return 0;
1229}
1230
1231static int iommu_disable_translation(struct intel_iommu *iommu)
1232{
1233 u32 sts;
1234 unsigned long flag;
1235
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001236 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001237 iommu->gcmd &= ~DMA_GCMD_TE;
1238 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1239
1240 /* Make sure hardware complete it */
1241 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001242 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001243
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001244 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001245 return 0;
1246}
1247
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001248
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001249static int iommu_init_domains(struct intel_iommu *iommu)
1250{
1251 unsigned long ndomains;
1252 unsigned long nlongs;
1253
1254 ndomains = cap_ndoms(iommu->cap);
Jiang Liu852bdb02014-01-06 14:18:11 +08001255 pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
1256 iommu->seq_id, ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001257 nlongs = BITS_TO_LONGS(ndomains);
1258
Donald Dutile94a91b52009-08-20 16:51:34 -04001259 spin_lock_init(&iommu->lock);
1260
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001261 /* TBD: there might be 64K domains,
1262 * consider other allocation for future chip
1263 */
1264 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1265 if (!iommu->domain_ids) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001266 pr_err("IOMMU%d: allocating domain id array failed\n",
1267 iommu->seq_id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001268 return -ENOMEM;
1269 }
1270 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1271 GFP_KERNEL);
1272 if (!iommu->domains) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001273 pr_err("IOMMU%d: allocating domain array failed\n",
1274 iommu->seq_id);
1275 kfree(iommu->domain_ids);
1276 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001277 return -ENOMEM;
1278 }
1279
1280 /*
1281 * if Caching mode is set, then invalid translations are tagged
1282 * with domainid 0. Hence we need to pre-allocate it.
1283 */
1284 if (cap_caching_mode(iommu->cap))
1285 set_bit(0, iommu->domain_ids);
1286 return 0;
1287}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001288
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001289
1290static void domain_exit(struct dmar_domain *domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001291static void vm_domain_exit(struct dmar_domain *domain);
Suresh Siddhae61d98d2008-07-10 11:16:35 -07001292
Jiang Liua868e6b2014-01-06 14:18:20 +08001293static void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001294{
1295 struct dmar_domain *domain;
Jiang Liu5ced12a2014-01-06 14:18:22 +08001296 int i, count;
Weidong Hanc7151a82008-12-08 22:51:37 +08001297 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001298
Donald Dutile94a91b52009-08-20 16:51:34 -04001299 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001300 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001301 domain = iommu->domains[i];
1302 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001303
Donald Dutile94a91b52009-08-20 16:51:34 -04001304 spin_lock_irqsave(&domain->iommu_lock, flags);
Jiang Liu5ced12a2014-01-06 14:18:22 +08001305 count = --domain->iommu_count;
1306 spin_unlock_irqrestore(&domain->iommu_lock, flags);
1307 if (count == 0) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001308 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
1309 vm_domain_exit(domain);
1310 else
1311 domain_exit(domain);
1312 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08001313 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001314 }
1315
1316 if (iommu->gcmd & DMA_GCMD_TE)
1317 iommu_disable_translation(iommu);
1318
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001319 kfree(iommu->domains);
1320 kfree(iommu->domain_ids);
Jiang Liua868e6b2014-01-06 14:18:20 +08001321 iommu->domains = NULL;
1322 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001323
Weidong Hand9630fe2008-12-08 11:06:32 +08001324 g_iommus[iommu->seq_id] = NULL;
1325
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001326 /* free context mapping */
1327 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001328}
1329
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001330static struct dmar_domain *alloc_domain(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001331{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001332 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001333
1334 domain = alloc_domain_mem();
1335 if (!domain)
1336 return NULL;
1337
Suresh Siddha4c923d42009-10-02 11:01:24 -07001338 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08001339 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001340 domain->flags = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001341
1342 return domain;
1343}
1344
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001345static int iommu_attach_domain(struct dmar_domain *domain,
1346 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001347{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001348 int num;
1349 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001350 unsigned long flags;
1351
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001352 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001353
1354 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001355
1356 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1357 if (num >= ndomains) {
1358 spin_unlock_irqrestore(&iommu->lock, flags);
1359 printk(KERN_ERR "IOMMU: no free domain ids\n");
1360 return -ENOMEM;
1361 }
1362
1363 domain->id = num;
1364 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001365 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001366 iommu->domains[num] = domain;
1367 spin_unlock_irqrestore(&iommu->lock, flags);
1368
1369 return 0;
1370}
1371
1372static void iommu_detach_domain(struct dmar_domain *domain,
1373 struct intel_iommu *iommu)
1374{
1375 unsigned long flags;
1376 int num, ndomains;
1377 int found = 0;
1378
1379 spin_lock_irqsave(&iommu->lock, flags);
1380 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001381 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001382 if (iommu->domains[num] == domain) {
1383 found = 1;
1384 break;
1385 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001386 }
1387
1388 if (found) {
1389 clear_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001390 clear_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001391 iommu->domains[num] = NULL;
1392 }
Weidong Han8c11e792008-12-08 15:29:22 +08001393 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001394}
1395
1396static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001397static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001398
Joseph Cihula51a63e62011-03-21 11:04:24 -07001399static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001400{
1401 struct pci_dev *pdev = NULL;
1402 struct iova *iova;
1403 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001404
David Millerf6611972008-02-06 01:36:23 -08001405 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001406
Mark Gross8a443df2008-03-04 14:59:31 -08001407 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1408 &reserved_rbtree_key);
1409
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001410 /* IOAPIC ranges shouldn't be accessed by DMA */
1411 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1412 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001413 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001414 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001415 return -ENODEV;
1416 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001417
1418 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1419 for_each_pci_dev(pdev) {
1420 struct resource *r;
1421
1422 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1423 r = &pdev->resource[i];
1424 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1425 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001426 iova = reserve_iova(&reserved_iova_list,
1427 IOVA_PFN(r->start),
1428 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001429 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001430 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001431 return -ENODEV;
1432 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001433 }
1434 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001435 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001436}
1437
1438static void domain_reserve_special_ranges(struct dmar_domain *domain)
1439{
1440 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1441}
1442
1443static inline int guestwidth_to_adjustwidth(int gaw)
1444{
1445 int agaw;
1446 int r = (gaw - 12) % 9;
1447
1448 if (r == 0)
1449 agaw = gaw;
1450 else
1451 agaw = gaw + 9 - r;
1452 if (agaw > 64)
1453 agaw = 64;
1454 return agaw;
1455}
1456
1457static int domain_init(struct dmar_domain *domain, int guest_width)
1458{
1459 struct intel_iommu *iommu;
1460 int adjust_width, agaw;
1461 unsigned long sagaw;
1462
David Millerf6611972008-02-06 01:36:23 -08001463 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Hanc7151a82008-12-08 22:51:37 +08001464 spin_lock_init(&domain->iommu_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001465
1466 domain_reserve_special_ranges(domain);
1467
1468 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001469 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001470 if (guest_width > cap_mgaw(iommu->cap))
1471 guest_width = cap_mgaw(iommu->cap);
1472 domain->gaw = guest_width;
1473 adjust_width = guestwidth_to_adjustwidth(guest_width);
1474 agaw = width_to_agaw(adjust_width);
1475 sagaw = cap_sagaw(iommu->cap);
1476 if (!test_bit(agaw, &sagaw)) {
1477 /* hardware doesn't support it, choose a bigger one */
1478 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1479 agaw = find_next_bit(&sagaw, 5, agaw);
1480 if (agaw >= 5)
1481 return -ENODEV;
1482 }
1483 domain->agaw = agaw;
1484 INIT_LIST_HEAD(&domain->devices);
1485
Weidong Han8e6040972008-12-08 15:49:06 +08001486 if (ecap_coherent(iommu->ecap))
1487 domain->iommu_coherency = 1;
1488 else
1489 domain->iommu_coherency = 0;
1490
Sheng Yang58c610b2009-03-18 15:33:05 +08001491 if (ecap_sc_support(iommu->ecap))
1492 domain->iommu_snooping = 1;
1493 else
1494 domain->iommu_snooping = 0;
1495
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001496 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Weidong Hanc7151a82008-12-08 22:51:37 +08001497 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001498 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001499
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001500 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001501 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001502 if (!domain->pgd)
1503 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001504 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001505 return 0;
1506}
1507
1508static void domain_exit(struct dmar_domain *domain)
1509{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001510 struct dmar_drhd_unit *drhd;
1511 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001512
1513 /* Domain 0 is reserved, so dont process it */
1514 if (!domain)
1515 return;
1516
Alex Williamson7b668352011-05-24 12:02:41 +01001517 /* Flush any lazy unmaps that may reference this domain */
1518 if (!intel_iommu_strict)
1519 flush_unmaps_timeout(0);
1520
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001521 domain_remove_dev_info(domain);
1522 /* destroy iovas */
1523 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001524
1525 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001526 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001527
1528 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001529 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001530
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001531 for_each_active_iommu(iommu, drhd)
Mike Travis1b198bb2012-03-05 15:05:16 -08001532 if (test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001533 iommu_detach_domain(domain, iommu);
1534
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001535 free_domain_mem(domain);
1536}
1537
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001538static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1539 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001540{
1541 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001542 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001543 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001544 struct dma_pte *pgd;
1545 unsigned long num;
1546 unsigned long ndomains;
1547 int id;
1548 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001549 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001550
1551 pr_debug("Set context mapping for %02x:%02x.%d\n",
1552 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001553
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001554 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001555 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1556 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001557
David Woodhouse276dbf992009-04-04 01:45:37 +01001558 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001559 if (!iommu)
1560 return -ENODEV;
1561
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001562 context = device_to_context_entry(iommu, bus, devfn);
1563 if (!context)
1564 return -ENOMEM;
1565 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001566 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001567 spin_unlock_irqrestore(&iommu->lock, flags);
1568 return 0;
1569 }
1570
Weidong Hanea6606b2008-12-08 23:08:15 +08001571 id = domain->id;
1572 pgd = domain->pgd;
1573
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001574 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1575 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001576 int found = 0;
1577
1578 /* find an available domain id for this device in iommu */
1579 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001580 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001581 if (iommu->domains[num] == domain) {
1582 id = num;
1583 found = 1;
1584 break;
1585 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001586 }
1587
1588 if (found == 0) {
1589 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1590 if (num >= ndomains) {
1591 spin_unlock_irqrestore(&iommu->lock, flags);
1592 printk(KERN_ERR "IOMMU: no free domain ids\n");
1593 return -EFAULT;
1594 }
1595
1596 set_bit(num, iommu->domain_ids);
1597 iommu->domains[num] = domain;
1598 id = num;
1599 }
1600
1601 /* Skip top levels of page tables for
1602 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001603 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001604 */
Chris Wright1672af12009-12-02 12:06:34 -08001605 if (translation != CONTEXT_TT_PASS_THROUGH) {
1606 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1607 pgd = phys_to_virt(dma_pte_addr(pgd));
1608 if (!dma_pte_present(pgd)) {
1609 spin_unlock_irqrestore(&iommu->lock, flags);
1610 return -ENOMEM;
1611 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001612 }
1613 }
1614 }
1615
1616 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001617
Yu Zhao93a23a72009-05-18 13:51:37 +08001618 if (translation != CONTEXT_TT_PASS_THROUGH) {
1619 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1620 translation = info ? CONTEXT_TT_DEV_IOTLB :
1621 CONTEXT_TT_MULTI_LEVEL;
1622 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001623 /*
1624 * In pass through mode, AW must be programmed to indicate the largest
1625 * AGAW value supported by hardware. And ASR is ignored by hardware.
1626 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001627 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001628 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001629 else {
1630 context_set_address_root(context, virt_to_phys(pgd));
1631 context_set_address_width(context, iommu->agaw);
1632 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001633
1634 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001635 context_set_fault_enable(context);
1636 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001637 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001638
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001639 /*
1640 * It's a non-present to present mapping. If hardware doesn't cache
1641 * non-present entry we only need to flush the write-buffer. If the
1642 * _does_ cache non-present entries, then it does so in the special
1643 * domain #0, which we have to flush:
1644 */
1645 if (cap_caching_mode(iommu->cap)) {
1646 iommu->flush.flush_context(iommu, 0,
1647 (((u16)bus) << 8) | devfn,
1648 DMA_CCMD_MASK_NOBIT,
1649 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001650 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001651 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001652 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001653 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001654 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001655 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001656
1657 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001658 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001659 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001660 if (domain->iommu_count == 1)
1661 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001662 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001663 }
1664 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001665 return 0;
1666}
1667
1668static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001669domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1670 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001671{
1672 int ret;
1673 struct pci_dev *tmp, *parent;
1674
David Woodhouse276dbf992009-04-04 01:45:37 +01001675 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001676 pdev->bus->number, pdev->devfn,
1677 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001678 if (ret)
1679 return ret;
1680
1681 /* dependent device mapping */
1682 tmp = pci_find_upstream_pcie_bridge(pdev);
1683 if (!tmp)
1684 return 0;
1685 /* Secondary interface's bus number and devfn 0 */
1686 parent = pdev->bus->self;
1687 while (parent != tmp) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001688 ret = domain_context_mapping_one(domain,
1689 pci_domain_nr(parent->bus),
1690 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001691 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001692 if (ret)
1693 return ret;
1694 parent = parent->bus->self;
1695 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001696 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001697 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001698 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001699 tmp->subordinate->number, 0,
1700 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001701 else /* this is a legacy PCI bridge */
1702 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001703 pci_domain_nr(tmp->bus),
1704 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001705 tmp->devfn,
1706 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001707}
1708
Weidong Han5331fe62008-12-08 23:00:00 +08001709static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001710{
1711 int ret;
1712 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001713 struct intel_iommu *iommu;
1714
David Woodhouse276dbf992009-04-04 01:45:37 +01001715 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1716 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001717 if (!iommu)
1718 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001719
David Woodhouse276dbf992009-04-04 01:45:37 +01001720 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001721 if (!ret)
1722 return ret;
1723 /* dependent device mapping */
1724 tmp = pci_find_upstream_pcie_bridge(pdev);
1725 if (!tmp)
1726 return ret;
1727 /* Secondary interface's bus number and devfn 0 */
1728 parent = pdev->bus->self;
1729 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001730 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001731 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001732 if (!ret)
1733 return ret;
1734 parent = parent->bus->self;
1735 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001736 if (pci_is_pcie(tmp))
David Woodhouse276dbf992009-04-04 01:45:37 +01001737 return device_context_mapped(iommu, tmp->subordinate->number,
1738 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001739 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001740 return device_context_mapped(iommu, tmp->bus->number,
1741 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001742}
1743
Fenghua Yuf5329592009-08-04 15:09:37 -07001744/* Returns a number of VTD pages, but aligned to MM page size */
1745static inline unsigned long aligned_nrpages(unsigned long host_addr,
1746 size_t size)
1747{
1748 host_addr &= ~PAGE_MASK;
1749 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1750}
1751
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001752/* Return largest possible superpage level for a given mapping */
1753static inline int hardware_largepage_caps(struct dmar_domain *domain,
1754 unsigned long iov_pfn,
1755 unsigned long phy_pfn,
1756 unsigned long pages)
1757{
1758 int support, level = 1;
1759 unsigned long pfnmerge;
1760
1761 support = domain->iommu_superpage;
1762
1763 /* To use a large page, the virtual *and* physical addresses
1764 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1765 of them will mean we have to use smaller pages. So just
1766 merge them and check both at once. */
1767 pfnmerge = iov_pfn | phy_pfn;
1768
1769 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1770 pages >>= VTD_STRIDE_SHIFT;
1771 if (!pages)
1772 break;
1773 pfnmerge >>= VTD_STRIDE_SHIFT;
1774 level++;
1775 support--;
1776 }
1777 return level;
1778}
1779
David Woodhouse9051aa02009-06-29 12:30:54 +01001780static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1781 struct scatterlist *sg, unsigned long phys_pfn,
1782 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001783{
1784 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001785 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001786 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001787 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001788 unsigned int largepage_lvl = 0;
1789 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001790
1791 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1792
1793 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1794 return -EINVAL;
1795
1796 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1797
David Woodhouse9051aa02009-06-29 12:30:54 +01001798 if (sg)
1799 sg_res = 0;
1800 else {
1801 sg_res = nr_pages + 1;
1802 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1803 }
1804
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001805 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001806 uint64_t tmp;
1807
David Woodhousee1605492009-06-29 11:17:38 +01001808 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001809 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001810 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1811 sg->dma_length = sg->length;
1812 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001813 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001814 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001815
David Woodhousee1605492009-06-29 11:17:38 +01001816 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001817 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1818
1819 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001820 if (!pte)
1821 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001822 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001823 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001824 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001825 /* Ensure that old small page tables are removed to make room
1826 for superpage, if they exist. */
1827 dma_pte_clear_range(domain, iov_pfn,
1828 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1829 dma_pte_free_pagetable(domain, iov_pfn,
1830 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1831 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001832 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001833 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001834
David Woodhousee1605492009-06-29 11:17:38 +01001835 }
1836 /* We don't need lock here, nobody else
1837 * touches the iova range
1838 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001839 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001840 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001841 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001842 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1843 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001844 if (dumps) {
1845 dumps--;
1846 debug_dma_dump_mappings(NULL);
1847 }
1848 WARN_ON(1);
1849 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001850
1851 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1852
1853 BUG_ON(nr_pages < lvl_pages);
1854 BUG_ON(sg_res < lvl_pages);
1855
1856 nr_pages -= lvl_pages;
1857 iov_pfn += lvl_pages;
1858 phys_pfn += lvl_pages;
1859 pteval += lvl_pages * VTD_PAGE_SIZE;
1860 sg_res -= lvl_pages;
1861
1862 /* If the next PTE would be the first in a new page, then we
1863 need to flush the cache on the entries we've just written.
1864 And then we'll need to recalculate 'pte', so clear it and
1865 let it get set again in the if (!pte) block above.
1866
1867 If we're done (!nr_pages) we need to flush the cache too.
1868
1869 Also if we've been setting superpages, we may need to
1870 recalculate 'pte' and switch back to smaller pages for the
1871 end of the mapping, if the trailing size is not enough to
1872 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001873 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001874 if (!nr_pages || first_pte_in_page(pte) ||
1875 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001876 domain_flush_cache(domain, first_pte,
1877 (void *)pte - (void *)first_pte);
1878 pte = NULL;
1879 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001880
1881 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001882 sg = sg_next(sg);
1883 }
1884 return 0;
1885}
1886
David Woodhouse9051aa02009-06-29 12:30:54 +01001887static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1888 struct scatterlist *sg, unsigned long nr_pages,
1889 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001890{
David Woodhouse9051aa02009-06-29 12:30:54 +01001891 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1892}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001893
David Woodhouse9051aa02009-06-29 12:30:54 +01001894static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1895 unsigned long phys_pfn, unsigned long nr_pages,
1896 int prot)
1897{
1898 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001899}
1900
Weidong Hanc7151a82008-12-08 22:51:37 +08001901static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001902{
Weidong Hanc7151a82008-12-08 22:51:37 +08001903 if (!iommu)
1904 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001905
1906 clear_context_table(iommu, bus, devfn);
1907 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001908 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001909 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001910}
1911
David Woodhouse109b9b02012-05-25 17:43:02 +01001912static inline void unlink_domain_info(struct device_domain_info *info)
1913{
1914 assert_spin_locked(&device_domain_lock);
1915 list_del(&info->link);
1916 list_del(&info->global);
1917 if (info->dev)
1918 info->dev->dev.archdata.iommu = NULL;
1919}
1920
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001921static void domain_remove_dev_info(struct dmar_domain *domain)
1922{
1923 struct device_domain_info *info;
1924 unsigned long flags;
Weidong Hanc7151a82008-12-08 22:51:37 +08001925 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001926
1927 spin_lock_irqsave(&device_domain_lock, flags);
1928 while (!list_empty(&domain->devices)) {
1929 info = list_entry(domain->devices.next,
1930 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01001931 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001932 spin_unlock_irqrestore(&device_domain_lock, flags);
1933
Yu Zhao93a23a72009-05-18 13:51:37 +08001934 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01001935 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001936 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001937 free_devinfo_mem(info);
1938
1939 spin_lock_irqsave(&device_domain_lock, flags);
1940 }
1941 spin_unlock_irqrestore(&device_domain_lock, flags);
1942}
1943
1944/*
1945 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001946 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001947 */
Kay, Allen M38717942008-09-09 18:37:29 +03001948static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001949find_domain(struct pci_dev *pdev)
1950{
1951 struct device_domain_info *info;
1952
1953 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001954 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001955 if (info)
1956 return info->domain;
1957 return NULL;
1958}
1959
Jiang Liu745f2582014-02-19 14:07:26 +08001960static inline struct dmar_domain *
1961dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
1962{
1963 struct device_domain_info *info;
1964
1965 list_for_each_entry(info, &device_domain_list, global)
1966 if (info->segment == segment && info->bus == bus &&
1967 info->devfn == devfn)
1968 return info->domain;
1969
1970 return NULL;
1971}
1972
1973static int dmar_insert_dev_info(int segment, int bus, int devfn,
1974 struct pci_dev *dev, struct dmar_domain **domp)
1975{
1976 struct dmar_domain *found, *domain = *domp;
1977 struct device_domain_info *info;
1978 unsigned long flags;
1979
1980 info = alloc_devinfo_mem();
1981 if (!info)
1982 return -ENOMEM;
1983
1984 info->segment = segment;
1985 info->bus = bus;
1986 info->devfn = devfn;
1987 info->dev = dev;
1988 info->domain = domain;
1989 if (!dev)
1990 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
1991
1992 spin_lock_irqsave(&device_domain_lock, flags);
1993 if (dev)
1994 found = find_domain(dev);
1995 else
1996 found = dmar_search_domain_by_dev_info(segment, bus, devfn);
1997 if (found) {
1998 spin_unlock_irqrestore(&device_domain_lock, flags);
1999 free_devinfo_mem(info);
2000 if (found != domain) {
2001 domain_exit(domain);
2002 *domp = found;
2003 }
2004 } else {
2005 list_add(&info->link, &domain->devices);
2006 list_add(&info->global, &device_domain_list);
2007 if (dev)
2008 dev->dev.archdata.iommu = info;
2009 spin_unlock_irqrestore(&device_domain_lock, flags);
2010 }
2011
2012 return 0;
2013}
2014
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002015/* domain is initialized */
2016static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
2017{
Jiang Liu745f2582014-02-19 14:07:26 +08002018 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002019 struct intel_iommu *iommu;
2020 struct dmar_drhd_unit *drhd;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002021 struct pci_dev *dev_tmp;
2022 unsigned long flags;
2023 int bus = 0, devfn = 0;
David Woodhouse276dbf992009-04-04 01:45:37 +01002024 int segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002025
2026 domain = find_domain(pdev);
2027 if (domain)
2028 return domain;
2029
David Woodhouse276dbf992009-04-04 01:45:37 +01002030 segment = pci_domain_nr(pdev->bus);
2031
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002032 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
2033 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002034 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002035 bus = dev_tmp->subordinate->number;
2036 devfn = 0;
2037 } else {
2038 bus = dev_tmp->bus->number;
2039 devfn = dev_tmp->devfn;
2040 }
2041 spin_lock_irqsave(&device_domain_lock, flags);
Jiang Liu745f2582014-02-19 14:07:26 +08002042 domain = dmar_search_domain_by_dev_info(segment, bus, devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002043 spin_unlock_irqrestore(&device_domain_lock, flags);
2044 /* pcie-pci bridge already has a domain, uses it */
Jiang Liu745f2582014-02-19 14:07:26 +08002045 if (domain)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002046 goto found_domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002047 }
2048
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002049 drhd = dmar_find_matched_drhd_unit(pdev);
2050 if (!drhd) {
2051 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2052 pci_name(pdev));
2053 return NULL;
2054 }
2055 iommu = drhd->iommu;
2056
Jiang Liu745f2582014-02-19 14:07:26 +08002057 /* Allocate and intialize new domain for the device */
2058 domain = alloc_domain();
2059 if (!domain)
2060 goto error;
2061 if (iommu_attach_domain(domain, iommu)) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002062 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002063 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002064 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002065 if (domain_init(domain, gaw)) {
2066 domain_exit(domain);
2067 goto error;
2068 }
2069
2070 /* register pcie-to-pci device */
2071 if (dev_tmp) {
Jiang Liu745f2582014-02-19 14:07:26 +08002072 if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002073 domain_exit(domain);
2074 goto error;
2075 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002076 }
2077
2078found_domain:
Jiang Liu745f2582014-02-19 14:07:26 +08002079 if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
2080 pdev, &domain) == 0)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002081 return domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002082error:
2083 /* recheck it here, maybe others set it */
2084 return find_domain(pdev);
2085}
2086
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002087static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002088#define IDENTMAP_ALL 1
2089#define IDENTMAP_GFX 2
2090#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002091
David Woodhouseb2132032009-06-26 18:50:28 +01002092static int iommu_domain_identity_map(struct dmar_domain *domain,
2093 unsigned long long start,
2094 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002095{
David Woodhousec5395d52009-06-28 16:35:56 +01002096 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2097 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002098
David Woodhousec5395d52009-06-28 16:35:56 +01002099 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2100 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002101 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002102 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002103 }
2104
David Woodhousec5395d52009-06-28 16:35:56 +01002105 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2106 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002107 /*
2108 * RMRR range might have overlap with physical memory range,
2109 * clear it first
2110 */
David Woodhousec5395d52009-06-28 16:35:56 +01002111 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002112
David Woodhousec5395d52009-06-28 16:35:56 +01002113 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2114 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002115 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002116}
2117
2118static int iommu_prepare_identity_map(struct pci_dev *pdev,
2119 unsigned long long start,
2120 unsigned long long end)
2121{
2122 struct dmar_domain *domain;
2123 int ret;
2124
David Woodhousec7ab48d2009-06-26 19:10:36 +01002125 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002126 if (!domain)
2127 return -ENOMEM;
2128
David Woodhouse19943b02009-08-04 16:19:20 +01002129 /* For _hardware_ passthrough, don't bother. But for software
2130 passthrough, we do it anyway -- it may indicate a memory
2131 range which is reserved in E820, so which didn't get set
2132 up to start with in si_domain */
2133 if (domain == si_domain && hw_pass_through) {
2134 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2135 pci_name(pdev), start, end);
2136 return 0;
2137 }
2138
2139 printk(KERN_INFO
2140 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2141 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002142
David Woodhouse5595b522009-12-02 09:21:55 +00002143 if (end < start) {
2144 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2145 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2146 dmi_get_system_info(DMI_BIOS_VENDOR),
2147 dmi_get_system_info(DMI_BIOS_VERSION),
2148 dmi_get_system_info(DMI_PRODUCT_VERSION));
2149 ret = -EIO;
2150 goto error;
2151 }
2152
David Woodhouse2ff729f2009-08-26 14:25:41 +01002153 if (end >> agaw_to_width(domain->agaw)) {
2154 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2155 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2156 agaw_to_width(domain->agaw),
2157 dmi_get_system_info(DMI_BIOS_VENDOR),
2158 dmi_get_system_info(DMI_BIOS_VERSION),
2159 dmi_get_system_info(DMI_PRODUCT_VERSION));
2160 ret = -EIO;
2161 goto error;
2162 }
David Woodhouse19943b02009-08-04 16:19:20 +01002163
David Woodhouseb2132032009-06-26 18:50:28 +01002164 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002165 if (ret)
2166 goto error;
2167
2168 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002169 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002170 if (ret)
2171 goto error;
2172
2173 return 0;
2174
2175 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002176 domain_exit(domain);
2177 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002178}
2179
2180static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2181 struct pci_dev *pdev)
2182{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002183 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002184 return 0;
2185 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002186 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002187}
2188
Suresh Siddhad3f13812011-08-23 17:05:25 -07002189#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002190static inline void iommu_prepare_isa(void)
2191{
2192 struct pci_dev *pdev;
2193 int ret;
2194
2195 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2196 if (!pdev)
2197 return;
2198
David Woodhousec7ab48d2009-06-26 19:10:36 +01002199 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002200 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002201
2202 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002203 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2204 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002205
2206}
2207#else
2208static inline void iommu_prepare_isa(void)
2209{
2210 return;
2211}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002212#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002213
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002214static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002215
Matt Kraai071e1372009-08-23 22:30:22 -07002216static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002217{
2218 struct dmar_drhd_unit *drhd;
2219 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002220 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002221
2222 si_domain = alloc_domain();
2223 if (!si_domain)
2224 return -EFAULT;
2225
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002226 for_each_active_iommu(iommu, drhd) {
2227 ret = iommu_attach_domain(si_domain, iommu);
2228 if (ret) {
2229 domain_exit(si_domain);
2230 return -EFAULT;
2231 }
2232 }
2233
2234 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2235 domain_exit(si_domain);
2236 return -EFAULT;
2237 }
2238
2239 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
Jiang Liu9544c002014-01-06 14:18:13 +08002240 pr_debug("IOMMU: identity mapping domain is domain %d\n",
2241 si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002242
David Woodhouse19943b02009-08-04 16:19:20 +01002243 if (hw)
2244 return 0;
2245
David Woodhousec7ab48d2009-06-26 19:10:36 +01002246 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002247 unsigned long start_pfn, end_pfn;
2248 int i;
2249
2250 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2251 ret = iommu_domain_identity_map(si_domain,
2252 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2253 if (ret)
2254 return ret;
2255 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002256 }
2257
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002258 return 0;
2259}
2260
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002261static int identity_mapping(struct pci_dev *pdev)
2262{
2263 struct device_domain_info *info;
2264
2265 if (likely(!iommu_identity_mapping))
2266 return 0;
2267
Mike Traviscb452a42011-05-28 13:15:03 -05002268 info = pdev->dev.archdata.iommu;
2269 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2270 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002271
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002272 return 0;
2273}
2274
2275static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002276 struct pci_dev *pdev,
2277 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002278{
2279 struct device_domain_info *info;
2280 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002281 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002282
2283 info = alloc_devinfo_mem();
2284 if (!info)
2285 return -ENOMEM;
2286
2287 info->segment = pci_domain_nr(pdev->bus);
2288 info->bus = pdev->bus->number;
2289 info->devfn = pdev->devfn;
2290 info->dev = pdev;
2291 info->domain = domain;
2292
2293 spin_lock_irqsave(&device_domain_lock, flags);
2294 list_add(&info->link, &domain->devices);
2295 list_add(&info->global, &device_domain_list);
2296 pdev->dev.archdata.iommu = info;
2297 spin_unlock_irqrestore(&device_domain_lock, flags);
2298
David Woodhousee2ad23d2012-05-25 17:42:54 +01002299 ret = domain_context_mapping(domain, pdev, translation);
2300 if (ret) {
2301 spin_lock_irqsave(&device_domain_lock, flags);
David Woodhouse109b9b02012-05-25 17:43:02 +01002302 unlink_domain_info(info);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002303 spin_unlock_irqrestore(&device_domain_lock, flags);
2304 free_devinfo_mem(info);
2305 return ret;
2306 }
2307
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002308 return 0;
2309}
2310
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002311static bool device_has_rmrr(struct pci_dev *dev)
2312{
2313 struct dmar_rmrr_unit *rmrr;
2314 int i;
2315
2316 for_each_rmrr_units(rmrr) {
2317 for (i = 0; i < rmrr->devices_cnt; i++) {
2318 /*
2319 * Return TRUE if this RMRR contains the device that
2320 * is passed in.
2321 */
2322 if (rmrr->devices[i] == dev)
2323 return true;
2324 }
2325 }
2326 return false;
2327}
2328
David Woodhouse6941af22009-07-04 18:24:27 +01002329static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2330{
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002331
2332 /*
2333 * We want to prevent any device associated with an RMRR from
2334 * getting placed into the SI Domain. This is done because
2335 * problems exist when devices are moved in and out of domains
2336 * and their respective RMRR info is lost. We exempt USB devices
2337 * from this process due to their usage of RMRRs that are known
2338 * to not be needed after BIOS hand-off to OS.
2339 */
2340 if (device_has_rmrr(pdev) &&
2341 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2342 return 0;
2343
David Woodhousee0fc7e02009-09-30 09:12:17 -07002344 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2345 return 1;
2346
2347 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2348 return 1;
2349
2350 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2351 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002352
David Woodhouse3dfc8132009-07-04 19:11:08 +01002353 /*
2354 * We want to start off with all devices in the 1:1 domain, and
2355 * take them out later if we find they can't access all of memory.
2356 *
2357 * However, we can't do this for PCI devices behind bridges,
2358 * because all PCI devices behind the same bridge will end up
2359 * with the same source-id on their transactions.
2360 *
2361 * Practically speaking, we can't change things around for these
2362 * devices at run-time, because we can't be sure there'll be no
2363 * DMA transactions in flight for any of their siblings.
2364 *
2365 * So PCI devices (unless they're on the root bus) as well as
2366 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2367 * the 1:1 domain, just in _case_ one of their siblings turns out
2368 * not to be able to map all of memory.
2369 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002370 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002371 if (!pci_is_root_bus(pdev->bus))
2372 return 0;
2373 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2374 return 0;
Yijing Wang62f87c02012-07-24 17:20:03 +08002375 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
David Woodhouse3dfc8132009-07-04 19:11:08 +01002376 return 0;
2377
2378 /*
2379 * At boot time, we don't yet know if devices will be 64-bit capable.
2380 * Assume that they will -- if they turn out not to be, then we can
2381 * take them out of the 1:1 domain later.
2382 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002383 if (!startup) {
2384 /*
2385 * If the device's dma_mask is less than the system's memory
2386 * size then this is not a candidate for identity mapping.
2387 */
2388 u64 dma_mask = pdev->dma_mask;
2389
2390 if (pdev->dev.coherent_dma_mask &&
2391 pdev->dev.coherent_dma_mask < dma_mask)
2392 dma_mask = pdev->dev.coherent_dma_mask;
2393
2394 return dma_mask >= dma_get_required_mask(&pdev->dev);
2395 }
David Woodhouse6941af22009-07-04 18:24:27 +01002396
2397 return 1;
2398}
2399
Matt Kraai071e1372009-08-23 22:30:22 -07002400static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002401{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002402 struct pci_dev *pdev = NULL;
2403 int ret;
2404
David Woodhouse19943b02009-08-04 16:19:20 +01002405 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002406 if (ret)
2407 return -EFAULT;
2408
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002409 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002410 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002411 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002412 hw ? CONTEXT_TT_PASS_THROUGH :
2413 CONTEXT_TT_MULTI_LEVEL);
2414 if (ret) {
2415 /* device not associated with an iommu */
2416 if (ret == -ENODEV)
2417 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002418 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002419 }
2420 pr_info("IOMMU: %s identity mapping for device %s\n",
2421 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002422 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002423 }
2424
2425 return 0;
2426}
2427
Joseph Cihulab7792602011-05-03 00:08:37 -07002428static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002429{
2430 struct dmar_drhd_unit *drhd;
2431 struct dmar_rmrr_unit *rmrr;
2432 struct pci_dev *pdev;
2433 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002434 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002435
2436 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002437 * for each drhd
2438 * allocate root
2439 * initialize and program root entry to not present
2440 * endfor
2441 */
2442 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002443 /*
2444 * lock not needed as this is only incremented in the single
2445 * threaded kernel __init code path all other access are read
2446 * only
2447 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002448 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2449 g_num_of_iommus++;
2450 continue;
2451 }
2452 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2453 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002454 }
2455
Weidong Hand9630fe2008-12-08 11:06:32 +08002456 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2457 GFP_KERNEL);
2458 if (!g_iommus) {
2459 printk(KERN_ERR "Allocating global iommu array failed\n");
2460 ret = -ENOMEM;
2461 goto error;
2462 }
2463
mark gross80b20dd2008-04-18 13:53:58 -07002464 deferred_flush = kzalloc(g_num_of_iommus *
2465 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2466 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002467 ret = -ENOMEM;
Jiang Liu989d51f2014-02-19 14:07:21 +08002468 goto free_g_iommus;
mark gross5e0d2a62008-03-04 15:22:08 -08002469 }
2470
Jiang Liu7c919772014-01-06 14:18:18 +08002471 for_each_active_iommu(iommu, drhd) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002472 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002473
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002474 ret = iommu_init_domains(iommu);
2475 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002476 goto free_iommu;
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002477
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002478 /*
2479 * TBD:
2480 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002481 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002482 */
2483 ret = iommu_alloc_root_entry(iommu);
2484 if (ret) {
2485 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002486 goto free_iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002487 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002488 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002489 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002490 }
2491
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002492 /*
2493 * Start from the sane iommu hardware state.
2494 */
Jiang Liu7c919772014-01-06 14:18:18 +08002495 for_each_active_iommu(iommu, drhd) {
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002496 /*
2497 * If the queued invalidation is already initialized by us
2498 * (for example, while enabling interrupt-remapping) then
2499 * we got the things already rolling from a sane state.
2500 */
2501 if (iommu->qi)
2502 continue;
2503
2504 /*
2505 * Clear any previous faults.
2506 */
2507 dmar_fault(-1, iommu);
2508 /*
2509 * Disable queued invalidation if supported and already enabled
2510 * before OS handover.
2511 */
2512 dmar_disable_qi(iommu);
2513 }
2514
Jiang Liu7c919772014-01-06 14:18:18 +08002515 for_each_active_iommu(iommu, drhd) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002516 if (dmar_enable_qi(iommu)) {
2517 /*
2518 * Queued Invalidate not enabled, use Register Based
2519 * Invalidate
2520 */
2521 iommu->flush.flush_context = __iommu_flush_context;
2522 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002523 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002524 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002525 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002526 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002527 } else {
2528 iommu->flush.flush_context = qi_flush_context;
2529 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002530 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002531 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002532 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002533 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002534 }
2535 }
2536
David Woodhouse19943b02009-08-04 16:19:20 +01002537 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002538 iommu_identity_mapping |= IDENTMAP_ALL;
2539
Suresh Siddhad3f13812011-08-23 17:05:25 -07002540#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002541 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002542#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002543
2544 check_tylersburg_isoch();
2545
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002546 /*
2547 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002548 * identity mappings for rmrr, gfx, and isa and may fall back to static
2549 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002550 */
David Woodhouse19943b02009-08-04 16:19:20 +01002551 if (iommu_identity_mapping) {
2552 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2553 if (ret) {
2554 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002555 goto free_iommu;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002556 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002557 }
David Woodhouse19943b02009-08-04 16:19:20 +01002558 /*
2559 * For each rmrr
2560 * for each dev attached to rmrr
2561 * do
2562 * locate drhd for dev, alloc domain for dev
2563 * allocate free domain
2564 * allocate page table entries for rmrr
2565 * if context not allocated for bus
2566 * allocate and init context
2567 * set present in root table for this bus
2568 * init context with domain, translation etc
2569 * endfor
2570 * endfor
2571 */
2572 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2573 for_each_rmrr_units(rmrr) {
2574 for (i = 0; i < rmrr->devices_cnt; i++) {
2575 pdev = rmrr->devices[i];
2576 /*
2577 * some BIOS lists non-exist devices in DMAR
2578 * table.
2579 */
2580 if (!pdev)
2581 continue;
2582 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2583 if (ret)
2584 printk(KERN_ERR
2585 "IOMMU: mapping reserved region failed\n");
2586 }
2587 }
2588
2589 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002590
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002591 /*
2592 * for each drhd
2593 * enable fault log
2594 * global invalidate context cache
2595 * global invalidate iotlb
2596 * enable translation
2597 */
Jiang Liu7c919772014-01-06 14:18:18 +08002598 for_each_iommu(iommu, drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002599 if (drhd->ignored) {
2600 /*
2601 * we always have to disable PMRs or DMA may fail on
2602 * this device
2603 */
2604 if (force_on)
Jiang Liu7c919772014-01-06 14:18:18 +08002605 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002606 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002607 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002608
2609 iommu_flush_write_buffer(iommu);
2610
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002611 ret = dmar_set_interrupt(iommu);
2612 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002613 goto free_iommu;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002614
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002615 iommu_set_root_entry(iommu);
2616
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002617 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002618 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002619
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002620 ret = iommu_enable_translation(iommu);
2621 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002622 goto free_iommu;
David Woodhouseb94996c2009-09-19 15:28:12 -07002623
2624 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002625 }
2626
2627 return 0;
Jiang Liu989d51f2014-02-19 14:07:21 +08002628
2629free_iommu:
Jiang Liu7c919772014-01-06 14:18:18 +08002630 for_each_active_iommu(iommu, drhd)
Jiang Liua868e6b2014-01-06 14:18:20 +08002631 free_dmar_iommu(iommu);
Jiang Liu9bdc5312014-01-06 14:18:27 +08002632 kfree(deferred_flush);
Jiang Liu989d51f2014-02-19 14:07:21 +08002633free_g_iommus:
Weidong Hand9630fe2008-12-08 11:06:32 +08002634 kfree(g_iommus);
Jiang Liu989d51f2014-02-19 14:07:21 +08002635error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002636 return ret;
2637}
2638
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002639/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002640static struct iova *intel_alloc_iova(struct device *dev,
2641 struct dmar_domain *domain,
2642 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002643{
2644 struct pci_dev *pdev = to_pci_dev(dev);
2645 struct iova *iova = NULL;
2646
David Woodhouse875764d2009-06-28 21:20:51 +01002647 /* Restrict dma_mask to the width that the iommu can handle */
2648 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2649
2650 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002651 /*
2652 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002653 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002654 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002655 */
David Woodhouse875764d2009-06-28 21:20:51 +01002656 iova = alloc_iova(&domain->iovad, nrpages,
2657 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2658 if (iova)
2659 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002660 }
David Woodhouse875764d2009-06-28 21:20:51 +01002661 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2662 if (unlikely(!iova)) {
2663 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2664 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002665 return NULL;
2666 }
2667
2668 return iova;
2669}
2670
David Woodhouse147202a2009-07-07 19:43:20 +01002671static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002672{
2673 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002674 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002675
2676 domain = get_domain_for_dev(pdev,
2677 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2678 if (!domain) {
2679 printk(KERN_ERR
2680 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002681 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002682 }
2683
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002684 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002685 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002686 ret = domain_context_mapping(domain, pdev,
2687 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002688 if (ret) {
2689 printk(KERN_ERR
2690 "Domain context map for %s failed",
2691 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002692 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002693 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002694 }
2695
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002696 return domain;
2697}
2698
David Woodhouse147202a2009-07-07 19:43:20 +01002699static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2700{
2701 struct device_domain_info *info;
2702
2703 /* No lock here, assumes no domain exit in normal case */
2704 info = dev->dev.archdata.iommu;
2705 if (likely(info))
2706 return info->domain;
2707
2708 return __get_valid_domain_for_dev(dev);
2709}
2710
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002711static int iommu_dummy(struct pci_dev *pdev)
2712{
2713 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2714}
2715
2716/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002717static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002718{
David Woodhouse73676832009-07-04 14:08:36 +01002719 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002720 int found;
2721
Yijing Wangdbad0862013-12-05 19:43:42 +08002722 if (unlikely(!dev_is_pci(dev)))
David Woodhouse73676832009-07-04 14:08:36 +01002723 return 1;
2724
2725 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002726 if (iommu_dummy(pdev))
2727 return 1;
2728
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002729 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002730 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002731
2732 found = identity_mapping(pdev);
2733 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002734 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002735 return 1;
2736 else {
2737 /*
2738 * 32 bit DMA is removed from si_domain and fall back
2739 * to non-identity mapping.
2740 */
2741 domain_remove_one_dev_info(si_domain, pdev);
2742 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2743 pci_name(pdev));
2744 return 0;
2745 }
2746 } else {
2747 /*
2748 * In case of a detached 64 bit DMA device from vm, the device
2749 * is put into si_domain for identity mapping.
2750 */
David Woodhouse6941af22009-07-04 18:24:27 +01002751 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002752 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002753 ret = domain_add_dev_info(si_domain, pdev,
2754 hw_pass_through ?
2755 CONTEXT_TT_PASS_THROUGH :
2756 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002757 if (!ret) {
2758 printk(KERN_INFO "64bit %s uses identity mapping\n",
2759 pci_name(pdev));
2760 return 1;
2761 }
2762 }
2763 }
2764
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002765 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002766}
2767
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002768static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2769 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002770{
2771 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002772 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002773 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002774 struct iova *iova;
2775 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002776 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002777 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002778 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002779
2780 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002781
David Woodhouse73676832009-07-04 14:08:36 +01002782 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002783 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002784
2785 domain = get_valid_domain_for_dev(pdev);
2786 if (!domain)
2787 return 0;
2788
Weidong Han8c11e792008-12-08 15:29:22 +08002789 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002790 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002791
Mike Travisc681d0b2011-05-28 13:15:05 -05002792 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002793 if (!iova)
2794 goto error;
2795
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002796 /*
2797 * Check if DMAR supports zero-length reads on write only
2798 * mappings..
2799 */
2800 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002801 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002802 prot |= DMA_PTE_READ;
2803 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2804 prot |= DMA_PTE_WRITE;
2805 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002806 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002807 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002808 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002809 * is not a big problem
2810 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002811 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002812 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002813 if (ret)
2814 goto error;
2815
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002816 /* it's a non-present to present mapping. Only flush if caching mode */
2817 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002818 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002819 else
Weidong Han8c11e792008-12-08 15:29:22 +08002820 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002821
David Woodhouse03d6a242009-06-28 15:33:46 +01002822 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2823 start_paddr += paddr & ~PAGE_MASK;
2824 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002825
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002826error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002827 if (iova)
2828 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002829 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002830 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002831 return 0;
2832}
2833
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002834static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2835 unsigned long offset, size_t size,
2836 enum dma_data_direction dir,
2837 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002838{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002839 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2840 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002841}
2842
mark gross5e0d2a62008-03-04 15:22:08 -08002843static void flush_unmaps(void)
2844{
mark gross80b20dd2008-04-18 13:53:58 -07002845 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002846
mark gross5e0d2a62008-03-04 15:22:08 -08002847 timer_on = 0;
2848
2849 /* just flush them all */
2850 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002851 struct intel_iommu *iommu = g_iommus[i];
2852 if (!iommu)
2853 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002854
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002855 if (!deferred_flush[i].next)
2856 continue;
2857
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002858 /* In caching mode, global flushes turn emulation expensive */
2859 if (!cap_caching_mode(iommu->cap))
2860 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002861 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002862 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002863 unsigned long mask;
2864 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002865 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002866
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002867 /* On real hardware multiple invalidations are expensive */
2868 if (cap_caching_mode(iommu->cap))
2869 iommu_flush_iotlb_psi(iommu, domain->id,
2870 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2871 else {
2872 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2873 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2874 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2875 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002876 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002877 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002878 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002879 }
2880
mark gross5e0d2a62008-03-04 15:22:08 -08002881 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002882}
2883
2884static void flush_unmaps_timeout(unsigned long data)
2885{
mark gross80b20dd2008-04-18 13:53:58 -07002886 unsigned long flags;
2887
2888 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002889 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002890 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002891}
2892
2893static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2894{
2895 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002896 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002897 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002898
2899 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002900 if (list_size == HIGH_WATER_MARK)
2901 flush_unmaps();
2902
Weidong Han8c11e792008-12-08 15:29:22 +08002903 iommu = domain_get_iommu(dom);
2904 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002905
mark gross80b20dd2008-04-18 13:53:58 -07002906 next = deferred_flush[iommu_id].next;
2907 deferred_flush[iommu_id].domain[next] = dom;
2908 deferred_flush[iommu_id].iova[next] = iova;
2909 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002910
2911 if (!timer_on) {
2912 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2913 timer_on = 1;
2914 }
2915 list_size++;
2916 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2917}
2918
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002919static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2920 size_t size, enum dma_data_direction dir,
2921 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002922{
2923 struct pci_dev *pdev = to_pci_dev(dev);
2924 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002925 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002926 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002927 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002928
David Woodhouse73676832009-07-04 14:08:36 +01002929 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002930 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002931
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002932 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002933 BUG_ON(!domain);
2934
Weidong Han8c11e792008-12-08 15:29:22 +08002935 iommu = domain_get_iommu(domain);
2936
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002937 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002938 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2939 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002940 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002941
David Woodhoused794dc92009-06-28 00:27:49 +01002942 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2943 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002944
David Woodhoused794dc92009-06-28 00:27:49 +01002945 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2946 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002947
2948 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002949 dma_pte_clear_range(domain, start_pfn, last_pfn);
2950
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002951 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002952 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2953
mark gross5e0d2a62008-03-04 15:22:08 -08002954 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002955 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002956 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002957 /* free iova */
2958 __free_iova(&domain->iovad, iova);
2959 } else {
2960 add_unmap(domain, iova);
2961 /*
2962 * queue up the release of the unmap to save the 1/6th of the
2963 * cpu used up by the iotlb flush operation...
2964 */
mark gross5e0d2a62008-03-04 15:22:08 -08002965 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002966}
2967
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002968static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02002969 dma_addr_t *dma_handle, gfp_t flags,
2970 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002971{
2972 void *vaddr;
2973 int order;
2974
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002975 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002976 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002977
2978 if (!iommu_no_mapping(hwdev))
2979 flags &= ~(GFP_DMA | GFP_DMA32);
2980 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
2981 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
2982 flags |= GFP_DMA;
2983 else
2984 flags |= GFP_DMA32;
2985 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002986
2987 vaddr = (void *)__get_free_pages(flags, order);
2988 if (!vaddr)
2989 return NULL;
2990 memset(vaddr, 0, size);
2991
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002992 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
2993 DMA_BIDIRECTIONAL,
2994 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002995 if (*dma_handle)
2996 return vaddr;
2997 free_pages((unsigned long)vaddr, order);
2998 return NULL;
2999}
3000
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003001static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003002 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003003{
3004 int order;
3005
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003006 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003007 order = get_order(size);
3008
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003009 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003010 free_pages((unsigned long)vaddr, order);
3011}
3012
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003013static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3014 int nelems, enum dma_data_direction dir,
3015 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003016{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003017 struct pci_dev *pdev = to_pci_dev(hwdev);
3018 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003019 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003020 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003021 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003022
David Woodhouse73676832009-07-04 14:08:36 +01003023 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003024 return;
3025
3026 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003027 BUG_ON(!domain);
3028
3029 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003030
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003031 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003032 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3033 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003034 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003035
David Woodhoused794dc92009-06-28 00:27:49 +01003036 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3037 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003038
3039 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003040 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003041
David Woodhoused794dc92009-06-28 00:27:49 +01003042 /* free page tables */
3043 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3044
David Woodhouseacea0012009-07-14 01:55:11 +01003045 if (intel_iommu_strict) {
3046 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003047 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003048 /* free iova */
3049 __free_iova(&domain->iovad, iova);
3050 } else {
3051 add_unmap(domain, iova);
3052 /*
3053 * queue up the release of the unmap to save the 1/6th of the
3054 * cpu used up by the iotlb flush operation...
3055 */
3056 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003057}
3058
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003059static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003060 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003061{
3062 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003063 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003064
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003065 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003066 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003067 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003068 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003069 }
3070 return nelems;
3071}
3072
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003073static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3074 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003075{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003076 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003077 struct pci_dev *pdev = to_pci_dev(hwdev);
3078 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003079 size_t size = 0;
3080 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003081 struct iova *iova = NULL;
3082 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003083 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003084 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003085 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003086
3087 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003088 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003089 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003090
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003091 domain = get_valid_domain_for_dev(pdev);
3092 if (!domain)
3093 return 0;
3094
Weidong Han8c11e792008-12-08 15:29:22 +08003095 iommu = domain_get_iommu(domain);
3096
David Woodhouseb536d242009-06-28 14:49:31 +01003097 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003098 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003099
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003100 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3101 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003102 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003103 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003104 return 0;
3105 }
3106
3107 /*
3108 * Check if DMAR supports zero-length reads on write only
3109 * mappings..
3110 */
3111 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003112 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003113 prot |= DMA_PTE_READ;
3114 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3115 prot |= DMA_PTE_WRITE;
3116
David Woodhouseb536d242009-06-28 14:49:31 +01003117 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003118
Fenghua Yuf5329592009-08-04 15:09:37 -07003119 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003120 if (unlikely(ret)) {
3121 /* clear the page */
3122 dma_pte_clear_range(domain, start_vpfn,
3123 start_vpfn + size - 1);
3124 /* free page tables */
3125 dma_pte_free_pagetable(domain, start_vpfn,
3126 start_vpfn + size - 1);
3127 /* free iova */
3128 __free_iova(&domain->iovad, iova);
3129 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003130 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003131
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003132 /* it's a non-present to present mapping. Only flush if caching mode */
3133 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003134 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003135 else
Weidong Han8c11e792008-12-08 15:29:22 +08003136 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003137
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003138 return nelems;
3139}
3140
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003141static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3142{
3143 return !dma_addr;
3144}
3145
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003146struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003147 .alloc = intel_alloc_coherent,
3148 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003149 .map_sg = intel_map_sg,
3150 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003151 .map_page = intel_map_page,
3152 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003153 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003154};
3155
3156static inline int iommu_domain_cache_init(void)
3157{
3158 int ret = 0;
3159
3160 iommu_domain_cache = kmem_cache_create("iommu_domain",
3161 sizeof(struct dmar_domain),
3162 0,
3163 SLAB_HWCACHE_ALIGN,
3164
3165 NULL);
3166 if (!iommu_domain_cache) {
3167 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3168 ret = -ENOMEM;
3169 }
3170
3171 return ret;
3172}
3173
3174static inline int iommu_devinfo_cache_init(void)
3175{
3176 int ret = 0;
3177
3178 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3179 sizeof(struct device_domain_info),
3180 0,
3181 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003182 NULL);
3183 if (!iommu_devinfo_cache) {
3184 printk(KERN_ERR "Couldn't create devinfo cache\n");
3185 ret = -ENOMEM;
3186 }
3187
3188 return ret;
3189}
3190
3191static inline int iommu_iova_cache_init(void)
3192{
3193 int ret = 0;
3194
3195 iommu_iova_cache = kmem_cache_create("iommu_iova",
3196 sizeof(struct iova),
3197 0,
3198 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003199 NULL);
3200 if (!iommu_iova_cache) {
3201 printk(KERN_ERR "Couldn't create iova cache\n");
3202 ret = -ENOMEM;
3203 }
3204
3205 return ret;
3206}
3207
3208static int __init iommu_init_mempool(void)
3209{
3210 int ret;
3211 ret = iommu_iova_cache_init();
3212 if (ret)
3213 return ret;
3214
3215 ret = iommu_domain_cache_init();
3216 if (ret)
3217 goto domain_error;
3218
3219 ret = iommu_devinfo_cache_init();
3220 if (!ret)
3221 return ret;
3222
3223 kmem_cache_destroy(iommu_domain_cache);
3224domain_error:
3225 kmem_cache_destroy(iommu_iova_cache);
3226
3227 return -ENOMEM;
3228}
3229
3230static void __init iommu_exit_mempool(void)
3231{
3232 kmem_cache_destroy(iommu_devinfo_cache);
3233 kmem_cache_destroy(iommu_domain_cache);
3234 kmem_cache_destroy(iommu_iova_cache);
3235
3236}
3237
Dan Williams556ab452010-07-23 15:47:56 -07003238static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3239{
3240 struct dmar_drhd_unit *drhd;
3241 u32 vtbar;
3242 int rc;
3243
3244 /* We know that this device on this chipset has its own IOMMU.
3245 * If we find it under a different IOMMU, then the BIOS is lying
3246 * to us. Hope that the IOMMU for this device is actually
3247 * disabled, and it needs no translation...
3248 */
3249 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3250 if (rc) {
3251 /* "can't" happen */
3252 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3253 return;
3254 }
3255 vtbar &= 0xffff0000;
3256
3257 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3258 drhd = dmar_find_matched_drhd_unit(pdev);
3259 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3260 TAINT_FIRMWARE_WORKAROUND,
3261 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3262 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3263}
3264DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3265
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003266static void __init init_no_remapping_devices(void)
3267{
3268 struct dmar_drhd_unit *drhd;
3269
3270 for_each_drhd_unit(drhd) {
3271 if (!drhd->include_all) {
3272 int i;
3273 for (i = 0; i < drhd->devices_cnt; i++)
3274 if (drhd->devices[i] != NULL)
3275 break;
3276 /* ignore DMAR unit if no pci devices exist */
3277 if (i == drhd->devices_cnt)
3278 drhd->ignored = 1;
3279 }
3280 }
3281
Jiang Liu7c919772014-01-06 14:18:18 +08003282 for_each_active_drhd_unit(drhd) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003283 int i;
Jiang Liu7c919772014-01-06 14:18:18 +08003284 if (drhd->include_all)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003285 continue;
3286
3287 for (i = 0; i < drhd->devices_cnt; i++)
3288 if (drhd->devices[i] &&
David Woodhousec0771df2011-10-14 20:59:46 +01003289 !IS_GFX_DEVICE(drhd->devices[i]))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003290 break;
3291
3292 if (i < drhd->devices_cnt)
3293 continue;
3294
David Woodhousec0771df2011-10-14 20:59:46 +01003295 /* This IOMMU has *only* gfx devices. Either bypass it or
3296 set the gfx_mapped flag, as appropriate */
3297 if (dmar_map_gfx) {
3298 intel_iommu_gfx_mapped = 1;
3299 } else {
3300 drhd->ignored = 1;
3301 for (i = 0; i < drhd->devices_cnt; i++) {
3302 if (!drhd->devices[i])
3303 continue;
3304 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3305 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003306 }
3307 }
3308}
3309
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003310#ifdef CONFIG_SUSPEND
3311static int init_iommu_hw(void)
3312{
3313 struct dmar_drhd_unit *drhd;
3314 struct intel_iommu *iommu = NULL;
3315
3316 for_each_active_iommu(iommu, drhd)
3317 if (iommu->qi)
3318 dmar_reenable_qi(iommu);
3319
Joseph Cihulab7792602011-05-03 00:08:37 -07003320 for_each_iommu(iommu, drhd) {
3321 if (drhd->ignored) {
3322 /*
3323 * we always have to disable PMRs or DMA may fail on
3324 * this device
3325 */
3326 if (force_on)
3327 iommu_disable_protect_mem_regions(iommu);
3328 continue;
3329 }
3330
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003331 iommu_flush_write_buffer(iommu);
3332
3333 iommu_set_root_entry(iommu);
3334
3335 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003336 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003337 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003338 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003339 if (iommu_enable_translation(iommu))
3340 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003341 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003342 }
3343
3344 return 0;
3345}
3346
3347static void iommu_flush_all(void)
3348{
3349 struct dmar_drhd_unit *drhd;
3350 struct intel_iommu *iommu;
3351
3352 for_each_active_iommu(iommu, drhd) {
3353 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003354 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003355 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003356 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003357 }
3358}
3359
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003360static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003361{
3362 struct dmar_drhd_unit *drhd;
3363 struct intel_iommu *iommu = NULL;
3364 unsigned long flag;
3365
3366 for_each_active_iommu(iommu, drhd) {
3367 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3368 GFP_ATOMIC);
3369 if (!iommu->iommu_state)
3370 goto nomem;
3371 }
3372
3373 iommu_flush_all();
3374
3375 for_each_active_iommu(iommu, drhd) {
3376 iommu_disable_translation(iommu);
3377
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003378 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003379
3380 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3381 readl(iommu->reg + DMAR_FECTL_REG);
3382 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3383 readl(iommu->reg + DMAR_FEDATA_REG);
3384 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3385 readl(iommu->reg + DMAR_FEADDR_REG);
3386 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3387 readl(iommu->reg + DMAR_FEUADDR_REG);
3388
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003389 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003390 }
3391 return 0;
3392
3393nomem:
3394 for_each_active_iommu(iommu, drhd)
3395 kfree(iommu->iommu_state);
3396
3397 return -ENOMEM;
3398}
3399
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003400static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003401{
3402 struct dmar_drhd_unit *drhd;
3403 struct intel_iommu *iommu = NULL;
3404 unsigned long flag;
3405
3406 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003407 if (force_on)
3408 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3409 else
3410 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003411 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003412 }
3413
3414 for_each_active_iommu(iommu, drhd) {
3415
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003416 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003417
3418 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3419 iommu->reg + DMAR_FECTL_REG);
3420 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3421 iommu->reg + DMAR_FEDATA_REG);
3422 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3423 iommu->reg + DMAR_FEADDR_REG);
3424 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3425 iommu->reg + DMAR_FEUADDR_REG);
3426
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003427 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003428 }
3429
3430 for_each_active_iommu(iommu, drhd)
3431 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003432}
3433
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003434static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003435 .resume = iommu_resume,
3436 .suspend = iommu_suspend,
3437};
3438
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003439static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003440{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003441 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003442}
3443
3444#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003445static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003446#endif /* CONFIG_PM */
3447
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003448static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3449{
3450 list_add(&rmrr->list, &dmar_rmrr_units);
3451}
3452
3453
3454int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3455{
3456 struct acpi_dmar_reserved_memory *rmrr;
3457 struct dmar_rmrr_unit *rmrru;
3458
3459 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3460 if (!rmrru)
3461 return -ENOMEM;
3462
3463 rmrru->hdr = header;
3464 rmrr = (struct acpi_dmar_reserved_memory *)header;
3465 rmrru->base_address = rmrr->base_address;
3466 rmrru->end_address = rmrr->end_address;
3467
3468 dmar_register_rmrr_unit(rmrru);
3469 return 0;
3470}
3471
3472static int __init
3473rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3474{
3475 struct acpi_dmar_reserved_memory *rmrr;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003476
3477 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003478 return dmar_parse_dev_scope((void *)(rmrr + 1),
3479 ((void *)rmrr) + rmrr->header.length,
3480 &rmrru->devices_cnt, &rmrru->devices,
3481 rmrr->segment);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003482}
3483
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003484int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3485{
3486 struct acpi_dmar_atsr *atsr;
3487 struct dmar_atsr_unit *atsru;
3488
3489 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3490 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3491 if (!atsru)
3492 return -ENOMEM;
3493
3494 atsru->hdr = hdr;
3495 atsru->include_all = atsr->flags & 0x1;
3496
3497 list_add(&atsru->list, &dmar_atsr_units);
3498
3499 return 0;
3500}
3501
3502static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3503{
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003504 struct acpi_dmar_atsr *atsr;
3505
3506 if (atsru->include_all)
3507 return 0;
3508
3509 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
Jiang Liu9bdc5312014-01-06 14:18:27 +08003510 return dmar_parse_dev_scope((void *)(atsr + 1),
3511 (void *)atsr + atsr->header.length,
3512 &atsru->devices_cnt, &atsru->devices,
3513 atsr->segment);
3514}
3515
3516static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
3517{
3518 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
3519 kfree(atsru);
3520}
3521
3522static void intel_iommu_free_dmars(void)
3523{
3524 struct dmar_rmrr_unit *rmrru, *rmrr_n;
3525 struct dmar_atsr_unit *atsru, *atsr_n;
3526
3527 list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
3528 list_del(&rmrru->list);
3529 dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
3530 kfree(rmrru);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003531 }
3532
Jiang Liu9bdc5312014-01-06 14:18:27 +08003533 list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
3534 list_del(&atsru->list);
3535 intel_iommu_free_atsr(atsru);
3536 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003537}
3538
3539int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3540{
3541 int i;
3542 struct pci_bus *bus;
3543 struct acpi_dmar_atsr *atsr;
3544 struct dmar_atsr_unit *atsru;
3545
3546 dev = pci_physfn(dev);
3547
3548 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3549 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3550 if (atsr->segment == pci_domain_nr(dev->bus))
3551 goto found;
3552 }
3553
3554 return 0;
3555
3556found:
3557 for (bus = dev->bus; bus; bus = bus->parent) {
3558 struct pci_dev *bridge = bus->self;
3559
3560 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003561 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003562 return 0;
3563
Yijing Wang62f87c02012-07-24 17:20:03 +08003564 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003565 for (i = 0; i < atsru->devices_cnt; i++)
3566 if (atsru->devices[i] == bridge)
3567 return 1;
3568 break;
3569 }
3570 }
3571
3572 if (atsru->include_all)
3573 return 1;
3574
3575 return 0;
3576}
3577
Sergey Senozhatskyc8f369a2011-10-26 18:45:39 +03003578int __init dmar_parse_rmrr_atsr_dev(void)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003579{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003580 struct dmar_rmrr_unit *rmrr;
3581 struct dmar_atsr_unit *atsr;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003582 int ret = 0;
3583
Jiang Liu9bdc5312014-01-06 14:18:27 +08003584 list_for_each_entry(rmrr, &dmar_rmrr_units, list) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003585 ret = rmrr_parse_dev(rmrr);
3586 if (ret)
3587 return ret;
3588 }
3589
Jiang Liu9bdc5312014-01-06 14:18:27 +08003590 list_for_each_entry(atsr, &dmar_atsr_units, list) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003591 ret = atsr_parse_dev(atsr);
3592 if (ret)
3593 return ret;
3594 }
3595
3596 return ret;
3597}
3598
Fenghua Yu99dcade2009-11-11 07:23:06 -08003599/*
3600 * Here we only respond to action of unbound device from driver.
3601 *
3602 * Added device is not attached to its DMAR domain here yet. That will happen
3603 * when mapping the device to iova.
3604 */
3605static int device_notifier(struct notifier_block *nb,
3606 unsigned long action, void *data)
3607{
3608 struct device *dev = data;
3609 struct pci_dev *pdev = to_pci_dev(dev);
3610 struct dmar_domain *domain;
3611
Jiang Liu816997d2014-02-19 14:07:22 +08003612 if (iommu_dummy(pdev))
David Woodhouse44cd6132009-12-02 10:18:30 +00003613 return 0;
3614
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003615 if (action != BUS_NOTIFY_UNBOUND_DRIVER &&
3616 action != BUS_NOTIFY_DEL_DEVICE)
3617 return 0;
3618
Fenghua Yu99dcade2009-11-11 07:23:06 -08003619 domain = find_domain(pdev);
3620 if (!domain)
3621 return 0;
3622
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003623 domain_remove_one_dev_info(domain, pdev);
3624 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3625 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3626 list_empty(&domain->devices))
3627 domain_exit(domain);
Alex Williamsona97590e2011-03-04 14:52:16 -07003628
Fenghua Yu99dcade2009-11-11 07:23:06 -08003629 return 0;
3630}
3631
3632static struct notifier_block device_nb = {
3633 .notifier_call = device_notifier,
3634};
3635
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003636int __init intel_iommu_init(void)
3637{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003638 int ret = -ENODEV;
Takao Indoh3a93c842013-04-23 17:35:03 +09003639 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +08003640 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003641
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003642 /* VT-d is required for a TXT/tboot launch, so enforce that */
3643 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003644
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003645 if (dmar_table_init()) {
3646 if (force_on)
3647 panic("tboot: Failed to initialize DMAR table\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003648 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003649 }
3650
Takao Indoh3a93c842013-04-23 17:35:03 +09003651 /*
3652 * Disable translation if already enabled prior to OS handover.
3653 */
Jiang Liu7c919772014-01-06 14:18:18 +08003654 for_each_active_iommu(iommu, drhd)
Takao Indoh3a93c842013-04-23 17:35:03 +09003655 if (iommu->gcmd & DMA_GCMD_TE)
3656 iommu_disable_translation(iommu);
Takao Indoh3a93c842013-04-23 17:35:03 +09003657
Suresh Siddhac2c72862011-08-23 17:05:19 -07003658 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003659 if (force_on)
3660 panic("tboot: Failed to initialize DMAR device scope\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003661 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003662 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003663
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003664 if (no_iommu || dmar_disabled)
Jiang Liu9bdc5312014-01-06 14:18:27 +08003665 goto out_free_dmar;
Suresh Siddha2ae21012008-07-10 11:16:43 -07003666
Joseph Cihula51a63e62011-03-21 11:04:24 -07003667 if (iommu_init_mempool()) {
3668 if (force_on)
3669 panic("tboot: Failed to initialize iommu memory\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003670 goto out_free_dmar;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003671 }
3672
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003673 if (list_empty(&dmar_rmrr_units))
3674 printk(KERN_INFO "DMAR: No RMRR found\n");
3675
3676 if (list_empty(&dmar_atsr_units))
3677 printk(KERN_INFO "DMAR: No ATSR found\n");
3678
Joseph Cihula51a63e62011-03-21 11:04:24 -07003679 if (dmar_init_reserved_ranges()) {
3680 if (force_on)
3681 panic("tboot: Failed to reserve iommu ranges\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003682 goto out_free_mempool;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003683 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003684
3685 init_no_remapping_devices();
3686
Joseph Cihulab7792602011-05-03 00:08:37 -07003687 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003688 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003689 if (force_on)
3690 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003691 printk(KERN_ERR "IOMMU: dmar init failed\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003692 goto out_free_reserved_range;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003693 }
3694 printk(KERN_INFO
3695 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3696
mark gross5e0d2a62008-03-04 15:22:08 -08003697 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003698#ifdef CONFIG_SWIOTLB
3699 swiotlb = 0;
3700#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003701 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003702
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003703 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003704
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003705 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003706
Fenghua Yu99dcade2009-11-11 07:23:06 -08003707 bus_register_notifier(&pci_bus_type, &device_nb);
3708
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003709 intel_iommu_enabled = 1;
3710
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003711 return 0;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003712
3713out_free_reserved_range:
3714 put_iova_domain(&reserved_iova_list);
3715out_free_mempool:
3716 iommu_exit_mempool();
3717out_free_dmar:
3718 intel_iommu_free_dmars();
3719 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003720}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003721
Han, Weidong3199aa62009-02-26 17:31:12 +08003722static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3723 struct pci_dev *pdev)
3724{
3725 struct pci_dev *tmp, *parent;
3726
3727 if (!iommu || !pdev)
3728 return;
3729
3730 /* dependent device detach */
3731 tmp = pci_find_upstream_pcie_bridge(pdev);
3732 /* Secondary interface's bus number and devfn 0 */
3733 if (tmp) {
3734 parent = pdev->bus->self;
3735 while (parent != tmp) {
3736 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01003737 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003738 parent = parent->bus->self;
3739 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003740 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003741 iommu_detach_dev(iommu,
3742 tmp->subordinate->number, 0);
3743 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01003744 iommu_detach_dev(iommu, tmp->bus->number,
3745 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003746 }
3747}
3748
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003749static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003750 struct pci_dev *pdev)
3751{
Yijing Wangbca2b912013-10-31 17:26:04 +08003752 struct device_domain_info *info, *tmp;
Weidong Hanc7151a82008-12-08 22:51:37 +08003753 struct intel_iommu *iommu;
3754 unsigned long flags;
3755 int found = 0;
Weidong Hanc7151a82008-12-08 22:51:37 +08003756
David Woodhouse276dbf992009-04-04 01:45:37 +01003757 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3758 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003759 if (!iommu)
3760 return;
3761
3762 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wangbca2b912013-10-31 17:26:04 +08003763 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
Mike Habeck8519dc42011-05-28 13:15:07 -05003764 if (info->segment == pci_domain_nr(pdev->bus) &&
3765 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003766 info->devfn == pdev->devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01003767 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003768 spin_unlock_irqrestore(&device_domain_lock, flags);
3769
Yu Zhao93a23a72009-05-18 13:51:37 +08003770 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003771 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003772 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003773 free_devinfo_mem(info);
3774
3775 spin_lock_irqsave(&device_domain_lock, flags);
3776
3777 if (found)
3778 break;
3779 else
3780 continue;
3781 }
3782
3783 /* if there is no other devices under the same iommu
3784 * owned by this domain, clear this iommu in iommu_bmp
3785 * update iommu count and coherency
3786 */
David Woodhouse276dbf992009-04-04 01:45:37 +01003787 if (iommu == device_to_iommu(info->segment, info->bus,
3788 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003789 found = 1;
3790 }
3791
Roland Dreier3e7abe22011-07-20 06:22:21 -07003792 spin_unlock_irqrestore(&device_domain_lock, flags);
3793
Weidong Hanc7151a82008-12-08 22:51:37 +08003794 if (found == 0) {
3795 unsigned long tmp_flags;
3796 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003797 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003798 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003799 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003800 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003801
Alex Williamson9b4554b2011-05-24 12:19:04 -04003802 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3803 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3804 spin_lock_irqsave(&iommu->lock, tmp_flags);
3805 clear_bit(domain->id, iommu->domain_ids);
3806 iommu->domains[domain->id] = NULL;
3807 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3808 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003809 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003810}
3811
3812static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
3813{
3814 struct device_domain_info *info;
3815 struct intel_iommu *iommu;
3816 unsigned long flags1, flags2;
3817
3818 spin_lock_irqsave(&device_domain_lock, flags1);
3819 while (!list_empty(&domain->devices)) {
3820 info = list_entry(domain->devices.next,
3821 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01003822 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003823 spin_unlock_irqrestore(&device_domain_lock, flags1);
3824
Yu Zhao93a23a72009-05-18 13:51:37 +08003825 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01003826 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003827 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003828 iommu_detach_dependent_devices(iommu, info->dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003829
3830 /* clear this iommu in iommu_bmp, update iommu count
Sheng Yang58c610b2009-03-18 15:33:05 +08003831 * and capabilities
Weidong Hanc7151a82008-12-08 22:51:37 +08003832 */
3833 spin_lock_irqsave(&domain->iommu_lock, flags2);
3834 if (test_and_clear_bit(iommu->seq_id,
Mike Travis1b198bb2012-03-05 15:05:16 -08003835 domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08003836 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003837 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003838 }
3839 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
3840
3841 free_devinfo_mem(info);
3842 spin_lock_irqsave(&device_domain_lock, flags1);
3843 }
3844 spin_unlock_irqrestore(&device_domain_lock, flags1);
3845}
3846
Weidong Han5e98c4b2008-12-08 23:03:27 +08003847/* domain id for virtual machine, it won't be set in context */
Jiang Liu18d99162014-01-06 14:18:10 +08003848static atomic_t vm_domid = ATOMIC_INIT(0);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003849
3850static struct dmar_domain *iommu_alloc_vm_domain(void)
3851{
3852 struct dmar_domain *domain;
3853
3854 domain = alloc_domain_mem();
3855 if (!domain)
3856 return NULL;
3857
Jiang Liu18d99162014-01-06 14:18:10 +08003858 domain->id = atomic_inc_return(&vm_domid);
Suresh Siddha4c923d42009-10-02 11:01:24 -07003859 domain->nid = -1;
Mike Travis1b198bb2012-03-05 15:05:16 -08003860 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003861 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
3862
3863 return domain;
3864}
3865
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003866static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003867{
3868 int adjust_width;
3869
3870 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003871 spin_lock_init(&domain->iommu_lock);
3872
3873 domain_reserve_special_ranges(domain);
3874
3875 /* calculate AGAW */
3876 domain->gaw = guest_width;
3877 adjust_width = guestwidth_to_adjustwidth(guest_width);
3878 domain->agaw = width_to_agaw(adjust_width);
3879
3880 INIT_LIST_HEAD(&domain->devices);
3881
3882 domain->iommu_count = 0;
3883 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003884 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003885 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003886 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003887 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003888
3889 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003890 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003891 if (!domain->pgd)
3892 return -ENOMEM;
3893 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3894 return 0;
3895}
3896
3897static void iommu_free_vm_domain(struct dmar_domain *domain)
3898{
3899 unsigned long flags;
3900 struct dmar_drhd_unit *drhd;
3901 struct intel_iommu *iommu;
3902 unsigned long i;
3903 unsigned long ndomains;
3904
Jiang Liu7c919772014-01-06 14:18:18 +08003905 for_each_active_iommu(iommu, drhd) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003906 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08003907 for_each_set_bit(i, iommu->domain_ids, ndomains) {
Weidong Han5e98c4b2008-12-08 23:03:27 +08003908 if (iommu->domains[i] == domain) {
3909 spin_lock_irqsave(&iommu->lock, flags);
3910 clear_bit(i, iommu->domain_ids);
3911 iommu->domains[i] = NULL;
3912 spin_unlock_irqrestore(&iommu->lock, flags);
3913 break;
3914 }
Weidong Han5e98c4b2008-12-08 23:03:27 +08003915 }
3916 }
3917}
3918
3919static void vm_domain_exit(struct dmar_domain *domain)
3920{
Weidong Han5e98c4b2008-12-08 23:03:27 +08003921 /* Domain 0 is reserved, so dont process it */
3922 if (!domain)
3923 return;
3924
3925 vm_domain_remove_all_dev_info(domain);
3926 /* destroy iovas */
3927 put_iova_domain(&domain->iovad);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003928
3929 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01003930 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003931
3932 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01003933 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Weidong Han5e98c4b2008-12-08 23:03:27 +08003934
3935 iommu_free_vm_domain(domain);
3936 free_domain_mem(domain);
3937}
3938
Joerg Roedel5d450802008-12-03 14:52:32 +01003939static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003940{
Joerg Roedel5d450802008-12-03 14:52:32 +01003941 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003942
Joerg Roedel5d450802008-12-03 14:52:32 +01003943 dmar_domain = iommu_alloc_vm_domain();
3944 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003945 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003946 "intel_iommu_domain_init: dmar_domain == NULL\n");
3947 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003948 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003949 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003950 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003951 "intel_iommu_domain_init() failed\n");
3952 vm_domain_exit(dmar_domain);
3953 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003954 }
Allen Kay8140a952011-10-14 12:32:17 -07003955 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003956 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003957
Joerg Roedel8a0e7152012-01-26 19:40:54 +01003958 domain->geometry.aperture_start = 0;
3959 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
3960 domain->geometry.force_aperture = true;
3961
Joerg Roedel5d450802008-12-03 14:52:32 +01003962 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003963}
Kay, Allen M38717942008-09-09 18:37:29 +03003964
Joerg Roedel5d450802008-12-03 14:52:32 +01003965static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003966{
Joerg Roedel5d450802008-12-03 14:52:32 +01003967 struct dmar_domain *dmar_domain = domain->priv;
3968
3969 domain->priv = NULL;
3970 vm_domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003971}
Kay, Allen M38717942008-09-09 18:37:29 +03003972
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003973static int intel_iommu_attach_device(struct iommu_domain *domain,
3974 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003975{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003976 struct dmar_domain *dmar_domain = domain->priv;
3977 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003978 struct intel_iommu *iommu;
3979 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03003980
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003981 /* normally pdev is not mapped */
3982 if (unlikely(domain_context_mapped(pdev))) {
3983 struct dmar_domain *old_domain;
3984
3985 old_domain = find_domain(pdev);
3986 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003987 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3988 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3989 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003990 else
3991 domain_remove_dev_info(old_domain);
3992 }
3993 }
3994
David Woodhouse276dbf992009-04-04 01:45:37 +01003995 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3996 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003997 if (!iommu)
3998 return -ENODEV;
3999
4000 /* check if this iommu agaw is sufficient for max mapped address */
4001 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01004002 if (addr_width > cap_mgaw(iommu->cap))
4003 addr_width = cap_mgaw(iommu->cap);
4004
4005 if (dmar_domain->max_addr > (1LL << addr_width)) {
4006 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004007 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01004008 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004009 return -EFAULT;
4010 }
Tom Lyona99c47a2010-05-17 08:20:45 +01004011 dmar_domain->gaw = addr_width;
4012
4013 /*
4014 * Knock out extra levels of page tables if necessary
4015 */
4016 while (iommu->agaw < dmar_domain->agaw) {
4017 struct dma_pte *pte;
4018
4019 pte = dmar_domain->pgd;
4020 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08004021 dmar_domain->pgd = (struct dma_pte *)
4022 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01004023 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01004024 }
4025 dmar_domain->agaw--;
4026 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004027
David Woodhouse5fe60f42009-08-09 10:53:41 +01004028 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004029}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004030
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004031static void intel_iommu_detach_device(struct iommu_domain *domain,
4032 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004033{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004034 struct dmar_domain *dmar_domain = domain->priv;
4035 struct pci_dev *pdev = to_pci_dev(dev);
4036
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004037 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03004038}
Kay, Allen M38717942008-09-09 18:37:29 +03004039
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004040static int intel_iommu_map(struct iommu_domain *domain,
4041 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004042 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03004043{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004044 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004045 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004046 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004047 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004048
Joerg Roedeldde57a22008-12-03 15:04:09 +01004049 if (iommu_prot & IOMMU_READ)
4050 prot |= DMA_PTE_READ;
4051 if (iommu_prot & IOMMU_WRITE)
4052 prot |= DMA_PTE_WRITE;
Sheng Yang9cf066972009-03-18 15:33:07 +08004053 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4054 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004055
David Woodhouse163cc522009-06-28 00:51:17 +01004056 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004057 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004058 u64 end;
4059
4060 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01004061 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004062 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004063 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004064 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004065 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004066 return -EFAULT;
4067 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004068 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004069 }
David Woodhousead051222009-06-28 14:22:28 +01004070 /* Round up size to next multiple of PAGE_SIZE, if it and
4071 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004072 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004073 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4074 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004075 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004076}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004077
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004078static size_t intel_iommu_unmap(struct iommu_domain *domain,
4079 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004080{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004081 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07004082 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01004083
Allen Kay292827c2011-10-14 12:31:54 -07004084 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004085 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004086
David Woodhouse163cc522009-06-28 00:51:17 +01004087 if (dmar_domain->max_addr == iova + size)
4088 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004089
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004090 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004091}
Kay, Allen M38717942008-09-09 18:37:29 +03004092
Joerg Roedeld14d6572008-12-03 15:06:57 +01004093static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
Varun Sethibb5547ac2013-03-29 01:23:58 +05304094 dma_addr_t iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004095{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004096 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004097 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004098 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004099
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004100 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004101 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004102 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004103
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004104 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004105}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004106
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004107static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4108 unsigned long cap)
4109{
4110 struct dmar_domain *dmar_domain = domain->priv;
4111
4112 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4113 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004114 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004115 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004116
4117 return 0;
4118}
4119
Alex Williamson783f1572012-05-30 14:19:43 -06004120#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4121
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004122static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004123{
4124 struct pci_dev *pdev = to_pci_dev(dev);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004125 struct pci_dev *bridge, *dma_pdev = NULL;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004126 struct iommu_group *group;
4127 int ret;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004128
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004129 if (!device_to_iommu(pci_domain_nr(pdev->bus),
4130 pdev->bus->number, pdev->devfn))
Alex Williamson70ae6f02011-10-21 15:56:11 -04004131 return -ENODEV;
4132
4133 bridge = pci_find_upstream_pcie_bridge(pdev);
4134 if (bridge) {
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004135 if (pci_is_pcie(bridge))
4136 dma_pdev = pci_get_domain_bus_and_slot(
4137 pci_domain_nr(pdev->bus),
4138 bridge->subordinate->number, 0);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004139 if (!dma_pdev)
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004140 dma_pdev = pci_dev_get(bridge);
4141 } else
4142 dma_pdev = pci_dev_get(pdev);
4143
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004144 /* Account for quirked devices */
Alex Williamson783f1572012-05-30 14:19:43 -06004145 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4146
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004147 /*
4148 * If it's a multifunction device that does not support our
Alex Williamsonc14d2692013-05-30 12:39:18 -06004149 * required ACS flags, add to the same group as lowest numbered
4150 * function that also does not suport the required ACS flags.
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004151 */
Alex Williamson783f1572012-05-30 14:19:43 -06004152 if (dma_pdev->multifunction &&
Alex Williamsonc14d2692013-05-30 12:39:18 -06004153 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
4154 u8 i, slot = PCI_SLOT(dma_pdev->devfn);
4155
4156 for (i = 0; i < 8; i++) {
4157 struct pci_dev *tmp;
4158
4159 tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
4160 if (!tmp)
4161 continue;
4162
4163 if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
4164 swap_pci_ref(&dma_pdev, tmp);
4165 break;
4166 }
4167 pci_dev_put(tmp);
4168 }
4169 }
Alex Williamson783f1572012-05-30 14:19:43 -06004170
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004171 /*
4172 * Devices on the root bus go through the iommu. If that's not us,
4173 * find the next upstream device and test ACS up to the root bus.
4174 * Finding the next device may require skipping virtual buses.
4175 */
Alex Williamson783f1572012-05-30 14:19:43 -06004176 while (!pci_is_root_bus(dma_pdev->bus)) {
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004177 struct pci_bus *bus = dma_pdev->bus;
4178
4179 while (!bus->self) {
4180 if (!pci_is_root_bus(bus))
4181 bus = bus->parent;
4182 else
4183 goto root_bus;
4184 }
4185
4186 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
Alex Williamson783f1572012-05-30 14:19:43 -06004187 break;
4188
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004189 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
Alex Williamson70ae6f02011-10-21 15:56:11 -04004190 }
4191
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004192root_bus:
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004193 group = iommu_group_get(&dma_pdev->dev);
4194 pci_dev_put(dma_pdev);
4195 if (!group) {
4196 group = iommu_group_alloc();
4197 if (IS_ERR(group))
4198 return PTR_ERR(group);
4199 }
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004200
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004201 ret = iommu_group_add_device(group, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004202
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004203 iommu_group_put(group);
4204 return ret;
4205}
4206
4207static void intel_iommu_remove_device(struct device *dev)
4208{
4209 iommu_group_remove_device(dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004210}
4211
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004212static struct iommu_ops intel_iommu_ops = {
4213 .domain_init = intel_iommu_domain_init,
4214 .domain_destroy = intel_iommu_domain_destroy,
4215 .attach_dev = intel_iommu_attach_device,
4216 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004217 .map = intel_iommu_map,
4218 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004219 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004220 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004221 .add_device = intel_iommu_add_device,
4222 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004223 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004224};
David Woodhouse9af88142009-02-13 23:18:03 +00004225
Daniel Vetter94526182013-01-20 23:50:13 +01004226static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4227{
4228 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4229 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4230 dmar_map_gfx = 0;
4231}
4232
4233DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4234DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4235DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4236DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4237DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4238DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4239DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4240
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004241static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004242{
4243 /*
4244 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004245 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004246 */
4247 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4248 rwbf_quirk = 1;
4249}
4250
4251DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004252DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4253DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4254DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4255DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4256DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4257DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004258
Adam Jacksoneecfd572010-08-25 21:17:34 +01004259#define GGC 0x52
4260#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4261#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4262#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4263#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4264#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4265#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4266#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4267#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4268
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004269static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004270{
4271 unsigned short ggc;
4272
Adam Jacksoneecfd572010-08-25 21:17:34 +01004273 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004274 return;
4275
Adam Jacksoneecfd572010-08-25 21:17:34 +01004276 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004277 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4278 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004279 } else if (dmar_map_gfx) {
4280 /* we have to ensure the gfx device is idle before we flush */
4281 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4282 intel_iommu_strict = 1;
4283 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004284}
4285DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4286DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4287DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4288DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4289
David Woodhousee0fc7e02009-09-30 09:12:17 -07004290/* On Tylersburg chipsets, some BIOSes have been known to enable the
4291 ISOCH DMAR unit for the Azalia sound device, but not give it any
4292 TLB entries, which causes it to deadlock. Check for that. We do
4293 this in a function called from init_dmars(), instead of in a PCI
4294 quirk, because we don't want to print the obnoxious "BIOS broken"
4295 message if VT-d is actually disabled.
4296*/
4297static void __init check_tylersburg_isoch(void)
4298{
4299 struct pci_dev *pdev;
4300 uint32_t vtisochctrl;
4301
4302 /* If there's no Azalia in the system anyway, forget it. */
4303 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4304 if (!pdev)
4305 return;
4306 pci_dev_put(pdev);
4307
4308 /* System Management Registers. Might be hidden, in which case
4309 we can't do the sanity check. But that's OK, because the
4310 known-broken BIOSes _don't_ actually hide it, so far. */
4311 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4312 if (!pdev)
4313 return;
4314
4315 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4316 pci_dev_put(pdev);
4317 return;
4318 }
4319
4320 pci_dev_put(pdev);
4321
4322 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4323 if (vtisochctrl & 1)
4324 return;
4325
4326 /* Drop all bits other than the number of TLB entries */
4327 vtisochctrl &= 0x1c;
4328
4329 /* If we have the recommended number of TLB entries (16), fine. */
4330 if (vtisochctrl == 0x10)
4331 return;
4332
4333 /* Zero TLB entries? You get to ride the short bus to school. */
4334 if (!vtisochctrl) {
4335 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4336 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4337 dmi_get_system_info(DMI_BIOS_VENDOR),
4338 dmi_get_system_info(DMI_BIOS_VERSION),
4339 dmi_get_system_info(DMI_PRODUCT_VERSION));
4340 iommu_identity_mapping |= IDENTMAP_AZALIA;
4341 return;
4342 }
4343
4344 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4345 vtisochctrl);
4346}