blob: 67247724179131f7711d9d34eef24be4241a7dad [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
Jiang Liu92d03cc2014-02-19 14:07:28 +0800428static void domain_exit(struct dmar_domain *domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700429static void domain_remove_dev_info(struct dmar_domain *domain);
Jiang Liub94e4112014-02-19 14:07:25 +0800430static void domain_remove_one_dev_info(struct dmar_domain *domain,
431 struct pci_dev *pdev);
Jiang Liu92d03cc2014-02-19 14:07:28 +0800432static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
433 struct pci_dev *pdev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700434
Suresh Siddhad3f13812011-08-23 17:05:25 -0700435#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800436int dmar_disabled = 0;
437#else
438int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700439#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800440
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200441int intel_iommu_enabled = 0;
442EXPORT_SYMBOL_GPL(intel_iommu_enabled);
443
David Woodhouse2d9e6672010-06-15 10:57:57 +0100444static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700445static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800446static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100447static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700448
David Woodhousec0771df2011-10-14 20:59:46 +0100449int intel_iommu_gfx_mapped;
450EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
451
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700452#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
453static DEFINE_SPINLOCK(device_domain_lock);
454static LIST_HEAD(device_domain_list);
455
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100456static struct iommu_ops intel_iommu_ops;
457
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700458static int __init intel_iommu_setup(char *str)
459{
460 if (!str)
461 return -EINVAL;
462 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800463 if (!strncmp(str, "on", 2)) {
464 dmar_disabled = 0;
465 printk(KERN_INFO "Intel-IOMMU: enabled\n");
466 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700467 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800468 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700469 } else if (!strncmp(str, "igfx_off", 8)) {
470 dmar_map_gfx = 0;
471 printk(KERN_INFO
472 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700473 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800474 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700475 "Intel-IOMMU: Forcing DAC for PCI devices\n");
476 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800477 } else if (!strncmp(str, "strict", 6)) {
478 printk(KERN_INFO
479 "Intel-IOMMU: disable batched IOTLB flush\n");
480 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100481 } else if (!strncmp(str, "sp_off", 6)) {
482 printk(KERN_INFO
483 "Intel-IOMMU: disable supported super page\n");
484 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700485 }
486
487 str += strcspn(str, ",");
488 while (*str == ',')
489 str++;
490 }
491 return 0;
492}
493__setup("intel_iommu=", intel_iommu_setup);
494
495static struct kmem_cache *iommu_domain_cache;
496static struct kmem_cache *iommu_devinfo_cache;
497static struct kmem_cache *iommu_iova_cache;
498
Suresh Siddha4c923d42009-10-02 11:01:24 -0700499static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700500{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700501 struct page *page;
502 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700503
Suresh Siddha4c923d42009-10-02 11:01:24 -0700504 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
505 if (page)
506 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700507 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700508}
509
510static inline void free_pgtable_page(void *vaddr)
511{
512 free_page((unsigned long)vaddr);
513}
514
515static inline void *alloc_domain_mem(void)
516{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900517 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700518}
519
Kay, Allen M38717942008-09-09 18:37:29 +0300520static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700521{
522 kmem_cache_free(iommu_domain_cache, vaddr);
523}
524
525static inline void * alloc_devinfo_mem(void)
526{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900527 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700528}
529
530static inline void free_devinfo_mem(void *vaddr)
531{
532 kmem_cache_free(iommu_devinfo_cache, vaddr);
533}
534
535struct iova *alloc_iova_mem(void)
536{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900537 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700538}
539
540void free_iova_mem(struct iova *iova)
541{
542 kmem_cache_free(iommu_iova_cache, iova);
543}
544
Weidong Han1b573682008-12-08 15:34:06 +0800545
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700546static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800547{
548 unsigned long sagaw;
549 int agaw = -1;
550
551 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700552 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800553 agaw >= 0; agaw--) {
554 if (test_bit(agaw, &sagaw))
555 break;
556 }
557
558 return agaw;
559}
560
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700561/*
562 * Calculate max SAGAW for each iommu.
563 */
564int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
565{
566 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
567}
568
569/*
570 * calculate agaw for each iommu.
571 * "SAGAW" may be different across iommus, use a default agaw, and
572 * get a supported less agaw for iommus that don't support the default agaw.
573 */
574int iommu_calculate_agaw(struct intel_iommu *iommu)
575{
576 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
577}
578
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700579/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800580static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
581{
582 int iommu_id;
583
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700584 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800585 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700586 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800587
Mike Travis1b198bb2012-03-05 15:05:16 -0800588 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800589 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
590 return NULL;
591
592 return g_iommus[iommu_id];
593}
594
Weidong Han8e6040972008-12-08 15:49:06 +0800595static void domain_update_iommu_coherency(struct dmar_domain *domain)
596{
597 int i;
598
Alex Williamson2e12bc22011-11-11 17:26:44 -0700599 i = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
600
601 domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0;
Weidong Han8e6040972008-12-08 15:49:06 +0800602
Mike Travis1b198bb2012-03-05 15:05:16 -0800603 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e6040972008-12-08 15:49:06 +0800604 if (!ecap_coherent(g_iommus[i]->ecap)) {
605 domain->iommu_coherency = 0;
606 break;
607 }
Weidong Han8e6040972008-12-08 15:49:06 +0800608 }
609}
610
Sheng Yang58c610b2009-03-18 15:33:05 +0800611static void domain_update_iommu_snooping(struct dmar_domain *domain)
612{
613 int i;
614
615 domain->iommu_snooping = 1;
616
Mike Travis1b198bb2012-03-05 15:05:16 -0800617 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800618 if (!ecap_sc_support(g_iommus[i]->ecap)) {
619 domain->iommu_snooping = 0;
620 break;
621 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800622 }
623}
624
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100625static void domain_update_iommu_superpage(struct dmar_domain *domain)
626{
Allen Kay8140a952011-10-14 12:32:17 -0700627 struct dmar_drhd_unit *drhd;
628 struct intel_iommu *iommu = NULL;
629 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100630
631 if (!intel_iommu_superpage) {
632 domain->iommu_superpage = 0;
633 return;
634 }
635
Allen Kay8140a952011-10-14 12:32:17 -0700636 /* set iommu_superpage to the smallest common denominator */
637 for_each_active_iommu(iommu, drhd) {
638 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100639 if (!mask) {
640 break;
641 }
642 }
643 domain->iommu_superpage = fls(mask);
644}
645
Sheng Yang58c610b2009-03-18 15:33:05 +0800646/* Some capabilities may be different across iommus */
647static void domain_update_iommu_cap(struct dmar_domain *domain)
648{
649 domain_update_iommu_coherency(domain);
650 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100651 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800652}
653
David Woodhouse276dbf992009-04-04 01:45:37 +0100654static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800655{
656 struct dmar_drhd_unit *drhd = NULL;
657 int i;
658
Jiang Liu7c919772014-01-06 14:18:18 +0800659 for_each_active_drhd_unit(drhd) {
David Woodhouse276dbf992009-04-04 01:45:37 +0100660 if (segment != drhd->segment)
661 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800662
David Woodhouse924b6232009-04-04 00:39:25 +0100663 for (i = 0; i < drhd->devices_cnt; i++) {
Dirk Hohndel288e4872009-01-11 15:33:51 +0000664 if (drhd->devices[i] &&
665 drhd->devices[i]->bus->number == bus &&
Weidong Hanc7151a82008-12-08 22:51:37 +0800666 drhd->devices[i]->devfn == devfn)
667 return drhd->iommu;
David Woodhouse4958c5d2009-04-06 13:30:01 -0700668 if (drhd->devices[i] &&
669 drhd->devices[i]->subordinate &&
David Woodhouse924b6232009-04-04 00:39:25 +0100670 drhd->devices[i]->subordinate->number <= bus &&
Yinghai Lub918c622012-05-17 18:51:11 -0700671 drhd->devices[i]->subordinate->busn_res.end >= bus)
David Woodhouse924b6232009-04-04 00:39:25 +0100672 return drhd->iommu;
673 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800674
675 if (drhd->include_all)
676 return drhd->iommu;
677 }
678
679 return NULL;
680}
681
Weidong Han5331fe62008-12-08 23:00:00 +0800682static void domain_flush_cache(struct dmar_domain *domain,
683 void *addr, int size)
684{
685 if (!domain->iommu_coherency)
686 clflush_cache_range(addr, size);
687}
688
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700689/* Gets context entry for a given bus and devfn */
690static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
691 u8 bus, u8 devfn)
692{
693 struct root_entry *root;
694 struct context_entry *context;
695 unsigned long phy_addr;
696 unsigned long flags;
697
698 spin_lock_irqsave(&iommu->lock, flags);
699 root = &iommu->root_entry[bus];
700 context = get_context_addr_from_root(root);
701 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700702 context = (struct context_entry *)
703 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700704 if (!context) {
705 spin_unlock_irqrestore(&iommu->lock, flags);
706 return NULL;
707 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700708 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700709 phy_addr = virt_to_phys((void *)context);
710 set_root_value(root, phy_addr);
711 set_root_present(root);
712 __iommu_flush_cache(iommu, root, sizeof(*root));
713 }
714 spin_unlock_irqrestore(&iommu->lock, flags);
715 return &context[devfn];
716}
717
718static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
719{
720 struct root_entry *root;
721 struct context_entry *context;
722 int ret;
723 unsigned long flags;
724
725 spin_lock_irqsave(&iommu->lock, flags);
726 root = &iommu->root_entry[bus];
727 context = get_context_addr_from_root(root);
728 if (!context) {
729 ret = 0;
730 goto out;
731 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000732 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700733out:
734 spin_unlock_irqrestore(&iommu->lock, flags);
735 return ret;
736}
737
738static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
739{
740 struct root_entry *root;
741 struct context_entry *context;
742 unsigned long flags;
743
744 spin_lock_irqsave(&iommu->lock, flags);
745 root = &iommu->root_entry[bus];
746 context = get_context_addr_from_root(root);
747 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000748 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700749 __iommu_flush_cache(iommu, &context[devfn], \
750 sizeof(*context));
751 }
752 spin_unlock_irqrestore(&iommu->lock, flags);
753}
754
755static void free_context_table(struct intel_iommu *iommu)
756{
757 struct root_entry *root;
758 int i;
759 unsigned long flags;
760 struct context_entry *context;
761
762 spin_lock_irqsave(&iommu->lock, flags);
763 if (!iommu->root_entry) {
764 goto out;
765 }
766 for (i = 0; i < ROOT_ENTRY_NR; i++) {
767 root = &iommu->root_entry[i];
768 context = get_context_addr_from_root(root);
769 if (context)
770 free_pgtable_page(context);
771 }
772 free_pgtable_page(iommu->root_entry);
773 iommu->root_entry = NULL;
774out:
775 spin_unlock_irqrestore(&iommu->lock, flags);
776}
777
David Woodhouseb026fd22009-06-28 10:37:25 +0100778static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
Allen Kay4399c8b2011-10-14 12:32:46 -0700779 unsigned long pfn, int target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700780{
David Woodhouseb026fd22009-06-28 10:37:25 +0100781 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700782 struct dma_pte *parent, *pte = NULL;
783 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700784 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700785
786 BUG_ON(!domain->pgd);
Julian Stecklinaf9423602013-10-09 10:03:52 +0200787
788 if (addr_width < BITS_PER_LONG && pfn >> addr_width)
789 /* Address beyond IOMMU's addressing capabilities. */
790 return NULL;
791
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700792 parent = domain->pgd;
793
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700794 while (level > 0) {
795 void *tmp_page;
796
David Woodhouseb026fd22009-06-28 10:37:25 +0100797 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700798 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700799 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100800 break;
801 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700802 break;
803
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000804 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100805 uint64_t pteval;
806
Suresh Siddha4c923d42009-10-02 11:01:24 -0700807 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700808
David Woodhouse206a73c12009-07-01 19:30:28 +0100809 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700810 return NULL;
David Woodhouse206a73c12009-07-01 19:30:28 +0100811
David Woodhousec85994e2009-07-01 19:21:24 +0100812 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400813 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 +0100814 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
815 /* Someone else set it while we were thinking; use theirs. */
816 free_pgtable_page(tmp_page);
817 } else {
818 dma_pte_addr(pte);
819 domain_flush_cache(domain, pte, sizeof(*pte));
820 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700821 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000822 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700823 level--;
824 }
825
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700826 return pte;
827}
828
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100829
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700830/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100831static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
832 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100833 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700834{
835 struct dma_pte *parent, *pte = NULL;
836 int total = agaw_to_level(domain->agaw);
837 int offset;
838
839 parent = domain->pgd;
840 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100841 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700842 pte = &parent[offset];
843 if (level == total)
844 return pte;
845
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100846 if (!dma_pte_present(pte)) {
847 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700848 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100849 }
850
851 if (pte->val & DMA_PTE_LARGE_PAGE) {
852 *large_page = total;
853 return pte;
854 }
855
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000856 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700857 total--;
858 }
859 return NULL;
860}
861
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700862/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700863static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100864 unsigned long start_pfn,
865 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700866{
David Woodhouse04b18e62009-06-27 19:15:01 +0100867 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100868 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100869 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700870
David Woodhouse04b18e62009-06-27 19:15:01 +0100871 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100872 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700873 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100874
David Woodhouse04b18e62009-06-27 19:15:01 +0100875 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700876 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100877 large_page = 1;
878 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100879 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100880 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100881 continue;
882 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100883 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100884 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100885 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100886 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100887 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
888
David Woodhouse310a5ab2009-06-28 18:52:20 +0100889 domain_flush_cache(domain, first_pte,
890 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700891
892 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700893
Jiang Liu5c645b32014-01-06 14:18:12 +0800894 return min_t(int, (large_page - 1) * 9, MAX_AGAW_PFN_WIDTH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700895}
896
Alex Williamson3269ee02013-06-15 10:27:19 -0600897static void dma_pte_free_level(struct dmar_domain *domain, int level,
898 struct dma_pte *pte, unsigned long pfn,
899 unsigned long start_pfn, unsigned long last_pfn)
900{
901 pfn = max(start_pfn, pfn);
902 pte = &pte[pfn_level_offset(pfn, level)];
903
904 do {
905 unsigned long level_pfn;
906 struct dma_pte *level_pte;
907
908 if (!dma_pte_present(pte) || dma_pte_superpage(pte))
909 goto next;
910
911 level_pfn = pfn & level_mask(level - 1);
912 level_pte = phys_to_virt(dma_pte_addr(pte));
913
914 if (level > 2)
915 dma_pte_free_level(domain, level - 1, level_pte,
916 level_pfn, start_pfn, last_pfn);
917
918 /* If range covers entire pagetable, free it */
919 if (!(start_pfn > level_pfn ||
Alex Williamson08336fd2014-01-21 15:48:18 -0800920 last_pfn < level_pfn + level_size(level) - 1)) {
Alex Williamson3269ee02013-06-15 10:27:19 -0600921 dma_clear_pte(pte);
922 domain_flush_cache(domain, pte, sizeof(*pte));
923 free_pgtable_page(level_pte);
924 }
925next:
926 pfn += level_size(level);
927 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
928}
929
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700930/* free page table pages. last level pte should already be cleared */
931static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100932 unsigned long start_pfn,
933 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700934{
David Woodhouse6660c632009-06-27 22:41:00 +0100935 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700936
David Woodhouse6660c632009-06-27 22:41:00 +0100937 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
938 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700939 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700940
David Woodhousef3a0a522009-06-30 03:40:07 +0100941 /* We don't need lock here; nobody else touches the iova range */
Alex Williamson3269ee02013-06-15 10:27:19 -0600942 dma_pte_free_level(domain, agaw_to_level(domain->agaw),
943 domain->pgd, 0, start_pfn, last_pfn);
David Woodhouse6660c632009-06-27 22:41:00 +0100944
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700945 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100946 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700947 free_pgtable_page(domain->pgd);
948 domain->pgd = NULL;
949 }
950}
951
952/* iommu handling */
953static int iommu_alloc_root_entry(struct intel_iommu *iommu)
954{
955 struct root_entry *root;
956 unsigned long flags;
957
Suresh Siddha4c923d42009-10-02 11:01:24 -0700958 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700959 if (!root)
960 return -ENOMEM;
961
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700962 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700963
964 spin_lock_irqsave(&iommu->lock, flags);
965 iommu->root_entry = root;
966 spin_unlock_irqrestore(&iommu->lock, flags);
967
968 return 0;
969}
970
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700971static void iommu_set_root_entry(struct intel_iommu *iommu)
972{
973 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100974 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700975 unsigned long flag;
976
977 addr = iommu->root_entry;
978
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200979 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700980 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
981
David Woodhousec416daa2009-05-10 20:30:58 +0100982 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700983
984 /* Make sure hardware complete it */
985 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100986 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700987
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200988 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700989}
990
991static void iommu_flush_write_buffer(struct intel_iommu *iommu)
992{
993 u32 val;
994 unsigned long flag;
995
David Woodhouse9af88142009-02-13 23:18:03 +0000996 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700997 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700998
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200999 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +01001000 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001001
1002 /* Make sure hardware complete it */
1003 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001004 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001005
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001006 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001007}
1008
1009/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001010static void __iommu_flush_context(struct intel_iommu *iommu,
1011 u16 did, u16 source_id, u8 function_mask,
1012 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001013{
1014 u64 val = 0;
1015 unsigned long flag;
1016
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001017 switch (type) {
1018 case DMA_CCMD_GLOBAL_INVL:
1019 val = DMA_CCMD_GLOBAL_INVL;
1020 break;
1021 case DMA_CCMD_DOMAIN_INVL:
1022 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1023 break;
1024 case DMA_CCMD_DEVICE_INVL:
1025 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1026 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1027 break;
1028 default:
1029 BUG();
1030 }
1031 val |= DMA_CCMD_ICC;
1032
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001033 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001034 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1035
1036 /* Make sure hardware complete it */
1037 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1038 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1039
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001040 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001041}
1042
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001043/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001044static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1045 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001046{
1047 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1048 u64 val = 0, val_iva = 0;
1049 unsigned long flag;
1050
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001051 switch (type) {
1052 case DMA_TLB_GLOBAL_FLUSH:
1053 /* global flush doesn't need set IVA_REG */
1054 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1055 break;
1056 case DMA_TLB_DSI_FLUSH:
1057 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1058 break;
1059 case DMA_TLB_PSI_FLUSH:
1060 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1061 /* Note: always flush non-leaf currently */
1062 val_iva = size_order | addr;
1063 break;
1064 default:
1065 BUG();
1066 }
1067 /* Note: set drain read/write */
1068#if 0
1069 /*
1070 * This is probably to be super secure.. Looks like we can
1071 * ignore it without any impact.
1072 */
1073 if (cap_read_drain(iommu->cap))
1074 val |= DMA_TLB_READ_DRAIN;
1075#endif
1076 if (cap_write_drain(iommu->cap))
1077 val |= DMA_TLB_WRITE_DRAIN;
1078
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001079 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001080 /* Note: Only uses first TLB reg currently */
1081 if (val_iva)
1082 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1083 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1084
1085 /* Make sure hardware complete it */
1086 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1087 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1088
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001089 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001090
1091 /* check IOTLB invalidation granularity */
1092 if (DMA_TLB_IAIG(val) == 0)
1093 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1094 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1095 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001096 (unsigned long long)DMA_TLB_IIRG(type),
1097 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001098}
1099
Yu Zhao93a23a72009-05-18 13:51:37 +08001100static struct device_domain_info *iommu_support_dev_iotlb(
1101 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001102{
Yu Zhao93a23a72009-05-18 13:51:37 +08001103 int found = 0;
1104 unsigned long flags;
1105 struct device_domain_info *info;
1106 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1107
1108 if (!ecap_dev_iotlb_support(iommu->ecap))
1109 return NULL;
1110
1111 if (!iommu->qi)
1112 return NULL;
1113
1114 spin_lock_irqsave(&device_domain_lock, flags);
1115 list_for_each_entry(info, &domain->devices, link)
1116 if (info->bus == bus && info->devfn == devfn) {
1117 found = 1;
1118 break;
1119 }
1120 spin_unlock_irqrestore(&device_domain_lock, flags);
1121
1122 if (!found || !info->dev)
1123 return NULL;
1124
1125 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1126 return NULL;
1127
1128 if (!dmar_find_matched_atsr_unit(info->dev))
1129 return NULL;
1130
1131 info->iommu = iommu;
1132
1133 return info;
1134}
1135
1136static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1137{
1138 if (!info)
1139 return;
1140
1141 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1142}
1143
1144static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1145{
1146 if (!info->dev || !pci_ats_enabled(info->dev))
1147 return;
1148
1149 pci_disable_ats(info->dev);
1150}
1151
1152static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1153 u64 addr, unsigned mask)
1154{
1155 u16 sid, qdep;
1156 unsigned long flags;
1157 struct device_domain_info *info;
1158
1159 spin_lock_irqsave(&device_domain_lock, flags);
1160 list_for_each_entry(info, &domain->devices, link) {
1161 if (!info->dev || !pci_ats_enabled(info->dev))
1162 continue;
1163
1164 sid = info->bus << 8 | info->devfn;
1165 qdep = pci_ats_queue_depth(info->dev);
1166 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1167 }
1168 spin_unlock_irqrestore(&device_domain_lock, flags);
1169}
1170
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001171static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001172 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001173{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001174 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001175 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001176
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001177 BUG_ON(pages == 0);
1178
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001179 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001180 * Fallback to domain selective flush if no PSI support or the size is
1181 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001182 * PSI requires page size to be 2 ^ x, and the base address is naturally
1183 * aligned to the size
1184 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001185 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1186 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001187 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001188 else
1189 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1190 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001191
1192 /*
Nadav Amit82653632010-04-01 13:24:40 +03001193 * In caching mode, changes of pages from non-present to present require
1194 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001195 */
Nadav Amit82653632010-04-01 13:24:40 +03001196 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001197 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001198}
1199
mark grossf8bab732008-02-08 04:18:38 -08001200static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1201{
1202 u32 pmen;
1203 unsigned long flags;
1204
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001205 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001206 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1207 pmen &= ~DMA_PMEN_EPM;
1208 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1209
1210 /* wait for the protected region status bit to clear */
1211 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1212 readl, !(pmen & DMA_PMEN_PRS), pmen);
1213
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001214 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001215}
1216
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001217static int iommu_enable_translation(struct intel_iommu *iommu)
1218{
1219 u32 sts;
1220 unsigned long flags;
1221
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001222 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001223 iommu->gcmd |= DMA_GCMD_TE;
1224 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001225
1226 /* Make sure hardware complete it */
1227 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001228 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001229
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001230 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001231 return 0;
1232}
1233
1234static int iommu_disable_translation(struct intel_iommu *iommu)
1235{
1236 u32 sts;
1237 unsigned long flag;
1238
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001239 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001240 iommu->gcmd &= ~DMA_GCMD_TE;
1241 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1242
1243 /* Make sure hardware complete it */
1244 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001245 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001246
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001247 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001248 return 0;
1249}
1250
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001251
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001252static int iommu_init_domains(struct intel_iommu *iommu)
1253{
1254 unsigned long ndomains;
1255 unsigned long nlongs;
1256
1257 ndomains = cap_ndoms(iommu->cap);
Jiang Liu852bdb02014-01-06 14:18:11 +08001258 pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
1259 iommu->seq_id, ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001260 nlongs = BITS_TO_LONGS(ndomains);
1261
Donald Dutile94a91b52009-08-20 16:51:34 -04001262 spin_lock_init(&iommu->lock);
1263
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001264 /* TBD: there might be 64K domains,
1265 * consider other allocation for future chip
1266 */
1267 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1268 if (!iommu->domain_ids) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001269 pr_err("IOMMU%d: allocating domain id array failed\n",
1270 iommu->seq_id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001271 return -ENOMEM;
1272 }
1273 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1274 GFP_KERNEL);
1275 if (!iommu->domains) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001276 pr_err("IOMMU%d: allocating domain array failed\n",
1277 iommu->seq_id);
1278 kfree(iommu->domain_ids);
1279 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001280 return -ENOMEM;
1281 }
1282
1283 /*
1284 * if Caching mode is set, then invalid translations are tagged
1285 * with domainid 0. Hence we need to pre-allocate it.
1286 */
1287 if (cap_caching_mode(iommu->cap))
1288 set_bit(0, iommu->domain_ids);
1289 return 0;
1290}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001291
Jiang Liua868e6b2014-01-06 14:18:20 +08001292static void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001293{
1294 struct dmar_domain *domain;
Jiang Liu5ced12a2014-01-06 14:18:22 +08001295 int i, count;
Weidong Hanc7151a82008-12-08 22:51:37 +08001296 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001297
Donald Dutile94a91b52009-08-20 16:51:34 -04001298 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001299 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Donald Dutile94a91b52009-08-20 16:51:34 -04001300 domain = iommu->domains[i];
1301 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001302
Donald Dutile94a91b52009-08-20 16:51:34 -04001303 spin_lock_irqsave(&domain->iommu_lock, flags);
Jiang Liu5ced12a2014-01-06 14:18:22 +08001304 count = --domain->iommu_count;
1305 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001306 if (count == 0)
1307 domain_exit(domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001308 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001309 }
1310
1311 if (iommu->gcmd & DMA_GCMD_TE)
1312 iommu_disable_translation(iommu);
1313
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001314 kfree(iommu->domains);
1315 kfree(iommu->domain_ids);
Jiang Liua868e6b2014-01-06 14:18:20 +08001316 iommu->domains = NULL;
1317 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001318
Weidong Hand9630fe2008-12-08 11:06:32 +08001319 g_iommus[iommu->seq_id] = NULL;
1320
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001321 /* free context mapping */
1322 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001323}
1324
Jiang Liu92d03cc2014-02-19 14:07:28 +08001325static struct dmar_domain *alloc_domain(bool vm)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001326{
Jiang Liu92d03cc2014-02-19 14:07:28 +08001327 /* domain id for virtual machine, it won't be set in context */
1328 static atomic_t vm_domid = ATOMIC_INIT(0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001329 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001330
1331 domain = alloc_domain_mem();
1332 if (!domain)
1333 return NULL;
1334
Suresh Siddha4c923d42009-10-02 11:01:24 -07001335 domain->nid = -1;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001336 domain->iommu_count = 0;
Mike Travis1b198bb2012-03-05 15:05:16 -08001337 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001338 domain->flags = 0;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001339 spin_lock_init(&domain->iommu_lock);
1340 INIT_LIST_HEAD(&domain->devices);
1341 if (vm) {
1342 domain->id = atomic_inc_return(&vm_domid);
1343 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
1344 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001345
1346 return domain;
1347}
1348
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001349static int iommu_attach_domain(struct dmar_domain *domain,
1350 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001351{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001352 int num;
1353 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001354 unsigned long flags;
1355
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001356 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001357
1358 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001359
1360 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1361 if (num >= ndomains) {
1362 spin_unlock_irqrestore(&iommu->lock, flags);
1363 printk(KERN_ERR "IOMMU: no free domain ids\n");
1364 return -ENOMEM;
1365 }
1366
1367 domain->id = num;
1368 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001369 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001370 iommu->domains[num] = domain;
1371 spin_unlock_irqrestore(&iommu->lock, flags);
1372
1373 return 0;
1374}
1375
1376static void iommu_detach_domain(struct dmar_domain *domain,
1377 struct intel_iommu *iommu)
1378{
1379 unsigned long flags;
1380 int num, ndomains;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001381
1382 spin_lock_irqsave(&iommu->lock, flags);
1383 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001384 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001385 if (iommu->domains[num] == domain) {
Jiang Liu92d03cc2014-02-19 14:07:28 +08001386 clear_bit(num, iommu->domain_ids);
1387 iommu->domains[num] = NULL;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001388 break;
1389 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001390 }
Weidong Han8c11e792008-12-08 15:29:22 +08001391 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001392}
1393
1394static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001395static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001396
Joseph Cihula51a63e62011-03-21 11:04:24 -07001397static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001398{
1399 struct pci_dev *pdev = NULL;
1400 struct iova *iova;
1401 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001402
David Millerf6611972008-02-06 01:36:23 -08001403 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001404
Mark Gross8a443df2008-03-04 14:59:31 -08001405 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1406 &reserved_rbtree_key);
1407
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001408 /* IOAPIC ranges shouldn't be accessed by DMA */
1409 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1410 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001411 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001412 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001413 return -ENODEV;
1414 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001415
1416 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1417 for_each_pci_dev(pdev) {
1418 struct resource *r;
1419
1420 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1421 r = &pdev->resource[i];
1422 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1423 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001424 iova = reserve_iova(&reserved_iova_list,
1425 IOVA_PFN(r->start),
1426 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001427 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001428 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001429 return -ENODEV;
1430 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001431 }
1432 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001433 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001434}
1435
1436static void domain_reserve_special_ranges(struct dmar_domain *domain)
1437{
1438 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1439}
1440
1441static inline int guestwidth_to_adjustwidth(int gaw)
1442{
1443 int agaw;
1444 int r = (gaw - 12) % 9;
1445
1446 if (r == 0)
1447 agaw = gaw;
1448 else
1449 agaw = gaw + 9 - r;
1450 if (agaw > 64)
1451 agaw = 64;
1452 return agaw;
1453}
1454
1455static int domain_init(struct dmar_domain *domain, int guest_width)
1456{
1457 struct intel_iommu *iommu;
1458 int adjust_width, agaw;
1459 unsigned long sagaw;
1460
David Millerf6611972008-02-06 01:36:23 -08001461 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001462 domain_reserve_special_ranges(domain);
1463
1464 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001465 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001466 if (guest_width > cap_mgaw(iommu->cap))
1467 guest_width = cap_mgaw(iommu->cap);
1468 domain->gaw = guest_width;
1469 adjust_width = guestwidth_to_adjustwidth(guest_width);
1470 agaw = width_to_agaw(adjust_width);
1471 sagaw = cap_sagaw(iommu->cap);
1472 if (!test_bit(agaw, &sagaw)) {
1473 /* hardware doesn't support it, choose a bigger one */
1474 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1475 agaw = find_next_bit(&sagaw, 5, agaw);
1476 if (agaw >= 5)
1477 return -ENODEV;
1478 }
1479 domain->agaw = agaw;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001480
Weidong Han8e6040972008-12-08 15:49:06 +08001481 if (ecap_coherent(iommu->ecap))
1482 domain->iommu_coherency = 1;
1483 else
1484 domain->iommu_coherency = 0;
1485
Sheng Yang58c610b2009-03-18 15:33:05 +08001486 if (ecap_sc_support(iommu->ecap))
1487 domain->iommu_snooping = 1;
1488 else
1489 domain->iommu_snooping = 0;
1490
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001491 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Weidong Hanc7151a82008-12-08 22:51:37 +08001492 domain->iommu_count = 1;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001493 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001494
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001495 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001496 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001497 if (!domain->pgd)
1498 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001499 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001500 return 0;
1501}
1502
1503static void domain_exit(struct dmar_domain *domain)
1504{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001505 struct dmar_drhd_unit *drhd;
1506 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001507
1508 /* Domain 0 is reserved, so dont process it */
1509 if (!domain)
1510 return;
1511
Alex Williamson7b668352011-05-24 12:02:41 +01001512 /* Flush any lazy unmaps that may reference this domain */
1513 if (!intel_iommu_strict)
1514 flush_unmaps_timeout(0);
1515
Jiang Liu92d03cc2014-02-19 14:07:28 +08001516 /* remove associated devices */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001517 domain_remove_dev_info(domain);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001518
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001519 /* destroy iovas */
1520 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001521
1522 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001523 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001524
1525 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001526 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001527
Jiang Liu92d03cc2014-02-19 14:07:28 +08001528 /* clear attached or cached domains */
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001529 for_each_active_iommu(iommu, drhd)
Jiang Liu92d03cc2014-02-19 14:07:28 +08001530 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1531 test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001532 iommu_detach_domain(domain, iommu);
1533
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001534 free_domain_mem(domain);
1535}
1536
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001537static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1538 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001539{
1540 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001541 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001542 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001543 struct dma_pte *pgd;
1544 unsigned long num;
1545 unsigned long ndomains;
1546 int id;
1547 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001548 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001549
1550 pr_debug("Set context mapping for %02x:%02x.%d\n",
1551 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001552
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001553 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001554 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1555 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001556
David Woodhouse276dbf992009-04-04 01:45:37 +01001557 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001558 if (!iommu)
1559 return -ENODEV;
1560
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001561 context = device_to_context_entry(iommu, bus, devfn);
1562 if (!context)
1563 return -ENOMEM;
1564 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001565 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001566 spin_unlock_irqrestore(&iommu->lock, flags);
1567 return 0;
1568 }
1569
Weidong Hanea6606b2008-12-08 23:08:15 +08001570 id = domain->id;
1571 pgd = domain->pgd;
1572
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001573 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1574 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001575 int found = 0;
1576
1577 /* find an available domain id for this device in iommu */
1578 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001579 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001580 if (iommu->domains[num] == domain) {
1581 id = num;
1582 found = 1;
1583 break;
1584 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001585 }
1586
1587 if (found == 0) {
1588 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1589 if (num >= ndomains) {
1590 spin_unlock_irqrestore(&iommu->lock, flags);
1591 printk(KERN_ERR "IOMMU: no free domain ids\n");
1592 return -EFAULT;
1593 }
1594
1595 set_bit(num, iommu->domain_ids);
1596 iommu->domains[num] = domain;
1597 id = num;
1598 }
1599
1600 /* Skip top levels of page tables for
1601 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001602 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001603 */
Chris Wright1672af12009-12-02 12:06:34 -08001604 if (translation != CONTEXT_TT_PASS_THROUGH) {
1605 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1606 pgd = phys_to_virt(dma_pte_addr(pgd));
1607 if (!dma_pte_present(pgd)) {
1608 spin_unlock_irqrestore(&iommu->lock, flags);
1609 return -ENOMEM;
1610 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001611 }
1612 }
1613 }
1614
1615 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001616
Yu Zhao93a23a72009-05-18 13:51:37 +08001617 if (translation != CONTEXT_TT_PASS_THROUGH) {
1618 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1619 translation = info ? CONTEXT_TT_DEV_IOTLB :
1620 CONTEXT_TT_MULTI_LEVEL;
1621 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001622 /*
1623 * In pass through mode, AW must be programmed to indicate the largest
1624 * AGAW value supported by hardware. And ASR is ignored by hardware.
1625 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001626 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001627 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001628 else {
1629 context_set_address_root(context, virt_to_phys(pgd));
1630 context_set_address_width(context, iommu->agaw);
1631 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001632
1633 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001634 context_set_fault_enable(context);
1635 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001636 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001637
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001638 /*
1639 * It's a non-present to present mapping. If hardware doesn't cache
1640 * non-present entry we only need to flush the write-buffer. If the
1641 * _does_ cache non-present entries, then it does so in the special
1642 * domain #0, which we have to flush:
1643 */
1644 if (cap_caching_mode(iommu->cap)) {
1645 iommu->flush.flush_context(iommu, 0,
1646 (((u16)bus) << 8) | devfn,
1647 DMA_CCMD_MASK_NOBIT,
1648 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001649 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001650 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001651 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001652 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001653 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001654 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001655
1656 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001657 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001658 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001659 if (domain->iommu_count == 1)
1660 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001661 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001662 }
1663 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001664 return 0;
1665}
1666
1667static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001668domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1669 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001670{
1671 int ret;
1672 struct pci_dev *tmp, *parent;
1673
David Woodhouse276dbf992009-04-04 01:45:37 +01001674 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001675 pdev->bus->number, pdev->devfn,
1676 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001677 if (ret)
1678 return ret;
1679
1680 /* dependent device mapping */
1681 tmp = pci_find_upstream_pcie_bridge(pdev);
1682 if (!tmp)
1683 return 0;
1684 /* Secondary interface's bus number and devfn 0 */
1685 parent = pdev->bus->self;
1686 while (parent != tmp) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001687 ret = domain_context_mapping_one(domain,
1688 pci_domain_nr(parent->bus),
1689 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001690 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001691 if (ret)
1692 return ret;
1693 parent = parent->bus->self;
1694 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001695 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001696 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001697 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001698 tmp->subordinate->number, 0,
1699 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001700 else /* this is a legacy PCI bridge */
1701 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001702 pci_domain_nr(tmp->bus),
1703 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001704 tmp->devfn,
1705 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001706}
1707
Weidong Han5331fe62008-12-08 23:00:00 +08001708static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001709{
1710 int ret;
1711 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001712 struct intel_iommu *iommu;
1713
David Woodhouse276dbf992009-04-04 01:45:37 +01001714 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1715 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001716 if (!iommu)
1717 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001718
David Woodhouse276dbf992009-04-04 01:45:37 +01001719 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001720 if (!ret)
1721 return ret;
1722 /* dependent device mapping */
1723 tmp = pci_find_upstream_pcie_bridge(pdev);
1724 if (!tmp)
1725 return ret;
1726 /* Secondary interface's bus number and devfn 0 */
1727 parent = pdev->bus->self;
1728 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001729 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001730 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001731 if (!ret)
1732 return ret;
1733 parent = parent->bus->self;
1734 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001735 if (pci_is_pcie(tmp))
David Woodhouse276dbf992009-04-04 01:45:37 +01001736 return device_context_mapped(iommu, tmp->subordinate->number,
1737 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001738 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001739 return device_context_mapped(iommu, tmp->bus->number,
1740 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001741}
1742
Fenghua Yuf5329592009-08-04 15:09:37 -07001743/* Returns a number of VTD pages, but aligned to MM page size */
1744static inline unsigned long aligned_nrpages(unsigned long host_addr,
1745 size_t size)
1746{
1747 host_addr &= ~PAGE_MASK;
1748 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1749}
1750
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001751/* Return largest possible superpage level for a given mapping */
1752static inline int hardware_largepage_caps(struct dmar_domain *domain,
1753 unsigned long iov_pfn,
1754 unsigned long phy_pfn,
1755 unsigned long pages)
1756{
1757 int support, level = 1;
1758 unsigned long pfnmerge;
1759
1760 support = domain->iommu_superpage;
1761
1762 /* To use a large page, the virtual *and* physical addresses
1763 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1764 of them will mean we have to use smaller pages. So just
1765 merge them and check both at once. */
1766 pfnmerge = iov_pfn | phy_pfn;
1767
1768 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1769 pages >>= VTD_STRIDE_SHIFT;
1770 if (!pages)
1771 break;
1772 pfnmerge >>= VTD_STRIDE_SHIFT;
1773 level++;
1774 support--;
1775 }
1776 return level;
1777}
1778
David Woodhouse9051aa02009-06-29 12:30:54 +01001779static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1780 struct scatterlist *sg, unsigned long phys_pfn,
1781 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001782{
1783 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001784 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001785 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001786 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001787 unsigned int largepage_lvl = 0;
1788 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001789
1790 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1791
1792 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1793 return -EINVAL;
1794
1795 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1796
David Woodhouse9051aa02009-06-29 12:30:54 +01001797 if (sg)
1798 sg_res = 0;
1799 else {
1800 sg_res = nr_pages + 1;
1801 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1802 }
1803
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001804 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001805 uint64_t tmp;
1806
David Woodhousee1605492009-06-29 11:17:38 +01001807 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001808 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001809 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1810 sg->dma_length = sg->length;
1811 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001812 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001813 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001814
David Woodhousee1605492009-06-29 11:17:38 +01001815 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001816 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1817
1818 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001819 if (!pte)
1820 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001821 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001822 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001823 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001824 /* Ensure that old small page tables are removed to make room
1825 for superpage, if they exist. */
1826 dma_pte_clear_range(domain, iov_pfn,
1827 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1828 dma_pte_free_pagetable(domain, iov_pfn,
1829 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1830 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001831 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001832 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001833
David Woodhousee1605492009-06-29 11:17:38 +01001834 }
1835 /* We don't need lock here, nobody else
1836 * touches the iova range
1837 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001838 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001839 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001840 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001841 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1842 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001843 if (dumps) {
1844 dumps--;
1845 debug_dma_dump_mappings(NULL);
1846 }
1847 WARN_ON(1);
1848 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001849
1850 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1851
1852 BUG_ON(nr_pages < lvl_pages);
1853 BUG_ON(sg_res < lvl_pages);
1854
1855 nr_pages -= lvl_pages;
1856 iov_pfn += lvl_pages;
1857 phys_pfn += lvl_pages;
1858 pteval += lvl_pages * VTD_PAGE_SIZE;
1859 sg_res -= lvl_pages;
1860
1861 /* If the next PTE would be the first in a new page, then we
1862 need to flush the cache on the entries we've just written.
1863 And then we'll need to recalculate 'pte', so clear it and
1864 let it get set again in the if (!pte) block above.
1865
1866 If we're done (!nr_pages) we need to flush the cache too.
1867
1868 Also if we've been setting superpages, we may need to
1869 recalculate 'pte' and switch back to smaller pages for the
1870 end of the mapping, if the trailing size is not enough to
1871 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001872 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001873 if (!nr_pages || first_pte_in_page(pte) ||
1874 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001875 domain_flush_cache(domain, first_pte,
1876 (void *)pte - (void *)first_pte);
1877 pte = NULL;
1878 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001879
1880 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001881 sg = sg_next(sg);
1882 }
1883 return 0;
1884}
1885
David Woodhouse9051aa02009-06-29 12:30:54 +01001886static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1887 struct scatterlist *sg, unsigned long nr_pages,
1888 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001889{
David Woodhouse9051aa02009-06-29 12:30:54 +01001890 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1891}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001892
David Woodhouse9051aa02009-06-29 12:30:54 +01001893static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1894 unsigned long phys_pfn, unsigned long nr_pages,
1895 int prot)
1896{
1897 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001898}
1899
Weidong Hanc7151a82008-12-08 22:51:37 +08001900static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001901{
Weidong Hanc7151a82008-12-08 22:51:37 +08001902 if (!iommu)
1903 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001904
1905 clear_context_table(iommu, bus, devfn);
1906 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001907 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001908 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001909}
1910
David Woodhouse109b9b02012-05-25 17:43:02 +01001911static inline void unlink_domain_info(struct device_domain_info *info)
1912{
1913 assert_spin_locked(&device_domain_lock);
1914 list_del(&info->link);
1915 list_del(&info->global);
1916 if (info->dev)
1917 info->dev->dev.archdata.iommu = NULL;
1918}
1919
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001920static void domain_remove_dev_info(struct dmar_domain *domain)
1921{
1922 struct device_domain_info *info;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001923 unsigned long flags, flags2;
Weidong Hanc7151a82008-12-08 22:51:37 +08001924 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001925
1926 spin_lock_irqsave(&device_domain_lock, flags);
1927 while (!list_empty(&domain->devices)) {
1928 info = list_entry(domain->devices.next,
1929 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01001930 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001931 spin_unlock_irqrestore(&device_domain_lock, flags);
1932
Yu Zhao93a23a72009-05-18 13:51:37 +08001933 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01001934 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001935 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001936
Jiang Liu92d03cc2014-02-19 14:07:28 +08001937 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
1938 iommu_detach_dependent_devices(iommu, info->dev);
1939 /* clear this iommu in iommu_bmp, update iommu count
1940 * and capabilities
1941 */
1942 spin_lock_irqsave(&domain->iommu_lock, flags2);
1943 if (test_and_clear_bit(iommu->seq_id,
1944 domain->iommu_bmp)) {
1945 domain->iommu_count--;
1946 domain_update_iommu_cap(domain);
1947 }
1948 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
1949 }
1950
1951 free_devinfo_mem(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001952 spin_lock_irqsave(&device_domain_lock, flags);
1953 }
1954 spin_unlock_irqrestore(&device_domain_lock, flags);
1955}
1956
1957/*
1958 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001959 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001960 */
Kay, Allen M38717942008-09-09 18:37:29 +03001961static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001962find_domain(struct pci_dev *pdev)
1963{
1964 struct device_domain_info *info;
1965
1966 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001967 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001968 if (info)
1969 return info->domain;
1970 return NULL;
1971}
1972
Jiang Liu745f2582014-02-19 14:07:26 +08001973static inline struct dmar_domain *
1974dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
1975{
1976 struct device_domain_info *info;
1977
1978 list_for_each_entry(info, &device_domain_list, global)
1979 if (info->segment == segment && info->bus == bus &&
1980 info->devfn == devfn)
1981 return info->domain;
1982
1983 return NULL;
1984}
1985
1986static int dmar_insert_dev_info(int segment, int bus, int devfn,
1987 struct pci_dev *dev, struct dmar_domain **domp)
1988{
1989 struct dmar_domain *found, *domain = *domp;
1990 struct device_domain_info *info;
1991 unsigned long flags;
1992
1993 info = alloc_devinfo_mem();
1994 if (!info)
1995 return -ENOMEM;
1996
1997 info->segment = segment;
1998 info->bus = bus;
1999 info->devfn = devfn;
2000 info->dev = dev;
2001 info->domain = domain;
2002 if (!dev)
2003 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
2004
2005 spin_lock_irqsave(&device_domain_lock, flags);
2006 if (dev)
2007 found = find_domain(dev);
2008 else
2009 found = dmar_search_domain_by_dev_info(segment, bus, devfn);
2010 if (found) {
2011 spin_unlock_irqrestore(&device_domain_lock, flags);
2012 free_devinfo_mem(info);
2013 if (found != domain) {
2014 domain_exit(domain);
2015 *domp = found;
2016 }
2017 } else {
2018 list_add(&info->link, &domain->devices);
2019 list_add(&info->global, &device_domain_list);
2020 if (dev)
2021 dev->dev.archdata.iommu = info;
2022 spin_unlock_irqrestore(&device_domain_lock, flags);
2023 }
2024
2025 return 0;
2026}
2027
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002028/* domain is initialized */
2029static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
2030{
Jiang Liue85bb5d2014-02-19 14:07:27 +08002031 struct dmar_domain *domain, *free = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002032 struct intel_iommu *iommu;
2033 struct dmar_drhd_unit *drhd;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002034 struct pci_dev *dev_tmp;
2035 unsigned long flags;
2036 int bus = 0, devfn = 0;
David Woodhouse276dbf992009-04-04 01:45:37 +01002037 int segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002038
2039 domain = find_domain(pdev);
2040 if (domain)
2041 return domain;
2042
David Woodhouse276dbf992009-04-04 01:45:37 +01002043 segment = pci_domain_nr(pdev->bus);
2044
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002045 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
2046 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002047 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002048 bus = dev_tmp->subordinate->number;
2049 devfn = 0;
2050 } else {
2051 bus = dev_tmp->bus->number;
2052 devfn = dev_tmp->devfn;
2053 }
2054 spin_lock_irqsave(&device_domain_lock, flags);
Jiang Liu745f2582014-02-19 14:07:26 +08002055 domain = dmar_search_domain_by_dev_info(segment, bus, devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002056 spin_unlock_irqrestore(&device_domain_lock, flags);
2057 /* pcie-pci bridge already has a domain, uses it */
Jiang Liu745f2582014-02-19 14:07:26 +08002058 if (domain)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002059 goto found_domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002060 }
2061
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002062 drhd = dmar_find_matched_drhd_unit(pdev);
2063 if (!drhd) {
2064 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2065 pci_name(pdev));
2066 return NULL;
2067 }
2068 iommu = drhd->iommu;
2069
Jiang Liu745f2582014-02-19 14:07:26 +08002070 /* Allocate and intialize new domain for the device */
Jiang Liu92d03cc2014-02-19 14:07:28 +08002071 domain = alloc_domain(false);
Jiang Liu745f2582014-02-19 14:07:26 +08002072 if (!domain)
2073 goto error;
2074 if (iommu_attach_domain(domain, iommu)) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002075 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002076 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002077 }
Jiang Liue85bb5d2014-02-19 14:07:27 +08002078 free = domain;
2079 if (domain_init(domain, gaw))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002080 goto error;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002081
2082 /* register pcie-to-pci device */
2083 if (dev_tmp) {
Jiang Liue85bb5d2014-02-19 14:07:27 +08002084 if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002085 goto error;
Jiang Liue85bb5d2014-02-19 14:07:27 +08002086 else
2087 free = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002088 }
2089
2090found_domain:
Jiang Liu745f2582014-02-19 14:07:26 +08002091 if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
2092 pdev, &domain) == 0)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002093 return domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002094error:
Jiang Liue85bb5d2014-02-19 14:07:27 +08002095 if (free)
2096 domain_exit(free);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002097 /* recheck it here, maybe others set it */
2098 return find_domain(pdev);
2099}
2100
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002101static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002102#define IDENTMAP_ALL 1
2103#define IDENTMAP_GFX 2
2104#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002105
David Woodhouseb2132032009-06-26 18:50:28 +01002106static int iommu_domain_identity_map(struct dmar_domain *domain,
2107 unsigned long long start,
2108 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002109{
David Woodhousec5395d52009-06-28 16:35:56 +01002110 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2111 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002112
David Woodhousec5395d52009-06-28 16:35:56 +01002113 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2114 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002115 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002116 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002117 }
2118
David Woodhousec5395d52009-06-28 16:35:56 +01002119 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2120 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002121 /*
2122 * RMRR range might have overlap with physical memory range,
2123 * clear it first
2124 */
David Woodhousec5395d52009-06-28 16:35:56 +01002125 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002126
David Woodhousec5395d52009-06-28 16:35:56 +01002127 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2128 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002129 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002130}
2131
2132static int iommu_prepare_identity_map(struct pci_dev *pdev,
2133 unsigned long long start,
2134 unsigned long long end)
2135{
2136 struct dmar_domain *domain;
2137 int ret;
2138
David Woodhousec7ab48d2009-06-26 19:10:36 +01002139 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002140 if (!domain)
2141 return -ENOMEM;
2142
David Woodhouse19943b02009-08-04 16:19:20 +01002143 /* For _hardware_ passthrough, don't bother. But for software
2144 passthrough, we do it anyway -- it may indicate a memory
2145 range which is reserved in E820, so which didn't get set
2146 up to start with in si_domain */
2147 if (domain == si_domain && hw_pass_through) {
2148 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2149 pci_name(pdev), start, end);
2150 return 0;
2151 }
2152
2153 printk(KERN_INFO
2154 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2155 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002156
David Woodhouse5595b522009-12-02 09:21:55 +00002157 if (end < start) {
2158 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2159 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2160 dmi_get_system_info(DMI_BIOS_VENDOR),
2161 dmi_get_system_info(DMI_BIOS_VERSION),
2162 dmi_get_system_info(DMI_PRODUCT_VERSION));
2163 ret = -EIO;
2164 goto error;
2165 }
2166
David Woodhouse2ff729f2009-08-26 14:25:41 +01002167 if (end >> agaw_to_width(domain->agaw)) {
2168 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2169 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2170 agaw_to_width(domain->agaw),
2171 dmi_get_system_info(DMI_BIOS_VENDOR),
2172 dmi_get_system_info(DMI_BIOS_VERSION),
2173 dmi_get_system_info(DMI_PRODUCT_VERSION));
2174 ret = -EIO;
2175 goto error;
2176 }
David Woodhouse19943b02009-08-04 16:19:20 +01002177
David Woodhouseb2132032009-06-26 18:50:28 +01002178 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002179 if (ret)
2180 goto error;
2181
2182 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002183 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002184 if (ret)
2185 goto error;
2186
2187 return 0;
2188
2189 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002190 domain_exit(domain);
2191 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002192}
2193
2194static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2195 struct pci_dev *pdev)
2196{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002197 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002198 return 0;
2199 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002200 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002201}
2202
Suresh Siddhad3f13812011-08-23 17:05:25 -07002203#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002204static inline void iommu_prepare_isa(void)
2205{
2206 struct pci_dev *pdev;
2207 int ret;
2208
2209 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2210 if (!pdev)
2211 return;
2212
David Woodhousec7ab48d2009-06-26 19:10:36 +01002213 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002214 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002215
2216 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002217 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2218 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002219
2220}
2221#else
2222static inline void iommu_prepare_isa(void)
2223{
2224 return;
2225}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002226#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002227
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002228static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002229
Matt Kraai071e1372009-08-23 22:30:22 -07002230static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002231{
2232 struct dmar_drhd_unit *drhd;
2233 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002234 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002235
Jiang Liu92d03cc2014-02-19 14:07:28 +08002236 si_domain = alloc_domain(false);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002237 if (!si_domain)
2238 return -EFAULT;
2239
Jiang Liu92d03cc2014-02-19 14:07:28 +08002240 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2241
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002242 for_each_active_iommu(iommu, drhd) {
2243 ret = iommu_attach_domain(si_domain, iommu);
2244 if (ret) {
2245 domain_exit(si_domain);
2246 return -EFAULT;
2247 }
2248 }
2249
2250 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2251 domain_exit(si_domain);
2252 return -EFAULT;
2253 }
2254
Jiang Liu9544c002014-01-06 14:18:13 +08002255 pr_debug("IOMMU: identity mapping domain is domain %d\n",
2256 si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002257
David Woodhouse19943b02009-08-04 16:19:20 +01002258 if (hw)
2259 return 0;
2260
David Woodhousec7ab48d2009-06-26 19:10:36 +01002261 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002262 unsigned long start_pfn, end_pfn;
2263 int i;
2264
2265 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2266 ret = iommu_domain_identity_map(si_domain,
2267 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2268 if (ret)
2269 return ret;
2270 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002271 }
2272
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002273 return 0;
2274}
2275
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002276static int identity_mapping(struct pci_dev *pdev)
2277{
2278 struct device_domain_info *info;
2279
2280 if (likely(!iommu_identity_mapping))
2281 return 0;
2282
Mike Traviscb452a42011-05-28 13:15:03 -05002283 info = pdev->dev.archdata.iommu;
2284 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2285 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002286
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002287 return 0;
2288}
2289
2290static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002291 struct pci_dev *pdev,
2292 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002293{
2294 struct device_domain_info *info;
2295 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002296 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002297
2298 info = alloc_devinfo_mem();
2299 if (!info)
2300 return -ENOMEM;
2301
2302 info->segment = pci_domain_nr(pdev->bus);
2303 info->bus = pdev->bus->number;
2304 info->devfn = pdev->devfn;
2305 info->dev = pdev;
2306 info->domain = domain;
2307
2308 spin_lock_irqsave(&device_domain_lock, flags);
2309 list_add(&info->link, &domain->devices);
2310 list_add(&info->global, &device_domain_list);
2311 pdev->dev.archdata.iommu = info;
2312 spin_unlock_irqrestore(&device_domain_lock, flags);
2313
David Woodhousee2ad23d2012-05-25 17:42:54 +01002314 ret = domain_context_mapping(domain, pdev, translation);
2315 if (ret) {
2316 spin_lock_irqsave(&device_domain_lock, flags);
David Woodhouse109b9b02012-05-25 17:43:02 +01002317 unlink_domain_info(info);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002318 spin_unlock_irqrestore(&device_domain_lock, flags);
2319 free_devinfo_mem(info);
2320 return ret;
2321 }
2322
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002323 return 0;
2324}
2325
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002326static bool device_has_rmrr(struct pci_dev *dev)
2327{
2328 struct dmar_rmrr_unit *rmrr;
2329 int i;
2330
2331 for_each_rmrr_units(rmrr) {
2332 for (i = 0; i < rmrr->devices_cnt; i++) {
2333 /*
2334 * Return TRUE if this RMRR contains the device that
2335 * is passed in.
2336 */
2337 if (rmrr->devices[i] == dev)
2338 return true;
2339 }
2340 }
2341 return false;
2342}
2343
David Woodhouse6941af22009-07-04 18:24:27 +01002344static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2345{
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002346
2347 /*
2348 * We want to prevent any device associated with an RMRR from
2349 * getting placed into the SI Domain. This is done because
2350 * problems exist when devices are moved in and out of domains
2351 * and their respective RMRR info is lost. We exempt USB devices
2352 * from this process due to their usage of RMRRs that are known
2353 * to not be needed after BIOS hand-off to OS.
2354 */
2355 if (device_has_rmrr(pdev) &&
2356 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2357 return 0;
2358
David Woodhousee0fc7e02009-09-30 09:12:17 -07002359 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2360 return 1;
2361
2362 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2363 return 1;
2364
2365 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2366 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002367
David Woodhouse3dfc8132009-07-04 19:11:08 +01002368 /*
2369 * We want to start off with all devices in the 1:1 domain, and
2370 * take them out later if we find they can't access all of memory.
2371 *
2372 * However, we can't do this for PCI devices behind bridges,
2373 * because all PCI devices behind the same bridge will end up
2374 * with the same source-id on their transactions.
2375 *
2376 * Practically speaking, we can't change things around for these
2377 * devices at run-time, because we can't be sure there'll be no
2378 * DMA transactions in flight for any of their siblings.
2379 *
2380 * So PCI devices (unless they're on the root bus) as well as
2381 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2382 * the 1:1 domain, just in _case_ one of their siblings turns out
2383 * not to be able to map all of memory.
2384 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002385 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002386 if (!pci_is_root_bus(pdev->bus))
2387 return 0;
2388 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2389 return 0;
Yijing Wang62f87c02012-07-24 17:20:03 +08002390 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
David Woodhouse3dfc8132009-07-04 19:11:08 +01002391 return 0;
2392
2393 /*
2394 * At boot time, we don't yet know if devices will be 64-bit capable.
2395 * Assume that they will -- if they turn out not to be, then we can
2396 * take them out of the 1:1 domain later.
2397 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002398 if (!startup) {
2399 /*
2400 * If the device's dma_mask is less than the system's memory
2401 * size then this is not a candidate for identity mapping.
2402 */
2403 u64 dma_mask = pdev->dma_mask;
2404
2405 if (pdev->dev.coherent_dma_mask &&
2406 pdev->dev.coherent_dma_mask < dma_mask)
2407 dma_mask = pdev->dev.coherent_dma_mask;
2408
2409 return dma_mask >= dma_get_required_mask(&pdev->dev);
2410 }
David Woodhouse6941af22009-07-04 18:24:27 +01002411
2412 return 1;
2413}
2414
Matt Kraai071e1372009-08-23 22:30:22 -07002415static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002416{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002417 struct pci_dev *pdev = NULL;
2418 int ret;
2419
David Woodhouse19943b02009-08-04 16:19:20 +01002420 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002421 if (ret)
2422 return -EFAULT;
2423
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002424 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002425 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002426 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002427 hw ? CONTEXT_TT_PASS_THROUGH :
2428 CONTEXT_TT_MULTI_LEVEL);
2429 if (ret) {
2430 /* device not associated with an iommu */
2431 if (ret == -ENODEV)
2432 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002433 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002434 }
2435 pr_info("IOMMU: %s identity mapping for device %s\n",
2436 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002437 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002438 }
2439
2440 return 0;
2441}
2442
Joseph Cihulab7792602011-05-03 00:08:37 -07002443static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002444{
2445 struct dmar_drhd_unit *drhd;
2446 struct dmar_rmrr_unit *rmrr;
2447 struct pci_dev *pdev;
2448 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002449 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002450
2451 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002452 * for each drhd
2453 * allocate root
2454 * initialize and program root entry to not present
2455 * endfor
2456 */
2457 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002458 /*
2459 * lock not needed as this is only incremented in the single
2460 * threaded kernel __init code path all other access are read
2461 * only
2462 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002463 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2464 g_num_of_iommus++;
2465 continue;
2466 }
2467 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2468 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002469 }
2470
Weidong Hand9630fe2008-12-08 11:06:32 +08002471 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2472 GFP_KERNEL);
2473 if (!g_iommus) {
2474 printk(KERN_ERR "Allocating global iommu array failed\n");
2475 ret = -ENOMEM;
2476 goto error;
2477 }
2478
mark gross80b20dd2008-04-18 13:53:58 -07002479 deferred_flush = kzalloc(g_num_of_iommus *
2480 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2481 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002482 ret = -ENOMEM;
Jiang Liu989d51f2014-02-19 14:07:21 +08002483 goto free_g_iommus;
mark gross5e0d2a62008-03-04 15:22:08 -08002484 }
2485
Jiang Liu7c919772014-01-06 14:18:18 +08002486 for_each_active_iommu(iommu, drhd) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002487 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002488
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002489 ret = iommu_init_domains(iommu);
2490 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002491 goto free_iommu;
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002492
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002493 /*
2494 * TBD:
2495 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002496 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002497 */
2498 ret = iommu_alloc_root_entry(iommu);
2499 if (ret) {
2500 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002501 goto free_iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002502 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002503 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002504 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002505 }
2506
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002507 /*
2508 * Start from the sane iommu hardware state.
2509 */
Jiang Liu7c919772014-01-06 14:18:18 +08002510 for_each_active_iommu(iommu, drhd) {
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002511 /*
2512 * If the queued invalidation is already initialized by us
2513 * (for example, while enabling interrupt-remapping) then
2514 * we got the things already rolling from a sane state.
2515 */
2516 if (iommu->qi)
2517 continue;
2518
2519 /*
2520 * Clear any previous faults.
2521 */
2522 dmar_fault(-1, iommu);
2523 /*
2524 * Disable queued invalidation if supported and already enabled
2525 * before OS handover.
2526 */
2527 dmar_disable_qi(iommu);
2528 }
2529
Jiang Liu7c919772014-01-06 14:18:18 +08002530 for_each_active_iommu(iommu, drhd) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002531 if (dmar_enable_qi(iommu)) {
2532 /*
2533 * Queued Invalidate not enabled, use Register Based
2534 * Invalidate
2535 */
2536 iommu->flush.flush_context = __iommu_flush_context;
2537 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002538 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002539 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002540 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002541 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002542 } else {
2543 iommu->flush.flush_context = qi_flush_context;
2544 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002545 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002546 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002547 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002548 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002549 }
2550 }
2551
David Woodhouse19943b02009-08-04 16:19:20 +01002552 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002553 iommu_identity_mapping |= IDENTMAP_ALL;
2554
Suresh Siddhad3f13812011-08-23 17:05:25 -07002555#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002556 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002557#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002558
2559 check_tylersburg_isoch();
2560
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002561 /*
2562 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002563 * identity mappings for rmrr, gfx, and isa and may fall back to static
2564 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002565 */
David Woodhouse19943b02009-08-04 16:19:20 +01002566 if (iommu_identity_mapping) {
2567 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2568 if (ret) {
2569 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002570 goto free_iommu;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002571 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002572 }
David Woodhouse19943b02009-08-04 16:19:20 +01002573 /*
2574 * For each rmrr
2575 * for each dev attached to rmrr
2576 * do
2577 * locate drhd for dev, alloc domain for dev
2578 * allocate free domain
2579 * allocate page table entries for rmrr
2580 * if context not allocated for bus
2581 * allocate and init context
2582 * set present in root table for this bus
2583 * init context with domain, translation etc
2584 * endfor
2585 * endfor
2586 */
2587 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2588 for_each_rmrr_units(rmrr) {
2589 for (i = 0; i < rmrr->devices_cnt; i++) {
2590 pdev = rmrr->devices[i];
2591 /*
2592 * some BIOS lists non-exist devices in DMAR
2593 * table.
2594 */
2595 if (!pdev)
2596 continue;
2597 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2598 if (ret)
2599 printk(KERN_ERR
2600 "IOMMU: mapping reserved region failed\n");
2601 }
2602 }
2603
2604 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002605
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002606 /*
2607 * for each drhd
2608 * enable fault log
2609 * global invalidate context cache
2610 * global invalidate iotlb
2611 * enable translation
2612 */
Jiang Liu7c919772014-01-06 14:18:18 +08002613 for_each_iommu(iommu, drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002614 if (drhd->ignored) {
2615 /*
2616 * we always have to disable PMRs or DMA may fail on
2617 * this device
2618 */
2619 if (force_on)
Jiang Liu7c919772014-01-06 14:18:18 +08002620 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002621 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002622 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002623
2624 iommu_flush_write_buffer(iommu);
2625
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002626 ret = dmar_set_interrupt(iommu);
2627 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002628 goto free_iommu;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002629
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002630 iommu_set_root_entry(iommu);
2631
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002632 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002633 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002634
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002635 ret = iommu_enable_translation(iommu);
2636 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002637 goto free_iommu;
David Woodhouseb94996c2009-09-19 15:28:12 -07002638
2639 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002640 }
2641
2642 return 0;
Jiang Liu989d51f2014-02-19 14:07:21 +08002643
2644free_iommu:
Jiang Liu7c919772014-01-06 14:18:18 +08002645 for_each_active_iommu(iommu, drhd)
Jiang Liua868e6b2014-01-06 14:18:20 +08002646 free_dmar_iommu(iommu);
Jiang Liu9bdc5312014-01-06 14:18:27 +08002647 kfree(deferred_flush);
Jiang Liu989d51f2014-02-19 14:07:21 +08002648free_g_iommus:
Weidong Hand9630fe2008-12-08 11:06:32 +08002649 kfree(g_iommus);
Jiang Liu989d51f2014-02-19 14:07:21 +08002650error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002651 return ret;
2652}
2653
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002654/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002655static struct iova *intel_alloc_iova(struct device *dev,
2656 struct dmar_domain *domain,
2657 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002658{
2659 struct pci_dev *pdev = to_pci_dev(dev);
2660 struct iova *iova = NULL;
2661
David Woodhouse875764d2009-06-28 21:20:51 +01002662 /* Restrict dma_mask to the width that the iommu can handle */
2663 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2664
2665 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002666 /*
2667 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002668 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002669 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002670 */
David Woodhouse875764d2009-06-28 21:20:51 +01002671 iova = alloc_iova(&domain->iovad, nrpages,
2672 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2673 if (iova)
2674 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002675 }
David Woodhouse875764d2009-06-28 21:20:51 +01002676 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2677 if (unlikely(!iova)) {
2678 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2679 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002680 return NULL;
2681 }
2682
2683 return iova;
2684}
2685
David Woodhouse147202a2009-07-07 19:43:20 +01002686static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002687{
2688 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002689 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002690
2691 domain = get_domain_for_dev(pdev,
2692 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2693 if (!domain) {
2694 printk(KERN_ERR
2695 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002696 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002697 }
2698
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002699 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002700 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002701 ret = domain_context_mapping(domain, pdev,
2702 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002703 if (ret) {
2704 printk(KERN_ERR
2705 "Domain context map for %s failed",
2706 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002707 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002708 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002709 }
2710
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002711 return domain;
2712}
2713
David Woodhouse147202a2009-07-07 19:43:20 +01002714static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2715{
2716 struct device_domain_info *info;
2717
2718 /* No lock here, assumes no domain exit in normal case */
2719 info = dev->dev.archdata.iommu;
2720 if (likely(info))
2721 return info->domain;
2722
2723 return __get_valid_domain_for_dev(dev);
2724}
2725
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002726static int iommu_dummy(struct pci_dev *pdev)
2727{
2728 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2729}
2730
2731/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002732static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002733{
David Woodhouse73676832009-07-04 14:08:36 +01002734 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002735 int found;
2736
Yijing Wangdbad0862013-12-05 19:43:42 +08002737 if (unlikely(!dev_is_pci(dev)))
David Woodhouse73676832009-07-04 14:08:36 +01002738 return 1;
2739
2740 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002741 if (iommu_dummy(pdev))
2742 return 1;
2743
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002744 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002745 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002746
2747 found = identity_mapping(pdev);
2748 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002749 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002750 return 1;
2751 else {
2752 /*
2753 * 32 bit DMA is removed from si_domain and fall back
2754 * to non-identity mapping.
2755 */
2756 domain_remove_one_dev_info(si_domain, pdev);
2757 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2758 pci_name(pdev));
2759 return 0;
2760 }
2761 } else {
2762 /*
2763 * In case of a detached 64 bit DMA device from vm, the device
2764 * is put into si_domain for identity mapping.
2765 */
David Woodhouse6941af22009-07-04 18:24:27 +01002766 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002767 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002768 ret = domain_add_dev_info(si_domain, pdev,
2769 hw_pass_through ?
2770 CONTEXT_TT_PASS_THROUGH :
2771 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002772 if (!ret) {
2773 printk(KERN_INFO "64bit %s uses identity mapping\n",
2774 pci_name(pdev));
2775 return 1;
2776 }
2777 }
2778 }
2779
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002780 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002781}
2782
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002783static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2784 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002785{
2786 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002787 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002788 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002789 struct iova *iova;
2790 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002791 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002792 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002793 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002794
2795 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002796
David Woodhouse73676832009-07-04 14:08:36 +01002797 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002798 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002799
2800 domain = get_valid_domain_for_dev(pdev);
2801 if (!domain)
2802 return 0;
2803
Weidong Han8c11e792008-12-08 15:29:22 +08002804 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002805 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002806
Mike Travisc681d0b2011-05-28 13:15:05 -05002807 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002808 if (!iova)
2809 goto error;
2810
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002811 /*
2812 * Check if DMAR supports zero-length reads on write only
2813 * mappings..
2814 */
2815 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002816 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002817 prot |= DMA_PTE_READ;
2818 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2819 prot |= DMA_PTE_WRITE;
2820 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002821 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002822 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002823 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002824 * is not a big problem
2825 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002826 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002827 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002828 if (ret)
2829 goto error;
2830
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002831 /* it's a non-present to present mapping. Only flush if caching mode */
2832 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002833 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002834 else
Weidong Han8c11e792008-12-08 15:29:22 +08002835 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002836
David Woodhouse03d6a242009-06-28 15:33:46 +01002837 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2838 start_paddr += paddr & ~PAGE_MASK;
2839 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002840
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002841error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002842 if (iova)
2843 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002844 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002845 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002846 return 0;
2847}
2848
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002849static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2850 unsigned long offset, size_t size,
2851 enum dma_data_direction dir,
2852 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002853{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002854 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2855 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002856}
2857
mark gross5e0d2a62008-03-04 15:22:08 -08002858static void flush_unmaps(void)
2859{
mark gross80b20dd2008-04-18 13:53:58 -07002860 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002861
mark gross5e0d2a62008-03-04 15:22:08 -08002862 timer_on = 0;
2863
2864 /* just flush them all */
2865 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002866 struct intel_iommu *iommu = g_iommus[i];
2867 if (!iommu)
2868 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002869
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002870 if (!deferred_flush[i].next)
2871 continue;
2872
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002873 /* In caching mode, global flushes turn emulation expensive */
2874 if (!cap_caching_mode(iommu->cap))
2875 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002876 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002877 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002878 unsigned long mask;
2879 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002880 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002881
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002882 /* On real hardware multiple invalidations are expensive */
2883 if (cap_caching_mode(iommu->cap))
2884 iommu_flush_iotlb_psi(iommu, domain->id,
2885 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2886 else {
2887 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2888 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2889 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2890 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002891 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002892 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002893 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002894 }
2895
mark gross5e0d2a62008-03-04 15:22:08 -08002896 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002897}
2898
2899static void flush_unmaps_timeout(unsigned long data)
2900{
mark gross80b20dd2008-04-18 13:53:58 -07002901 unsigned long flags;
2902
2903 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002904 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002905 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002906}
2907
2908static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2909{
2910 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002911 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002912 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002913
2914 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002915 if (list_size == HIGH_WATER_MARK)
2916 flush_unmaps();
2917
Weidong Han8c11e792008-12-08 15:29:22 +08002918 iommu = domain_get_iommu(dom);
2919 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002920
mark gross80b20dd2008-04-18 13:53:58 -07002921 next = deferred_flush[iommu_id].next;
2922 deferred_flush[iommu_id].domain[next] = dom;
2923 deferred_flush[iommu_id].iova[next] = iova;
2924 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002925
2926 if (!timer_on) {
2927 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2928 timer_on = 1;
2929 }
2930 list_size++;
2931 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2932}
2933
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002934static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2935 size_t size, enum dma_data_direction dir,
2936 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002937{
2938 struct pci_dev *pdev = to_pci_dev(dev);
2939 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002940 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002941 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002942 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002943
David Woodhouse73676832009-07-04 14:08:36 +01002944 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002945 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002946
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002947 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002948 BUG_ON(!domain);
2949
Weidong Han8c11e792008-12-08 15:29:22 +08002950 iommu = domain_get_iommu(domain);
2951
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002952 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002953 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2954 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002955 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002956
David Woodhoused794dc92009-06-28 00:27:49 +01002957 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2958 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002959
David Woodhoused794dc92009-06-28 00:27:49 +01002960 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2961 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002962
2963 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002964 dma_pte_clear_range(domain, start_pfn, last_pfn);
2965
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002966 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002967 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2968
mark gross5e0d2a62008-03-04 15:22:08 -08002969 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002970 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002971 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002972 /* free iova */
2973 __free_iova(&domain->iovad, iova);
2974 } else {
2975 add_unmap(domain, iova);
2976 /*
2977 * queue up the release of the unmap to save the 1/6th of the
2978 * cpu used up by the iotlb flush operation...
2979 */
mark gross5e0d2a62008-03-04 15:22:08 -08002980 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002981}
2982
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002983static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02002984 dma_addr_t *dma_handle, gfp_t flags,
2985 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002986{
2987 void *vaddr;
2988 int order;
2989
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002990 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002991 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002992
2993 if (!iommu_no_mapping(hwdev))
2994 flags &= ~(GFP_DMA | GFP_DMA32);
2995 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
2996 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
2997 flags |= GFP_DMA;
2998 else
2999 flags |= GFP_DMA32;
3000 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003001
3002 vaddr = (void *)__get_free_pages(flags, order);
3003 if (!vaddr)
3004 return NULL;
3005 memset(vaddr, 0, size);
3006
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003007 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
3008 DMA_BIDIRECTIONAL,
3009 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003010 if (*dma_handle)
3011 return vaddr;
3012 free_pages((unsigned long)vaddr, order);
3013 return NULL;
3014}
3015
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003016static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003017 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003018{
3019 int order;
3020
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003021 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003022 order = get_order(size);
3023
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003024 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003025 free_pages((unsigned long)vaddr, order);
3026}
3027
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003028static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3029 int nelems, enum dma_data_direction dir,
3030 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003031{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003032 struct pci_dev *pdev = to_pci_dev(hwdev);
3033 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003034 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003035 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003036 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003037
David Woodhouse73676832009-07-04 14:08:36 +01003038 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003039 return;
3040
3041 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003042 BUG_ON(!domain);
3043
3044 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003045
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003046 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003047 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3048 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003049 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003050
David Woodhoused794dc92009-06-28 00:27:49 +01003051 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3052 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003053
3054 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003055 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003056
David Woodhoused794dc92009-06-28 00:27:49 +01003057 /* free page tables */
3058 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3059
David Woodhouseacea0012009-07-14 01:55:11 +01003060 if (intel_iommu_strict) {
3061 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003062 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003063 /* free iova */
3064 __free_iova(&domain->iovad, iova);
3065 } else {
3066 add_unmap(domain, iova);
3067 /*
3068 * queue up the release of the unmap to save the 1/6th of the
3069 * cpu used up by the iotlb flush operation...
3070 */
3071 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003072}
3073
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003074static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003075 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003076{
3077 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003078 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003079
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003080 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003081 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003082 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003083 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003084 }
3085 return nelems;
3086}
3087
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003088static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3089 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003090{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003091 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003092 struct pci_dev *pdev = to_pci_dev(hwdev);
3093 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003094 size_t size = 0;
3095 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003096 struct iova *iova = NULL;
3097 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003098 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003099 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003100 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003101
3102 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003103 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003104 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003105
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003106 domain = get_valid_domain_for_dev(pdev);
3107 if (!domain)
3108 return 0;
3109
Weidong Han8c11e792008-12-08 15:29:22 +08003110 iommu = domain_get_iommu(domain);
3111
David Woodhouseb536d242009-06-28 14:49:31 +01003112 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003113 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003114
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003115 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3116 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003117 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003118 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003119 return 0;
3120 }
3121
3122 /*
3123 * Check if DMAR supports zero-length reads on write only
3124 * mappings..
3125 */
3126 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003127 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003128 prot |= DMA_PTE_READ;
3129 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3130 prot |= DMA_PTE_WRITE;
3131
David Woodhouseb536d242009-06-28 14:49:31 +01003132 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003133
Fenghua Yuf5329592009-08-04 15:09:37 -07003134 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003135 if (unlikely(ret)) {
3136 /* clear the page */
3137 dma_pte_clear_range(domain, start_vpfn,
3138 start_vpfn + size - 1);
3139 /* free page tables */
3140 dma_pte_free_pagetable(domain, start_vpfn,
3141 start_vpfn + size - 1);
3142 /* free iova */
3143 __free_iova(&domain->iovad, iova);
3144 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003145 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003146
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003147 /* it's a non-present to present mapping. Only flush if caching mode */
3148 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003149 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003150 else
Weidong Han8c11e792008-12-08 15:29:22 +08003151 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003152
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003153 return nelems;
3154}
3155
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003156static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3157{
3158 return !dma_addr;
3159}
3160
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003161struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003162 .alloc = intel_alloc_coherent,
3163 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003164 .map_sg = intel_map_sg,
3165 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003166 .map_page = intel_map_page,
3167 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003168 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003169};
3170
3171static inline int iommu_domain_cache_init(void)
3172{
3173 int ret = 0;
3174
3175 iommu_domain_cache = kmem_cache_create("iommu_domain",
3176 sizeof(struct dmar_domain),
3177 0,
3178 SLAB_HWCACHE_ALIGN,
3179
3180 NULL);
3181 if (!iommu_domain_cache) {
3182 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3183 ret = -ENOMEM;
3184 }
3185
3186 return ret;
3187}
3188
3189static inline int iommu_devinfo_cache_init(void)
3190{
3191 int ret = 0;
3192
3193 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3194 sizeof(struct device_domain_info),
3195 0,
3196 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003197 NULL);
3198 if (!iommu_devinfo_cache) {
3199 printk(KERN_ERR "Couldn't create devinfo cache\n");
3200 ret = -ENOMEM;
3201 }
3202
3203 return ret;
3204}
3205
3206static inline int iommu_iova_cache_init(void)
3207{
3208 int ret = 0;
3209
3210 iommu_iova_cache = kmem_cache_create("iommu_iova",
3211 sizeof(struct iova),
3212 0,
3213 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003214 NULL);
3215 if (!iommu_iova_cache) {
3216 printk(KERN_ERR "Couldn't create iova cache\n");
3217 ret = -ENOMEM;
3218 }
3219
3220 return ret;
3221}
3222
3223static int __init iommu_init_mempool(void)
3224{
3225 int ret;
3226 ret = iommu_iova_cache_init();
3227 if (ret)
3228 return ret;
3229
3230 ret = iommu_domain_cache_init();
3231 if (ret)
3232 goto domain_error;
3233
3234 ret = iommu_devinfo_cache_init();
3235 if (!ret)
3236 return ret;
3237
3238 kmem_cache_destroy(iommu_domain_cache);
3239domain_error:
3240 kmem_cache_destroy(iommu_iova_cache);
3241
3242 return -ENOMEM;
3243}
3244
3245static void __init iommu_exit_mempool(void)
3246{
3247 kmem_cache_destroy(iommu_devinfo_cache);
3248 kmem_cache_destroy(iommu_domain_cache);
3249 kmem_cache_destroy(iommu_iova_cache);
3250
3251}
3252
Dan Williams556ab452010-07-23 15:47:56 -07003253static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3254{
3255 struct dmar_drhd_unit *drhd;
3256 u32 vtbar;
3257 int rc;
3258
3259 /* We know that this device on this chipset has its own IOMMU.
3260 * If we find it under a different IOMMU, then the BIOS is lying
3261 * to us. Hope that the IOMMU for this device is actually
3262 * disabled, and it needs no translation...
3263 */
3264 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3265 if (rc) {
3266 /* "can't" happen */
3267 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3268 return;
3269 }
3270 vtbar &= 0xffff0000;
3271
3272 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3273 drhd = dmar_find_matched_drhd_unit(pdev);
3274 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3275 TAINT_FIRMWARE_WORKAROUND,
3276 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3277 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3278}
3279DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3280
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003281static void __init init_no_remapping_devices(void)
3282{
3283 struct dmar_drhd_unit *drhd;
3284
3285 for_each_drhd_unit(drhd) {
3286 if (!drhd->include_all) {
3287 int i;
3288 for (i = 0; i < drhd->devices_cnt; i++)
3289 if (drhd->devices[i] != NULL)
3290 break;
3291 /* ignore DMAR unit if no pci devices exist */
3292 if (i == drhd->devices_cnt)
3293 drhd->ignored = 1;
3294 }
3295 }
3296
Jiang Liu7c919772014-01-06 14:18:18 +08003297 for_each_active_drhd_unit(drhd) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003298 int i;
Jiang Liu7c919772014-01-06 14:18:18 +08003299 if (drhd->include_all)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003300 continue;
3301
3302 for (i = 0; i < drhd->devices_cnt; i++)
3303 if (drhd->devices[i] &&
David Woodhousec0771df2011-10-14 20:59:46 +01003304 !IS_GFX_DEVICE(drhd->devices[i]))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003305 break;
3306
3307 if (i < drhd->devices_cnt)
3308 continue;
3309
David Woodhousec0771df2011-10-14 20:59:46 +01003310 /* This IOMMU has *only* gfx devices. Either bypass it or
3311 set the gfx_mapped flag, as appropriate */
3312 if (dmar_map_gfx) {
3313 intel_iommu_gfx_mapped = 1;
3314 } else {
3315 drhd->ignored = 1;
3316 for (i = 0; i < drhd->devices_cnt; i++) {
3317 if (!drhd->devices[i])
3318 continue;
3319 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3320 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003321 }
3322 }
3323}
3324
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003325#ifdef CONFIG_SUSPEND
3326static int init_iommu_hw(void)
3327{
3328 struct dmar_drhd_unit *drhd;
3329 struct intel_iommu *iommu = NULL;
3330
3331 for_each_active_iommu(iommu, drhd)
3332 if (iommu->qi)
3333 dmar_reenable_qi(iommu);
3334
Joseph Cihulab7792602011-05-03 00:08:37 -07003335 for_each_iommu(iommu, drhd) {
3336 if (drhd->ignored) {
3337 /*
3338 * we always have to disable PMRs or DMA may fail on
3339 * this device
3340 */
3341 if (force_on)
3342 iommu_disable_protect_mem_regions(iommu);
3343 continue;
3344 }
3345
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003346 iommu_flush_write_buffer(iommu);
3347
3348 iommu_set_root_entry(iommu);
3349
3350 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003351 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003352 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003353 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003354 if (iommu_enable_translation(iommu))
3355 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003356 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003357 }
3358
3359 return 0;
3360}
3361
3362static void iommu_flush_all(void)
3363{
3364 struct dmar_drhd_unit *drhd;
3365 struct intel_iommu *iommu;
3366
3367 for_each_active_iommu(iommu, drhd) {
3368 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003369 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003370 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003371 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003372 }
3373}
3374
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003375static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003376{
3377 struct dmar_drhd_unit *drhd;
3378 struct intel_iommu *iommu = NULL;
3379 unsigned long flag;
3380
3381 for_each_active_iommu(iommu, drhd) {
3382 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3383 GFP_ATOMIC);
3384 if (!iommu->iommu_state)
3385 goto nomem;
3386 }
3387
3388 iommu_flush_all();
3389
3390 for_each_active_iommu(iommu, drhd) {
3391 iommu_disable_translation(iommu);
3392
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003393 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003394
3395 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3396 readl(iommu->reg + DMAR_FECTL_REG);
3397 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3398 readl(iommu->reg + DMAR_FEDATA_REG);
3399 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3400 readl(iommu->reg + DMAR_FEADDR_REG);
3401 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3402 readl(iommu->reg + DMAR_FEUADDR_REG);
3403
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003404 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003405 }
3406 return 0;
3407
3408nomem:
3409 for_each_active_iommu(iommu, drhd)
3410 kfree(iommu->iommu_state);
3411
3412 return -ENOMEM;
3413}
3414
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003415static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003416{
3417 struct dmar_drhd_unit *drhd;
3418 struct intel_iommu *iommu = NULL;
3419 unsigned long flag;
3420
3421 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003422 if (force_on)
3423 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3424 else
3425 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003426 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003427 }
3428
3429 for_each_active_iommu(iommu, drhd) {
3430
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003431 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003432
3433 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3434 iommu->reg + DMAR_FECTL_REG);
3435 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3436 iommu->reg + DMAR_FEDATA_REG);
3437 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3438 iommu->reg + DMAR_FEADDR_REG);
3439 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3440 iommu->reg + DMAR_FEUADDR_REG);
3441
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003442 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003443 }
3444
3445 for_each_active_iommu(iommu, drhd)
3446 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003447}
3448
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003449static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003450 .resume = iommu_resume,
3451 .suspend = iommu_suspend,
3452};
3453
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003454static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003455{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003456 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003457}
3458
3459#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003460static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003461#endif /* CONFIG_PM */
3462
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003463static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3464{
3465 list_add(&rmrr->list, &dmar_rmrr_units);
3466}
3467
3468
3469int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3470{
3471 struct acpi_dmar_reserved_memory *rmrr;
3472 struct dmar_rmrr_unit *rmrru;
3473
3474 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3475 if (!rmrru)
3476 return -ENOMEM;
3477
3478 rmrru->hdr = header;
3479 rmrr = (struct acpi_dmar_reserved_memory *)header;
3480 rmrru->base_address = rmrr->base_address;
3481 rmrru->end_address = rmrr->end_address;
3482
3483 dmar_register_rmrr_unit(rmrru);
3484 return 0;
3485}
3486
3487static int __init
3488rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3489{
3490 struct acpi_dmar_reserved_memory *rmrr;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003491
3492 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003493 return dmar_parse_dev_scope((void *)(rmrr + 1),
3494 ((void *)rmrr) + rmrr->header.length,
3495 &rmrru->devices_cnt, &rmrru->devices,
3496 rmrr->segment);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003497}
3498
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003499int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3500{
3501 struct acpi_dmar_atsr *atsr;
3502 struct dmar_atsr_unit *atsru;
3503
3504 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3505 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3506 if (!atsru)
3507 return -ENOMEM;
3508
3509 atsru->hdr = hdr;
3510 atsru->include_all = atsr->flags & 0x1;
3511
3512 list_add(&atsru->list, &dmar_atsr_units);
3513
3514 return 0;
3515}
3516
3517static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3518{
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003519 struct acpi_dmar_atsr *atsr;
3520
3521 if (atsru->include_all)
3522 return 0;
3523
3524 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
Jiang Liu9bdc5312014-01-06 14:18:27 +08003525 return dmar_parse_dev_scope((void *)(atsr + 1),
3526 (void *)atsr + atsr->header.length,
3527 &atsru->devices_cnt, &atsru->devices,
3528 atsr->segment);
3529}
3530
3531static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
3532{
3533 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
3534 kfree(atsru);
3535}
3536
3537static void intel_iommu_free_dmars(void)
3538{
3539 struct dmar_rmrr_unit *rmrru, *rmrr_n;
3540 struct dmar_atsr_unit *atsru, *atsr_n;
3541
3542 list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
3543 list_del(&rmrru->list);
3544 dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
3545 kfree(rmrru);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003546 }
3547
Jiang Liu9bdc5312014-01-06 14:18:27 +08003548 list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
3549 list_del(&atsru->list);
3550 intel_iommu_free_atsr(atsru);
3551 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003552}
3553
3554int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3555{
3556 int i;
3557 struct pci_bus *bus;
3558 struct acpi_dmar_atsr *atsr;
3559 struct dmar_atsr_unit *atsru;
3560
3561 dev = pci_physfn(dev);
3562
3563 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3564 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3565 if (atsr->segment == pci_domain_nr(dev->bus))
3566 goto found;
3567 }
3568
3569 return 0;
3570
3571found:
3572 for (bus = dev->bus; bus; bus = bus->parent) {
3573 struct pci_dev *bridge = bus->self;
3574
3575 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003576 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003577 return 0;
3578
Yijing Wang62f87c02012-07-24 17:20:03 +08003579 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003580 for (i = 0; i < atsru->devices_cnt; i++)
3581 if (atsru->devices[i] == bridge)
3582 return 1;
3583 break;
3584 }
3585 }
3586
3587 if (atsru->include_all)
3588 return 1;
3589
3590 return 0;
3591}
3592
Sergey Senozhatskyc8f369a2011-10-26 18:45:39 +03003593int __init dmar_parse_rmrr_atsr_dev(void)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003594{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003595 struct dmar_rmrr_unit *rmrr;
3596 struct dmar_atsr_unit *atsr;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003597 int ret = 0;
3598
Jiang Liu9bdc5312014-01-06 14:18:27 +08003599 list_for_each_entry(rmrr, &dmar_rmrr_units, list) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003600 ret = rmrr_parse_dev(rmrr);
3601 if (ret)
3602 return ret;
3603 }
3604
Jiang Liu9bdc5312014-01-06 14:18:27 +08003605 list_for_each_entry(atsr, &dmar_atsr_units, list) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003606 ret = atsr_parse_dev(atsr);
3607 if (ret)
3608 return ret;
3609 }
3610
3611 return ret;
3612}
3613
Fenghua Yu99dcade2009-11-11 07:23:06 -08003614/*
3615 * Here we only respond to action of unbound device from driver.
3616 *
3617 * Added device is not attached to its DMAR domain here yet. That will happen
3618 * when mapping the device to iova.
3619 */
3620static int device_notifier(struct notifier_block *nb,
3621 unsigned long action, void *data)
3622{
3623 struct device *dev = data;
3624 struct pci_dev *pdev = to_pci_dev(dev);
3625 struct dmar_domain *domain;
3626
Jiang Liu816997d2014-02-19 14:07:22 +08003627 if (iommu_dummy(pdev))
David Woodhouse44cd6132009-12-02 10:18:30 +00003628 return 0;
3629
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003630 if (action != BUS_NOTIFY_UNBOUND_DRIVER &&
3631 action != BUS_NOTIFY_DEL_DEVICE)
3632 return 0;
3633
Fenghua Yu99dcade2009-11-11 07:23:06 -08003634 domain = find_domain(pdev);
3635 if (!domain)
3636 return 0;
3637
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003638 domain_remove_one_dev_info(domain, pdev);
3639 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3640 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3641 list_empty(&domain->devices))
3642 domain_exit(domain);
Alex Williamsona97590e2011-03-04 14:52:16 -07003643
Fenghua Yu99dcade2009-11-11 07:23:06 -08003644 return 0;
3645}
3646
3647static struct notifier_block device_nb = {
3648 .notifier_call = device_notifier,
3649};
3650
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003651int __init intel_iommu_init(void)
3652{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003653 int ret = -ENODEV;
Takao Indoh3a93c842013-04-23 17:35:03 +09003654 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +08003655 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003656
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003657 /* VT-d is required for a TXT/tboot launch, so enforce that */
3658 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003659
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003660 if (dmar_table_init()) {
3661 if (force_on)
3662 panic("tboot: Failed to initialize DMAR table\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003663 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003664 }
3665
Takao Indoh3a93c842013-04-23 17:35:03 +09003666 /*
3667 * Disable translation if already enabled prior to OS handover.
3668 */
Jiang Liu7c919772014-01-06 14:18:18 +08003669 for_each_active_iommu(iommu, drhd)
Takao Indoh3a93c842013-04-23 17:35:03 +09003670 if (iommu->gcmd & DMA_GCMD_TE)
3671 iommu_disable_translation(iommu);
Takao Indoh3a93c842013-04-23 17:35:03 +09003672
Suresh Siddhac2c72862011-08-23 17:05:19 -07003673 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003674 if (force_on)
3675 panic("tboot: Failed to initialize DMAR device scope\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003676 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003677 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003678
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003679 if (no_iommu || dmar_disabled)
Jiang Liu9bdc5312014-01-06 14:18:27 +08003680 goto out_free_dmar;
Suresh Siddha2ae21012008-07-10 11:16:43 -07003681
Joseph Cihula51a63e62011-03-21 11:04:24 -07003682 if (iommu_init_mempool()) {
3683 if (force_on)
3684 panic("tboot: Failed to initialize iommu memory\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003685 goto out_free_dmar;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003686 }
3687
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003688 if (list_empty(&dmar_rmrr_units))
3689 printk(KERN_INFO "DMAR: No RMRR found\n");
3690
3691 if (list_empty(&dmar_atsr_units))
3692 printk(KERN_INFO "DMAR: No ATSR found\n");
3693
Joseph Cihula51a63e62011-03-21 11:04:24 -07003694 if (dmar_init_reserved_ranges()) {
3695 if (force_on)
3696 panic("tboot: Failed to reserve iommu ranges\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003697 goto out_free_mempool;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003698 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003699
3700 init_no_remapping_devices();
3701
Joseph Cihulab7792602011-05-03 00:08:37 -07003702 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003703 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003704 if (force_on)
3705 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003706 printk(KERN_ERR "IOMMU: dmar init failed\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003707 goto out_free_reserved_range;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003708 }
3709 printk(KERN_INFO
3710 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3711
mark gross5e0d2a62008-03-04 15:22:08 -08003712 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003713#ifdef CONFIG_SWIOTLB
3714 swiotlb = 0;
3715#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003716 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003717
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003718 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003719
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003720 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003721
Fenghua Yu99dcade2009-11-11 07:23:06 -08003722 bus_register_notifier(&pci_bus_type, &device_nb);
3723
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003724 intel_iommu_enabled = 1;
3725
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003726 return 0;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003727
3728out_free_reserved_range:
3729 put_iova_domain(&reserved_iova_list);
3730out_free_mempool:
3731 iommu_exit_mempool();
3732out_free_dmar:
3733 intel_iommu_free_dmars();
3734 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003735}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003736
Han, Weidong3199aa62009-02-26 17:31:12 +08003737static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3738 struct pci_dev *pdev)
3739{
3740 struct pci_dev *tmp, *parent;
3741
3742 if (!iommu || !pdev)
3743 return;
3744
3745 /* dependent device detach */
3746 tmp = pci_find_upstream_pcie_bridge(pdev);
3747 /* Secondary interface's bus number and devfn 0 */
3748 if (tmp) {
3749 parent = pdev->bus->self;
3750 while (parent != tmp) {
3751 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01003752 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003753 parent = parent->bus->self;
3754 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003755 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003756 iommu_detach_dev(iommu,
3757 tmp->subordinate->number, 0);
3758 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01003759 iommu_detach_dev(iommu, tmp->bus->number,
3760 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003761 }
3762}
3763
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003764static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003765 struct pci_dev *pdev)
3766{
Yijing Wangbca2b912013-10-31 17:26:04 +08003767 struct device_domain_info *info, *tmp;
Weidong Hanc7151a82008-12-08 22:51:37 +08003768 struct intel_iommu *iommu;
3769 unsigned long flags;
3770 int found = 0;
Weidong Hanc7151a82008-12-08 22:51:37 +08003771
David Woodhouse276dbf992009-04-04 01:45:37 +01003772 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3773 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003774 if (!iommu)
3775 return;
3776
3777 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wangbca2b912013-10-31 17:26:04 +08003778 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
Mike Habeck8519dc42011-05-28 13:15:07 -05003779 if (info->segment == pci_domain_nr(pdev->bus) &&
3780 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003781 info->devfn == pdev->devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01003782 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003783 spin_unlock_irqrestore(&device_domain_lock, flags);
3784
Yu Zhao93a23a72009-05-18 13:51:37 +08003785 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003786 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003787 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003788 free_devinfo_mem(info);
3789
3790 spin_lock_irqsave(&device_domain_lock, flags);
3791
3792 if (found)
3793 break;
3794 else
3795 continue;
3796 }
3797
3798 /* if there is no other devices under the same iommu
3799 * owned by this domain, clear this iommu in iommu_bmp
3800 * update iommu count and coherency
3801 */
David Woodhouse276dbf992009-04-04 01:45:37 +01003802 if (iommu == device_to_iommu(info->segment, info->bus,
3803 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003804 found = 1;
3805 }
3806
Roland Dreier3e7abe22011-07-20 06:22:21 -07003807 spin_unlock_irqrestore(&device_domain_lock, flags);
3808
Weidong Hanc7151a82008-12-08 22:51:37 +08003809 if (found == 0) {
3810 unsigned long tmp_flags;
3811 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003812 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003813 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003814 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003815 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003816
Alex Williamson9b4554b2011-05-24 12:19:04 -04003817 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3818 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3819 spin_lock_irqsave(&iommu->lock, tmp_flags);
3820 clear_bit(domain->id, iommu->domain_ids);
3821 iommu->domains[domain->id] = NULL;
3822 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3823 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003824 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003825}
3826
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003827static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003828{
3829 int adjust_width;
3830
3831 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003832 domain_reserve_special_ranges(domain);
3833
3834 /* calculate AGAW */
3835 domain->gaw = guest_width;
3836 adjust_width = guestwidth_to_adjustwidth(guest_width);
3837 domain->agaw = width_to_agaw(adjust_width);
3838
Weidong Han5e98c4b2008-12-08 23:03:27 +08003839 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003840 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003841 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003842 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003843 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003844
3845 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003846 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003847 if (!domain->pgd)
3848 return -ENOMEM;
3849 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3850 return 0;
3851}
3852
Joerg Roedel5d450802008-12-03 14:52:32 +01003853static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003854{
Joerg Roedel5d450802008-12-03 14:52:32 +01003855 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003856
Jiang Liu92d03cc2014-02-19 14:07:28 +08003857 dmar_domain = alloc_domain(true);
Joerg Roedel5d450802008-12-03 14:52:32 +01003858 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003859 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003860 "intel_iommu_domain_init: dmar_domain == NULL\n");
3861 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003862 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003863 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003864 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003865 "intel_iommu_domain_init() failed\n");
Jiang Liu92d03cc2014-02-19 14:07:28 +08003866 domain_exit(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003867 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003868 }
Allen Kay8140a952011-10-14 12:32:17 -07003869 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003870 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003871
Joerg Roedel8a0e7152012-01-26 19:40:54 +01003872 domain->geometry.aperture_start = 0;
3873 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
3874 domain->geometry.force_aperture = true;
3875
Joerg Roedel5d450802008-12-03 14:52:32 +01003876 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003877}
Kay, Allen M38717942008-09-09 18:37:29 +03003878
Joerg Roedel5d450802008-12-03 14:52:32 +01003879static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003880{
Joerg Roedel5d450802008-12-03 14:52:32 +01003881 struct dmar_domain *dmar_domain = domain->priv;
3882
3883 domain->priv = NULL;
Jiang Liu92d03cc2014-02-19 14:07:28 +08003884 domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003885}
Kay, Allen M38717942008-09-09 18:37:29 +03003886
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003887static int intel_iommu_attach_device(struct iommu_domain *domain,
3888 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003889{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003890 struct dmar_domain *dmar_domain = domain->priv;
3891 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003892 struct intel_iommu *iommu;
3893 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03003894
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003895 /* normally pdev is not mapped */
3896 if (unlikely(domain_context_mapped(pdev))) {
3897 struct dmar_domain *old_domain;
3898
3899 old_domain = find_domain(pdev);
3900 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003901 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3902 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3903 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003904 else
3905 domain_remove_dev_info(old_domain);
3906 }
3907 }
3908
David Woodhouse276dbf992009-04-04 01:45:37 +01003909 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3910 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003911 if (!iommu)
3912 return -ENODEV;
3913
3914 /* check if this iommu agaw is sufficient for max mapped address */
3915 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01003916 if (addr_width > cap_mgaw(iommu->cap))
3917 addr_width = cap_mgaw(iommu->cap);
3918
3919 if (dmar_domain->max_addr > (1LL << addr_width)) {
3920 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003921 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01003922 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003923 return -EFAULT;
3924 }
Tom Lyona99c47a2010-05-17 08:20:45 +01003925 dmar_domain->gaw = addr_width;
3926
3927 /*
3928 * Knock out extra levels of page tables if necessary
3929 */
3930 while (iommu->agaw < dmar_domain->agaw) {
3931 struct dma_pte *pte;
3932
3933 pte = dmar_domain->pgd;
3934 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08003935 dmar_domain->pgd = (struct dma_pte *)
3936 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01003937 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01003938 }
3939 dmar_domain->agaw--;
3940 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003941
David Woodhouse5fe60f42009-08-09 10:53:41 +01003942 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003943}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003944
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003945static void intel_iommu_detach_device(struct iommu_domain *domain,
3946 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003947{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003948 struct dmar_domain *dmar_domain = domain->priv;
3949 struct pci_dev *pdev = to_pci_dev(dev);
3950
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003951 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003952}
Kay, Allen M38717942008-09-09 18:37:29 +03003953
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003954static int intel_iommu_map(struct iommu_domain *domain,
3955 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02003956 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003957{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003958 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003959 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003960 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003961 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003962
Joerg Roedeldde57a22008-12-03 15:04:09 +01003963 if (iommu_prot & IOMMU_READ)
3964 prot |= DMA_PTE_READ;
3965 if (iommu_prot & IOMMU_WRITE)
3966 prot |= DMA_PTE_WRITE;
Sheng Yang9cf066972009-03-18 15:33:07 +08003967 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
3968 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003969
David Woodhouse163cc522009-06-28 00:51:17 +01003970 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003971 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003972 u64 end;
3973
3974 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01003975 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003976 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01003977 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003978 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01003979 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003980 return -EFAULT;
3981 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003982 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003983 }
David Woodhousead051222009-06-28 14:22:28 +01003984 /* Round up size to next multiple of PAGE_SIZE, if it and
3985 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01003986 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01003987 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
3988 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003989 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003990}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003991
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02003992static size_t intel_iommu_unmap(struct iommu_domain *domain,
3993 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003994{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003995 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07003996 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01003997
Allen Kay292827c2011-10-14 12:31:54 -07003998 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01003999 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004000
David Woodhouse163cc522009-06-28 00:51:17 +01004001 if (dmar_domain->max_addr == iova + size)
4002 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004003
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004004 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004005}
Kay, Allen M38717942008-09-09 18:37:29 +03004006
Joerg Roedeld14d6572008-12-03 15:06:57 +01004007static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
Varun Sethibb5547ac2013-03-29 01:23:58 +05304008 dma_addr_t iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004009{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004010 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004011 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004012 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004013
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004014 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004015 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004016 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004017
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004018 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004019}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004020
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004021static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4022 unsigned long cap)
4023{
4024 struct dmar_domain *dmar_domain = domain->priv;
4025
4026 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4027 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004028 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004029 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004030
4031 return 0;
4032}
4033
Alex Williamson783f1572012-05-30 14:19:43 -06004034#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4035
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004036static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004037{
4038 struct pci_dev *pdev = to_pci_dev(dev);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004039 struct pci_dev *bridge, *dma_pdev = NULL;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004040 struct iommu_group *group;
4041 int ret;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004042
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004043 if (!device_to_iommu(pci_domain_nr(pdev->bus),
4044 pdev->bus->number, pdev->devfn))
Alex Williamson70ae6f02011-10-21 15:56:11 -04004045 return -ENODEV;
4046
4047 bridge = pci_find_upstream_pcie_bridge(pdev);
4048 if (bridge) {
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004049 if (pci_is_pcie(bridge))
4050 dma_pdev = pci_get_domain_bus_and_slot(
4051 pci_domain_nr(pdev->bus),
4052 bridge->subordinate->number, 0);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004053 if (!dma_pdev)
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004054 dma_pdev = pci_dev_get(bridge);
4055 } else
4056 dma_pdev = pci_dev_get(pdev);
4057
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004058 /* Account for quirked devices */
Alex Williamson783f1572012-05-30 14:19:43 -06004059 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4060
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004061 /*
4062 * If it's a multifunction device that does not support our
Alex Williamsonc14d2692013-05-30 12:39:18 -06004063 * required ACS flags, add to the same group as lowest numbered
4064 * function that also does not suport the required ACS flags.
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004065 */
Alex Williamson783f1572012-05-30 14:19:43 -06004066 if (dma_pdev->multifunction &&
Alex Williamsonc14d2692013-05-30 12:39:18 -06004067 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
4068 u8 i, slot = PCI_SLOT(dma_pdev->devfn);
4069
4070 for (i = 0; i < 8; i++) {
4071 struct pci_dev *tmp;
4072
4073 tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
4074 if (!tmp)
4075 continue;
4076
4077 if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
4078 swap_pci_ref(&dma_pdev, tmp);
4079 break;
4080 }
4081 pci_dev_put(tmp);
4082 }
4083 }
Alex Williamson783f1572012-05-30 14:19:43 -06004084
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004085 /*
4086 * Devices on the root bus go through the iommu. If that's not us,
4087 * find the next upstream device and test ACS up to the root bus.
4088 * Finding the next device may require skipping virtual buses.
4089 */
Alex Williamson783f1572012-05-30 14:19:43 -06004090 while (!pci_is_root_bus(dma_pdev->bus)) {
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004091 struct pci_bus *bus = dma_pdev->bus;
4092
4093 while (!bus->self) {
4094 if (!pci_is_root_bus(bus))
4095 bus = bus->parent;
4096 else
4097 goto root_bus;
4098 }
4099
4100 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
Alex Williamson783f1572012-05-30 14:19:43 -06004101 break;
4102
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004103 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
Alex Williamson70ae6f02011-10-21 15:56:11 -04004104 }
4105
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004106root_bus:
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004107 group = iommu_group_get(&dma_pdev->dev);
4108 pci_dev_put(dma_pdev);
4109 if (!group) {
4110 group = iommu_group_alloc();
4111 if (IS_ERR(group))
4112 return PTR_ERR(group);
4113 }
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004114
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004115 ret = iommu_group_add_device(group, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004116
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004117 iommu_group_put(group);
4118 return ret;
4119}
4120
4121static void intel_iommu_remove_device(struct device *dev)
4122{
4123 iommu_group_remove_device(dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004124}
4125
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004126static struct iommu_ops intel_iommu_ops = {
4127 .domain_init = intel_iommu_domain_init,
4128 .domain_destroy = intel_iommu_domain_destroy,
4129 .attach_dev = intel_iommu_attach_device,
4130 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004131 .map = intel_iommu_map,
4132 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004133 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004134 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004135 .add_device = intel_iommu_add_device,
4136 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004137 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004138};
David Woodhouse9af88142009-02-13 23:18:03 +00004139
Daniel Vetter94526182013-01-20 23:50:13 +01004140static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4141{
4142 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4143 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4144 dmar_map_gfx = 0;
4145}
4146
4147DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4148DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4149DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4150DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4151DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4152DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4153DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4154
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004155static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004156{
4157 /*
4158 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004159 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004160 */
4161 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4162 rwbf_quirk = 1;
4163}
4164
4165DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004166DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4167DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4168DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4169DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4170DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4171DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004172
Adam Jacksoneecfd572010-08-25 21:17:34 +01004173#define GGC 0x52
4174#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4175#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4176#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4177#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4178#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4179#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4180#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4181#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4182
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004183static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004184{
4185 unsigned short ggc;
4186
Adam Jacksoneecfd572010-08-25 21:17:34 +01004187 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004188 return;
4189
Adam Jacksoneecfd572010-08-25 21:17:34 +01004190 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004191 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4192 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004193 } else if (dmar_map_gfx) {
4194 /* we have to ensure the gfx device is idle before we flush */
4195 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4196 intel_iommu_strict = 1;
4197 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004198}
4199DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4200DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4201DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4202DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4203
David Woodhousee0fc7e02009-09-30 09:12:17 -07004204/* On Tylersburg chipsets, some BIOSes have been known to enable the
4205 ISOCH DMAR unit for the Azalia sound device, but not give it any
4206 TLB entries, which causes it to deadlock. Check for that. We do
4207 this in a function called from init_dmars(), instead of in a PCI
4208 quirk, because we don't want to print the obnoxious "BIOS broken"
4209 message if VT-d is actually disabled.
4210*/
4211static void __init check_tylersburg_isoch(void)
4212{
4213 struct pci_dev *pdev;
4214 uint32_t vtisochctrl;
4215
4216 /* If there's no Azalia in the system anyway, forget it. */
4217 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4218 if (!pdev)
4219 return;
4220 pci_dev_put(pdev);
4221
4222 /* System Management Registers. Might be hidden, in which case
4223 we can't do the sanity check. But that's OK, because the
4224 known-broken BIOSes _don't_ actually hide it, so far. */
4225 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4226 if (!pdev)
4227 return;
4228
4229 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4230 pci_dev_put(pdev);
4231 return;
4232 }
4233
4234 pci_dev_put(pdev);
4235
4236 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4237 if (vtisochctrl & 1)
4238 return;
4239
4240 /* Drop all bits other than the number of TLB entries */
4241 vtisochctrl &= 0x1c;
4242
4243 /* If we have the recommended number of TLB entries (16), fine. */
4244 if (vtisochctrl == 0x10)
4245 return;
4246
4247 /* Zero TLB entries? You get to ride the short bus to school. */
4248 if (!vtisochctrl) {
4249 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4250 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4251 dmi_get_system_info(DMI_BIOS_VENDOR),
4252 dmi_get_system_info(DMI_BIOS_VERSION),
4253 dmi_get_system_info(DMI_PRODUCT_VERSION));
4254 iommu_identity_mapping |= IDENTMAP_AZALIA;
4255 return;
4256 }
4257
4258 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4259 vtisochctrl);
4260}