blob: 7732c43871fa9124671f7246a87bddc5538d7e0a [file] [log] [blame]
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001/*
2 * Copyright (c) 2006, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
mark gross98bcef52008-02-23 15:23:35 -080017 * Copyright (C) 2006-2008 Intel Corporation
18 * Author: Ashok Raj <ashok.raj@intel.com>
19 * Author: Shaohua Li <shaohua.li@intel.com>
20 * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Fenghua Yu5b6985c2008-10-16 18:02:32 -070021 * Author: Fenghua Yu <fenghua.yu@intel.com>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070022 */
23
24#include <linux/init.h>
25#include <linux/bitmap.h>
mark gross5e0d2a62008-03-04 15:22:08 -080026#include <linux/debugfs.h>
Paul Gortmaker54485c32011-10-29 10:26:25 -040027#include <linux/export.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070028#include <linux/slab.h>
29#include <linux/irq.h>
30#include <linux/interrupt.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070031#include <linux/spinlock.h>
32#include <linux/pci.h>
33#include <linux/dmar.h>
34#include <linux/dma-mapping.h>
35#include <linux/mempool.h>
mark gross5e0d2a62008-03-04 15:22:08 -080036#include <linux/timer.h>
Kay, Allen M38717942008-09-09 18:37:29 +030037#include <linux/iova.h>
Joerg Roedel5d450802008-12-03 14:52:32 +010038#include <linux/iommu.h>
Kay, Allen M38717942008-09-09 18:37:29 +030039#include <linux/intel-iommu.h>
Rafael J. Wysocki134fac32011-03-23 22:16:14 +010040#include <linux/syscore_ops.h>
Shane Wang69575d32009-09-01 18:25:07 -070041#include <linux/tboot.h>
Stephen Rothwelladb2fe02009-08-31 15:24:23 +100042#include <linux/dmi.h>
Joerg Roedel5cdede22011-04-04 15:55:18 +020043#include <linux/pci-ats.h>
Tejun Heo0ee332c2011-12-08 10:22:09 -080044#include <linux/memblock.h>
Suresh Siddha8a8f4222012-03-30 11:47:08 -070045#include <asm/irq_remapping.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070046#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090047#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070048
Joerg Roedel078e1ee2012-09-26 12:44:43 +020049#include "irq_remapping.h"
Varun Sethi61e015a2013-04-23 10:05:24 +053050#include "pci.h"
Joerg Roedel078e1ee2012-09-26 12:44:43 +020051
Fenghua Yu5b6985c2008-10-16 18:02:32 -070052#define ROOT_SIZE VTD_PAGE_SIZE
53#define CONTEXT_SIZE VTD_PAGE_SIZE
54
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070055#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
56#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070057#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070058
59#define IOAPIC_RANGE_START (0xfee00000)
60#define IOAPIC_RANGE_END (0xfeefffff)
61#define IOVA_START_ADDR (0x1000)
62
63#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
64
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070065#define MAX_AGAW_WIDTH 64
Jiang Liu5c645b32014-01-06 14:18:12 +080066#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070067
David Woodhouse2ebe3152009-09-19 07:34:04 -070068#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
69#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
70
71/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
72 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
73#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
74 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
75#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070076
Mark McLoughlinf27be032008-11-20 15:49:43 +000077#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a92009-04-06 19:01:15 -070078#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070079#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080080
Andrew Mortondf08cdc2010-09-22 13:05:11 -070081/* page table handling */
82#define LEVEL_STRIDE (9)
83#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
84
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +020085/*
86 * This bitmap is used to advertise the page sizes our hardware support
87 * to the IOMMU core, which will then use this information to split
88 * physically contiguous memory regions it is mapping into page sizes
89 * that we support.
90 *
91 * Traditionally the IOMMU core just handed us the mappings directly,
92 * after making sure the size is an order of a 4KiB page and that the
93 * mapping has natural alignment.
94 *
95 * To retain this behavior, we currently advertise that we support
96 * all page sizes that are an order of 4KiB.
97 *
98 * If at some point we'd like to utilize the IOMMU core's new behavior,
99 * we could change this to advertise the real page sizes we support.
100 */
101#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
102
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700103static inline int agaw_to_level(int agaw)
104{
105 return agaw + 2;
106}
107
108static inline int agaw_to_width(int agaw)
109{
Jiang Liu5c645b32014-01-06 14:18:12 +0800110 return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700111}
112
113static inline int width_to_agaw(int width)
114{
Jiang Liu5c645b32014-01-06 14:18:12 +0800115 return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700116}
117
118static inline unsigned int level_to_offset_bits(int level)
119{
120 return (level - 1) * LEVEL_STRIDE;
121}
122
123static inline int pfn_level_offset(unsigned long pfn, int level)
124{
125 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
126}
127
128static inline unsigned long level_mask(int level)
129{
130 return -1UL << level_to_offset_bits(level);
131}
132
133static inline unsigned long level_size(int level)
134{
135 return 1UL << level_to_offset_bits(level);
136}
137
138static inline unsigned long align_to_level(unsigned long pfn, int level)
139{
140 return (pfn + level_size(level) - 1) & level_mask(level);
141}
David Woodhousefd18de52009-05-10 23:57:41 +0100142
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100143static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
144{
Jiang Liu5c645b32014-01-06 14:18:12 +0800145 return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100146}
147
David Woodhousedd4e8312009-06-27 16:21:20 +0100148/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
149 are never going to work. */
150static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
151{
152 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
153}
154
155static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
156{
157 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
158}
159static inline unsigned long page_to_dma_pfn(struct page *pg)
160{
161 return mm_to_dma_pfn(page_to_pfn(pg));
162}
163static inline unsigned long virt_to_dma_pfn(void *p)
164{
165 return page_to_dma_pfn(virt_to_page(p));
166}
167
Weidong Hand9630fe2008-12-08 11:06:32 +0800168/* global iommu list, set NULL for ignored DMAR units */
169static struct intel_iommu **g_iommus;
170
David Woodhousee0fc7e02009-09-30 09:12:17 -0700171static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000172static int rwbf_quirk;
173
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000174/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700175 * set to 1 to panic kernel if can't successfully enable VT-d
176 * (used when kernel is launched w/ TXT)
177 */
178static int force_on = 0;
179
180/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000181 * 0: Present
182 * 1-11: Reserved
183 * 12-63: Context Ptr (12 - (haw-1))
184 * 64-127: Reserved
185 */
186struct root_entry {
187 u64 val;
188 u64 rsvd1;
189};
190#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
191static inline bool root_present(struct root_entry *root)
192{
193 return (root->val & 1);
194}
195static inline void set_root_present(struct root_entry *root)
196{
197 root->val |= 1;
198}
199static inline void set_root_value(struct root_entry *root, unsigned long value)
200{
201 root->val |= value & VTD_PAGE_MASK;
202}
203
204static inline struct context_entry *
205get_context_addr_from_root(struct root_entry *root)
206{
207 return (struct context_entry *)
208 (root_present(root)?phys_to_virt(
209 root->val & VTD_PAGE_MASK) :
210 NULL);
211}
212
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000213/*
214 * low 64 bits:
215 * 0: present
216 * 1: fault processing disable
217 * 2-3: translation type
218 * 12-63: address space root
219 * high 64 bits:
220 * 0-2: address width
221 * 3-6: aval
222 * 8-23: domain id
223 */
224struct context_entry {
225 u64 lo;
226 u64 hi;
227};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000228
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000229static inline bool context_present(struct context_entry *context)
230{
231 return (context->lo & 1);
232}
233static inline void context_set_present(struct context_entry *context)
234{
235 context->lo |= 1;
236}
237
238static inline void context_set_fault_enable(struct context_entry *context)
239{
240 context->lo &= (((u64)-1) << 2) | 1;
241}
242
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000243static inline void context_set_translation_type(struct context_entry *context,
244 unsigned long value)
245{
246 context->lo &= (((u64)-1) << 4) | 3;
247 context->lo |= (value & 3) << 2;
248}
249
250static inline void context_set_address_root(struct context_entry *context,
251 unsigned long value)
252{
253 context->lo |= value & VTD_PAGE_MASK;
254}
255
256static inline void context_set_address_width(struct context_entry *context,
257 unsigned long value)
258{
259 context->hi |= value & 7;
260}
261
262static inline void context_set_domain_id(struct context_entry *context,
263 unsigned long value)
264{
265 context->hi |= (value & ((1 << 16) - 1)) << 8;
266}
267
268static inline void context_clear_entry(struct context_entry *context)
269{
270 context->lo = 0;
271 context->hi = 0;
272}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000273
Mark McLoughlin622ba122008-11-20 15:49:46 +0000274/*
275 * 0: readable
276 * 1: writable
277 * 2-6: reserved
278 * 7: super page
Sheng Yang9cf06692009-03-18 15:33:07 +0800279 * 8-10: available
280 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000281 * 12-63: Host physcial address
282 */
283struct dma_pte {
284 u64 val;
285};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000286
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000287static inline void dma_clear_pte(struct dma_pte *pte)
288{
289 pte->val = 0;
290}
291
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 Woodhouse276dbf92009-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 Woodhouse276dbf92009-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 Woodhouse276dbf92009-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)) {
Jiang Liua4eaa862014-02-19 14:07:30 +08001300 /*
1301 * Domain id 0 is reserved for invalid translation
1302 * if hardware supports caching mode.
1303 */
1304 if (cap_caching_mode(iommu->cap) && i == 0)
1305 continue;
1306
Donald Dutile94a91b52009-08-20 16:51:34 -04001307 domain = iommu->domains[i];
1308 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001309
Donald Dutile94a91b52009-08-20 16:51:34 -04001310 spin_lock_irqsave(&domain->iommu_lock, flags);
Jiang Liu5ced12a2014-01-06 14:18:22 +08001311 count = --domain->iommu_count;
1312 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001313 if (count == 0)
1314 domain_exit(domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001315 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001316 }
1317
1318 if (iommu->gcmd & DMA_GCMD_TE)
1319 iommu_disable_translation(iommu);
1320
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001321 kfree(iommu->domains);
1322 kfree(iommu->domain_ids);
Jiang Liua868e6b2014-01-06 14:18:20 +08001323 iommu->domains = NULL;
1324 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001325
Weidong Hand9630fe2008-12-08 11:06:32 +08001326 g_iommus[iommu->seq_id] = NULL;
1327
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001328 /* free context mapping */
1329 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001330}
1331
Jiang Liu92d03cc2014-02-19 14:07:28 +08001332static struct dmar_domain *alloc_domain(bool vm)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001333{
Jiang Liu92d03cc2014-02-19 14:07:28 +08001334 /* domain id for virtual machine, it won't be set in context */
1335 static atomic_t vm_domid = ATOMIC_INIT(0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001336 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001337
1338 domain = alloc_domain_mem();
1339 if (!domain)
1340 return NULL;
1341
Suresh Siddha4c923d42009-10-02 11:01:24 -07001342 domain->nid = -1;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001343 domain->iommu_count = 0;
Mike Travis1b198bb2012-03-05 15:05:16 -08001344 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001345 domain->flags = 0;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001346 spin_lock_init(&domain->iommu_lock);
1347 INIT_LIST_HEAD(&domain->devices);
1348 if (vm) {
1349 domain->id = atomic_inc_return(&vm_domid);
1350 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
1351 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001352
1353 return domain;
1354}
1355
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001356static int iommu_attach_domain(struct dmar_domain *domain,
1357 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001358{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001359 int num;
1360 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001361 unsigned long flags;
1362
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001363 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001364
1365 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001366
1367 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1368 if (num >= ndomains) {
1369 spin_unlock_irqrestore(&iommu->lock, flags);
1370 printk(KERN_ERR "IOMMU: no free domain ids\n");
1371 return -ENOMEM;
1372 }
1373
1374 domain->id = num;
Jiang Liu9ebd6822014-02-19 14:07:29 +08001375 domain->iommu_count++;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001376 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001377 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001378 iommu->domains[num] = domain;
1379 spin_unlock_irqrestore(&iommu->lock, flags);
1380
1381 return 0;
1382}
1383
1384static void iommu_detach_domain(struct dmar_domain *domain,
1385 struct intel_iommu *iommu)
1386{
1387 unsigned long flags;
1388 int num, ndomains;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001389
1390 spin_lock_irqsave(&iommu->lock, flags);
1391 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001392 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001393 if (iommu->domains[num] == domain) {
Jiang Liu92d03cc2014-02-19 14:07:28 +08001394 clear_bit(num, iommu->domain_ids);
1395 iommu->domains[num] = NULL;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001396 break;
1397 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001398 }
Weidong Han8c11e792008-12-08 15:29:22 +08001399 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001400}
1401
1402static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001403static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001404
Joseph Cihula51a63e62011-03-21 11:04:24 -07001405static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001406{
1407 struct pci_dev *pdev = NULL;
1408 struct iova *iova;
1409 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001410
David Millerf6611972008-02-06 01:36:23 -08001411 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001412
Mark Gross8a443df2008-03-04 14:59:31 -08001413 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1414 &reserved_rbtree_key);
1415
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001416 /* IOAPIC ranges shouldn't be accessed by DMA */
1417 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1418 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001419 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001420 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001421 return -ENODEV;
1422 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001423
1424 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1425 for_each_pci_dev(pdev) {
1426 struct resource *r;
1427
1428 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1429 r = &pdev->resource[i];
1430 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1431 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001432 iova = reserve_iova(&reserved_iova_list,
1433 IOVA_PFN(r->start),
1434 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001435 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001436 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001437 return -ENODEV;
1438 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001439 }
1440 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001441 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001442}
1443
1444static void domain_reserve_special_ranges(struct dmar_domain *domain)
1445{
1446 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1447}
1448
1449static inline int guestwidth_to_adjustwidth(int gaw)
1450{
1451 int agaw;
1452 int r = (gaw - 12) % 9;
1453
1454 if (r == 0)
1455 agaw = gaw;
1456 else
1457 agaw = gaw + 9 - r;
1458 if (agaw > 64)
1459 agaw = 64;
1460 return agaw;
1461}
1462
1463static int domain_init(struct dmar_domain *domain, int guest_width)
1464{
1465 struct intel_iommu *iommu;
1466 int adjust_width, agaw;
1467 unsigned long sagaw;
1468
David Millerf6611972008-02-06 01:36:23 -08001469 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001470 domain_reserve_special_ranges(domain);
1471
1472 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001473 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001474 if (guest_width > cap_mgaw(iommu->cap))
1475 guest_width = cap_mgaw(iommu->cap);
1476 domain->gaw = guest_width;
1477 adjust_width = guestwidth_to_adjustwidth(guest_width);
1478 agaw = width_to_agaw(adjust_width);
1479 sagaw = cap_sagaw(iommu->cap);
1480 if (!test_bit(agaw, &sagaw)) {
1481 /* hardware doesn't support it, choose a bigger one */
1482 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1483 agaw = find_next_bit(&sagaw, 5, agaw);
1484 if (agaw >= 5)
1485 return -ENODEV;
1486 }
1487 domain->agaw = agaw;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001488
Weidong Han8e6040972008-12-08 15:49:06 +08001489 if (ecap_coherent(iommu->ecap))
1490 domain->iommu_coherency = 1;
1491 else
1492 domain->iommu_coherency = 0;
1493
Sheng Yang58c610b2009-03-18 15:33:05 +08001494 if (ecap_sc_support(iommu->ecap))
1495 domain->iommu_snooping = 1;
1496 else
1497 domain->iommu_snooping = 0;
1498
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001499 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Suresh Siddha4c923d42009-10-02 11:01:24 -07001500 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001501
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001502 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001503 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001504 if (!domain->pgd)
1505 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001506 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001507 return 0;
1508}
1509
1510static void domain_exit(struct dmar_domain *domain)
1511{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001512 struct dmar_drhd_unit *drhd;
1513 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001514
1515 /* Domain 0 is reserved, so dont process it */
1516 if (!domain)
1517 return;
1518
Alex Williamson7b668352011-05-24 12:02:41 +01001519 /* Flush any lazy unmaps that may reference this domain */
1520 if (!intel_iommu_strict)
1521 flush_unmaps_timeout(0);
1522
Jiang Liu92d03cc2014-02-19 14:07:28 +08001523 /* remove associated devices */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001524 domain_remove_dev_info(domain);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001525
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001526 /* destroy iovas */
1527 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001528
1529 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001530 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001531
1532 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001533 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001534
Jiang Liu92d03cc2014-02-19 14:07:28 +08001535 /* clear attached or cached domains */
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001536 for_each_active_iommu(iommu, drhd)
Jiang Liu92d03cc2014-02-19 14:07:28 +08001537 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1538 test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001539 iommu_detach_domain(domain, iommu);
1540
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001541 free_domain_mem(domain);
1542}
1543
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001544static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1545 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001546{
1547 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001548 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001549 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001550 struct dma_pte *pgd;
1551 unsigned long num;
1552 unsigned long ndomains;
1553 int id;
1554 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001555 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001556
1557 pr_debug("Set context mapping for %02x:%02x.%d\n",
1558 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001559
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001560 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001561 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1562 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001563
David Woodhouse276dbf92009-04-04 01:45:37 +01001564 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001565 if (!iommu)
1566 return -ENODEV;
1567
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001568 context = device_to_context_entry(iommu, bus, devfn);
1569 if (!context)
1570 return -ENOMEM;
1571 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001572 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001573 spin_unlock_irqrestore(&iommu->lock, flags);
1574 return 0;
1575 }
1576
Weidong Hanea6606b2008-12-08 23:08:15 +08001577 id = domain->id;
1578 pgd = domain->pgd;
1579
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001580 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1581 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001582 int found = 0;
1583
1584 /* find an available domain id for this device in iommu */
1585 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001586 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001587 if (iommu->domains[num] == domain) {
1588 id = num;
1589 found = 1;
1590 break;
1591 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001592 }
1593
1594 if (found == 0) {
1595 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1596 if (num >= ndomains) {
1597 spin_unlock_irqrestore(&iommu->lock, flags);
1598 printk(KERN_ERR "IOMMU: no free domain ids\n");
1599 return -EFAULT;
1600 }
1601
1602 set_bit(num, iommu->domain_ids);
1603 iommu->domains[num] = domain;
1604 id = num;
1605 }
1606
1607 /* Skip top levels of page tables for
1608 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001609 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001610 */
Chris Wright1672af12009-12-02 12:06:34 -08001611 if (translation != CONTEXT_TT_PASS_THROUGH) {
1612 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1613 pgd = phys_to_virt(dma_pte_addr(pgd));
1614 if (!dma_pte_present(pgd)) {
1615 spin_unlock_irqrestore(&iommu->lock, flags);
1616 return -ENOMEM;
1617 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001618 }
1619 }
1620 }
1621
1622 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001623
Yu Zhao93a23a72009-05-18 13:51:37 +08001624 if (translation != CONTEXT_TT_PASS_THROUGH) {
1625 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1626 translation = info ? CONTEXT_TT_DEV_IOTLB :
1627 CONTEXT_TT_MULTI_LEVEL;
1628 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001629 /*
1630 * In pass through mode, AW must be programmed to indicate the largest
1631 * AGAW value supported by hardware. And ASR is ignored by hardware.
1632 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001633 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001634 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001635 else {
1636 context_set_address_root(context, virt_to_phys(pgd));
1637 context_set_address_width(context, iommu->agaw);
1638 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001639
1640 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001641 context_set_fault_enable(context);
1642 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001643 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001644
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001645 /*
1646 * It's a non-present to present mapping. If hardware doesn't cache
1647 * non-present entry we only need to flush the write-buffer. If the
1648 * _does_ cache non-present entries, then it does so in the special
1649 * domain #0, which we have to flush:
1650 */
1651 if (cap_caching_mode(iommu->cap)) {
1652 iommu->flush.flush_context(iommu, 0,
1653 (((u16)bus) << 8) | devfn,
1654 DMA_CCMD_MASK_NOBIT,
1655 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001656 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001657 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001658 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001659 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001660 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001661 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001662
1663 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001664 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001665 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001666 if (domain->iommu_count == 1)
1667 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001668 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001669 }
1670 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001671 return 0;
1672}
1673
1674static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001675domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1676 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001677{
1678 int ret;
1679 struct pci_dev *tmp, *parent;
1680
David Woodhouse276dbf92009-04-04 01:45:37 +01001681 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001682 pdev->bus->number, pdev->devfn,
1683 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001684 if (ret)
1685 return ret;
1686
1687 /* dependent device mapping */
1688 tmp = pci_find_upstream_pcie_bridge(pdev);
1689 if (!tmp)
1690 return 0;
1691 /* Secondary interface's bus number and devfn 0 */
1692 parent = pdev->bus->self;
1693 while (parent != tmp) {
David Woodhouse276dbf92009-04-04 01:45:37 +01001694 ret = domain_context_mapping_one(domain,
1695 pci_domain_nr(parent->bus),
1696 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001697 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001698 if (ret)
1699 return ret;
1700 parent = parent->bus->self;
1701 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001702 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001703 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001704 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001705 tmp->subordinate->number, 0,
1706 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001707 else /* this is a legacy PCI bridge */
1708 return domain_context_mapping_one(domain,
David Woodhouse276dbf92009-04-04 01:45:37 +01001709 pci_domain_nr(tmp->bus),
1710 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001711 tmp->devfn,
1712 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001713}
1714
Weidong Han5331fe62008-12-08 23:00:00 +08001715static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001716{
1717 int ret;
1718 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001719 struct intel_iommu *iommu;
1720
David Woodhouse276dbf92009-04-04 01:45:37 +01001721 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1722 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001723 if (!iommu)
1724 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001725
David Woodhouse276dbf92009-04-04 01:45:37 +01001726 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001727 if (!ret)
1728 return ret;
1729 /* dependent device mapping */
1730 tmp = pci_find_upstream_pcie_bridge(pdev);
1731 if (!tmp)
1732 return ret;
1733 /* Secondary interface's bus number and devfn 0 */
1734 parent = pdev->bus->self;
1735 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001736 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01001737 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001738 if (!ret)
1739 return ret;
1740 parent = parent->bus->self;
1741 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001742 if (pci_is_pcie(tmp))
David Woodhouse276dbf92009-04-04 01:45:37 +01001743 return device_context_mapped(iommu, tmp->subordinate->number,
1744 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001745 else
David Woodhouse276dbf92009-04-04 01:45:37 +01001746 return device_context_mapped(iommu, tmp->bus->number,
1747 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001748}
1749
Fenghua Yuf5329592009-08-04 15:09:37 -07001750/* Returns a number of VTD pages, but aligned to MM page size */
1751static inline unsigned long aligned_nrpages(unsigned long host_addr,
1752 size_t size)
1753{
1754 host_addr &= ~PAGE_MASK;
1755 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1756}
1757
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001758/* Return largest possible superpage level for a given mapping */
1759static inline int hardware_largepage_caps(struct dmar_domain *domain,
1760 unsigned long iov_pfn,
1761 unsigned long phy_pfn,
1762 unsigned long pages)
1763{
1764 int support, level = 1;
1765 unsigned long pfnmerge;
1766
1767 support = domain->iommu_superpage;
1768
1769 /* To use a large page, the virtual *and* physical addresses
1770 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1771 of them will mean we have to use smaller pages. So just
1772 merge them and check both at once. */
1773 pfnmerge = iov_pfn | phy_pfn;
1774
1775 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1776 pages >>= VTD_STRIDE_SHIFT;
1777 if (!pages)
1778 break;
1779 pfnmerge >>= VTD_STRIDE_SHIFT;
1780 level++;
1781 support--;
1782 }
1783 return level;
1784}
1785
David Woodhouse9051aa02009-06-29 12:30:54 +01001786static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1787 struct scatterlist *sg, unsigned long phys_pfn,
1788 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001789{
1790 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001791 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001792 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001793 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001794 unsigned int largepage_lvl = 0;
1795 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001796
1797 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1798
1799 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1800 return -EINVAL;
1801
1802 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1803
David Woodhouse9051aa02009-06-29 12:30:54 +01001804 if (sg)
1805 sg_res = 0;
1806 else {
1807 sg_res = nr_pages + 1;
1808 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1809 }
1810
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001811 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001812 uint64_t tmp;
1813
David Woodhousee1605492009-06-29 11:17:38 +01001814 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001815 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001816 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1817 sg->dma_length = sg->length;
1818 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001819 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001820 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001821
David Woodhousee1605492009-06-29 11:17:38 +01001822 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001823 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1824
1825 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001826 if (!pte)
1827 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001828 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001829 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001830 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001831 /* Ensure that old small page tables are removed to make room
1832 for superpage, if they exist. */
1833 dma_pte_clear_range(domain, iov_pfn,
1834 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1835 dma_pte_free_pagetable(domain, iov_pfn,
1836 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1837 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001838 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001839 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001840
David Woodhousee1605492009-06-29 11:17:38 +01001841 }
1842 /* We don't need lock here, nobody else
1843 * touches the iova range
1844 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001845 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001846 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001847 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001848 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1849 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001850 if (dumps) {
1851 dumps--;
1852 debug_dma_dump_mappings(NULL);
1853 }
1854 WARN_ON(1);
1855 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001856
1857 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1858
1859 BUG_ON(nr_pages < lvl_pages);
1860 BUG_ON(sg_res < lvl_pages);
1861
1862 nr_pages -= lvl_pages;
1863 iov_pfn += lvl_pages;
1864 phys_pfn += lvl_pages;
1865 pteval += lvl_pages * VTD_PAGE_SIZE;
1866 sg_res -= lvl_pages;
1867
1868 /* If the next PTE would be the first in a new page, then we
1869 need to flush the cache on the entries we've just written.
1870 And then we'll need to recalculate 'pte', so clear it and
1871 let it get set again in the if (!pte) block above.
1872
1873 If we're done (!nr_pages) we need to flush the cache too.
1874
1875 Also if we've been setting superpages, we may need to
1876 recalculate 'pte' and switch back to smaller pages for the
1877 end of the mapping, if the trailing size is not enough to
1878 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001879 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001880 if (!nr_pages || first_pte_in_page(pte) ||
1881 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001882 domain_flush_cache(domain, first_pte,
1883 (void *)pte - (void *)first_pte);
1884 pte = NULL;
1885 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001886
1887 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001888 sg = sg_next(sg);
1889 }
1890 return 0;
1891}
1892
David Woodhouse9051aa02009-06-29 12:30:54 +01001893static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1894 struct scatterlist *sg, unsigned long nr_pages,
1895 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001896{
David Woodhouse9051aa02009-06-29 12:30:54 +01001897 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1898}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001899
David Woodhouse9051aa02009-06-29 12:30:54 +01001900static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1901 unsigned long phys_pfn, unsigned long nr_pages,
1902 int prot)
1903{
1904 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001905}
1906
Weidong Hanc7151a82008-12-08 22:51:37 +08001907static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001908{
Weidong Hanc7151a82008-12-08 22:51:37 +08001909 if (!iommu)
1910 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001911
1912 clear_context_table(iommu, bus, devfn);
1913 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001914 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001915 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001916}
1917
David Woodhouse109b9b02012-05-25 17:43:02 +01001918static inline void unlink_domain_info(struct device_domain_info *info)
1919{
1920 assert_spin_locked(&device_domain_lock);
1921 list_del(&info->link);
1922 list_del(&info->global);
1923 if (info->dev)
1924 info->dev->dev.archdata.iommu = NULL;
1925}
1926
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001927static void domain_remove_dev_info(struct dmar_domain *domain)
1928{
1929 struct device_domain_info *info;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001930 unsigned long flags, flags2;
Weidong Hanc7151a82008-12-08 22:51:37 +08001931 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001932
1933 spin_lock_irqsave(&device_domain_lock, flags);
1934 while (!list_empty(&domain->devices)) {
1935 info = list_entry(domain->devices.next,
1936 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01001937 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001938 spin_unlock_irqrestore(&device_domain_lock, flags);
1939
Yu Zhao93a23a72009-05-18 13:51:37 +08001940 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf92009-04-04 01:45:37 +01001941 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001942 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001943
Jiang Liu92d03cc2014-02-19 14:07:28 +08001944 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
1945 iommu_detach_dependent_devices(iommu, info->dev);
1946 /* clear this iommu in iommu_bmp, update iommu count
1947 * and capabilities
1948 */
1949 spin_lock_irqsave(&domain->iommu_lock, flags2);
1950 if (test_and_clear_bit(iommu->seq_id,
1951 domain->iommu_bmp)) {
1952 domain->iommu_count--;
1953 domain_update_iommu_cap(domain);
1954 }
1955 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
1956 }
1957
1958 free_devinfo_mem(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001959 spin_lock_irqsave(&device_domain_lock, flags);
1960 }
1961 spin_unlock_irqrestore(&device_domain_lock, flags);
1962}
1963
1964/*
1965 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001966 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001967 */
Kay, Allen M38717942008-09-09 18:37:29 +03001968static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001969find_domain(struct pci_dev *pdev)
1970{
1971 struct device_domain_info *info;
1972
1973 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001974 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001975 if (info)
1976 return info->domain;
1977 return NULL;
1978}
1979
Jiang Liu745f2582014-02-19 14:07:26 +08001980static inline struct dmar_domain *
1981dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
1982{
1983 struct device_domain_info *info;
1984
1985 list_for_each_entry(info, &device_domain_list, global)
1986 if (info->segment == segment && info->bus == bus &&
1987 info->devfn == devfn)
1988 return info->domain;
1989
1990 return NULL;
1991}
1992
1993static int dmar_insert_dev_info(int segment, int bus, int devfn,
1994 struct pci_dev *dev, struct dmar_domain **domp)
1995{
1996 struct dmar_domain *found, *domain = *domp;
1997 struct device_domain_info *info;
1998 unsigned long flags;
1999
2000 info = alloc_devinfo_mem();
2001 if (!info)
2002 return -ENOMEM;
2003
2004 info->segment = segment;
2005 info->bus = bus;
2006 info->devfn = devfn;
2007 info->dev = dev;
2008 info->domain = domain;
2009 if (!dev)
2010 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
2011
2012 spin_lock_irqsave(&device_domain_lock, flags);
2013 if (dev)
2014 found = find_domain(dev);
2015 else
2016 found = dmar_search_domain_by_dev_info(segment, bus, devfn);
2017 if (found) {
2018 spin_unlock_irqrestore(&device_domain_lock, flags);
2019 free_devinfo_mem(info);
2020 if (found != domain) {
2021 domain_exit(domain);
2022 *domp = found;
2023 }
2024 } else {
2025 list_add(&info->link, &domain->devices);
2026 list_add(&info->global, &device_domain_list);
2027 if (dev)
2028 dev->dev.archdata.iommu = info;
2029 spin_unlock_irqrestore(&device_domain_lock, flags);
2030 }
2031
2032 return 0;
2033}
2034
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002035/* domain is initialized */
2036static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
2037{
Jiang Liue85bb5d2014-02-19 14:07:27 +08002038 struct dmar_domain *domain, *free = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002039 struct intel_iommu *iommu;
2040 struct dmar_drhd_unit *drhd;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002041 struct pci_dev *dev_tmp;
2042 unsigned long flags;
2043 int bus = 0, devfn = 0;
David Woodhouse276dbf92009-04-04 01:45:37 +01002044 int segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002045
2046 domain = find_domain(pdev);
2047 if (domain)
2048 return domain;
2049
David Woodhouse276dbf92009-04-04 01:45:37 +01002050 segment = pci_domain_nr(pdev->bus);
2051
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002052 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
2053 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002054 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002055 bus = dev_tmp->subordinate->number;
2056 devfn = 0;
2057 } else {
2058 bus = dev_tmp->bus->number;
2059 devfn = dev_tmp->devfn;
2060 }
2061 spin_lock_irqsave(&device_domain_lock, flags);
Jiang Liu745f2582014-02-19 14:07:26 +08002062 domain = dmar_search_domain_by_dev_info(segment, bus, devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002063 spin_unlock_irqrestore(&device_domain_lock, flags);
2064 /* pcie-pci bridge already has a domain, uses it */
Jiang Liu745f2582014-02-19 14:07:26 +08002065 if (domain)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002066 goto found_domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002067 }
2068
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002069 drhd = dmar_find_matched_drhd_unit(pdev);
2070 if (!drhd) {
2071 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2072 pci_name(pdev));
2073 return NULL;
2074 }
2075 iommu = drhd->iommu;
2076
Jiang Liu745f2582014-02-19 14:07:26 +08002077 /* Allocate and intialize new domain for the device */
Jiang Liu92d03cc2014-02-19 14:07:28 +08002078 domain = alloc_domain(false);
Jiang Liu745f2582014-02-19 14:07:26 +08002079 if (!domain)
2080 goto error;
2081 if (iommu_attach_domain(domain, iommu)) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002082 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002083 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002084 }
Jiang Liue85bb5d2014-02-19 14:07:27 +08002085 free = domain;
2086 if (domain_init(domain, gaw))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002087 goto error;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002088
2089 /* register pcie-to-pci device */
2090 if (dev_tmp) {
Jiang Liue85bb5d2014-02-19 14:07:27 +08002091 if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002092 goto error;
Jiang Liue85bb5d2014-02-19 14:07:27 +08002093 else
2094 free = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002095 }
2096
2097found_domain:
Jiang Liu745f2582014-02-19 14:07:26 +08002098 if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
2099 pdev, &domain) == 0)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002100 return domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002101error:
Jiang Liue85bb5d2014-02-19 14:07:27 +08002102 if (free)
2103 domain_exit(free);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002104 /* recheck it here, maybe others set it */
2105 return find_domain(pdev);
2106}
2107
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002108static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002109#define IDENTMAP_ALL 1
2110#define IDENTMAP_GFX 2
2111#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002112
David Woodhouseb2132032009-06-26 18:50:28 +01002113static int iommu_domain_identity_map(struct dmar_domain *domain,
2114 unsigned long long start,
2115 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002116{
David Woodhousec5395d52009-06-28 16:35:56 +01002117 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2118 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002119
David Woodhousec5395d52009-06-28 16:35:56 +01002120 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2121 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002122 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002123 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002124 }
2125
David Woodhousec5395d52009-06-28 16:35:56 +01002126 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2127 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002128 /*
2129 * RMRR range might have overlap with physical memory range,
2130 * clear it first
2131 */
David Woodhousec5395d52009-06-28 16:35:56 +01002132 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002133
David Woodhousec5395d52009-06-28 16:35:56 +01002134 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2135 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002136 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002137}
2138
2139static int iommu_prepare_identity_map(struct pci_dev *pdev,
2140 unsigned long long start,
2141 unsigned long long end)
2142{
2143 struct dmar_domain *domain;
2144 int ret;
2145
David Woodhousec7ab48d2009-06-26 19:10:36 +01002146 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002147 if (!domain)
2148 return -ENOMEM;
2149
David Woodhouse19943b02009-08-04 16:19:20 +01002150 /* For _hardware_ passthrough, don't bother. But for software
2151 passthrough, we do it anyway -- it may indicate a memory
2152 range which is reserved in E820, so which didn't get set
2153 up to start with in si_domain */
2154 if (domain == si_domain && hw_pass_through) {
2155 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2156 pci_name(pdev), start, end);
2157 return 0;
2158 }
2159
2160 printk(KERN_INFO
2161 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2162 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002163
David Woodhouse5595b522009-12-02 09:21:55 +00002164 if (end < start) {
2165 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2166 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2167 dmi_get_system_info(DMI_BIOS_VENDOR),
2168 dmi_get_system_info(DMI_BIOS_VERSION),
2169 dmi_get_system_info(DMI_PRODUCT_VERSION));
2170 ret = -EIO;
2171 goto error;
2172 }
2173
David Woodhouse2ff729f2009-08-26 14:25:41 +01002174 if (end >> agaw_to_width(domain->agaw)) {
2175 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2176 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2177 agaw_to_width(domain->agaw),
2178 dmi_get_system_info(DMI_BIOS_VENDOR),
2179 dmi_get_system_info(DMI_BIOS_VERSION),
2180 dmi_get_system_info(DMI_PRODUCT_VERSION));
2181 ret = -EIO;
2182 goto error;
2183 }
David Woodhouse19943b02009-08-04 16:19:20 +01002184
David Woodhouseb2132032009-06-26 18:50:28 +01002185 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002186 if (ret)
2187 goto error;
2188
2189 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002190 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002191 if (ret)
2192 goto error;
2193
2194 return 0;
2195
2196 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002197 domain_exit(domain);
2198 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002199}
2200
2201static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2202 struct pci_dev *pdev)
2203{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002204 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002205 return 0;
2206 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002207 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002208}
2209
Suresh Siddhad3f13812011-08-23 17:05:25 -07002210#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002211static inline void iommu_prepare_isa(void)
2212{
2213 struct pci_dev *pdev;
2214 int ret;
2215
2216 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2217 if (!pdev)
2218 return;
2219
David Woodhousec7ab48d2009-06-26 19:10:36 +01002220 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002221 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002222
2223 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002224 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2225 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002226
2227}
2228#else
2229static inline void iommu_prepare_isa(void)
2230{
2231 return;
2232}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002233#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002234
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002235static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002236
Matt Kraai071e1372009-08-23 22:30:22 -07002237static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002238{
2239 struct dmar_drhd_unit *drhd;
2240 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002241 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002242
Jiang Liu92d03cc2014-02-19 14:07:28 +08002243 si_domain = alloc_domain(false);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002244 if (!si_domain)
2245 return -EFAULT;
2246
Jiang Liu92d03cc2014-02-19 14:07:28 +08002247 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2248
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002249 for_each_active_iommu(iommu, drhd) {
2250 ret = iommu_attach_domain(si_domain, iommu);
2251 if (ret) {
2252 domain_exit(si_domain);
2253 return -EFAULT;
2254 }
2255 }
2256
2257 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2258 domain_exit(si_domain);
2259 return -EFAULT;
2260 }
2261
Jiang Liu9544c002014-01-06 14:18:13 +08002262 pr_debug("IOMMU: identity mapping domain is domain %d\n",
2263 si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002264
David Woodhouse19943b02009-08-04 16:19:20 +01002265 if (hw)
2266 return 0;
2267
David Woodhousec7ab48d2009-06-26 19:10:36 +01002268 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002269 unsigned long start_pfn, end_pfn;
2270 int i;
2271
2272 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2273 ret = iommu_domain_identity_map(si_domain,
2274 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2275 if (ret)
2276 return ret;
2277 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002278 }
2279
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002280 return 0;
2281}
2282
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002283static int identity_mapping(struct pci_dev *pdev)
2284{
2285 struct device_domain_info *info;
2286
2287 if (likely(!iommu_identity_mapping))
2288 return 0;
2289
Mike Traviscb452a42011-05-28 13:15:03 -05002290 info = pdev->dev.archdata.iommu;
2291 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2292 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002293
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002294 return 0;
2295}
2296
2297static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002298 struct pci_dev *pdev,
2299 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002300{
2301 struct device_domain_info *info;
2302 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002303 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002304
2305 info = alloc_devinfo_mem();
2306 if (!info)
2307 return -ENOMEM;
2308
2309 info->segment = pci_domain_nr(pdev->bus);
2310 info->bus = pdev->bus->number;
2311 info->devfn = pdev->devfn;
2312 info->dev = pdev;
2313 info->domain = domain;
2314
2315 spin_lock_irqsave(&device_domain_lock, flags);
2316 list_add(&info->link, &domain->devices);
2317 list_add(&info->global, &device_domain_list);
2318 pdev->dev.archdata.iommu = info;
2319 spin_unlock_irqrestore(&device_domain_lock, flags);
2320
David Woodhousee2ad23d2012-05-25 17:42:54 +01002321 ret = domain_context_mapping(domain, pdev, translation);
2322 if (ret) {
2323 spin_lock_irqsave(&device_domain_lock, flags);
David Woodhouse109b9b02012-05-25 17:43:02 +01002324 unlink_domain_info(info);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002325 spin_unlock_irqrestore(&device_domain_lock, flags);
2326 free_devinfo_mem(info);
2327 return ret;
2328 }
2329
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002330 return 0;
2331}
2332
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002333static bool device_has_rmrr(struct pci_dev *dev)
2334{
2335 struct dmar_rmrr_unit *rmrr;
2336 int i;
2337
2338 for_each_rmrr_units(rmrr) {
2339 for (i = 0; i < rmrr->devices_cnt; i++) {
2340 /*
2341 * Return TRUE if this RMRR contains the device that
2342 * is passed in.
2343 */
2344 if (rmrr->devices[i] == dev)
2345 return true;
2346 }
2347 }
2348 return false;
2349}
2350
David Woodhouse6941af22009-07-04 18:24:27 +01002351static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2352{
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002353
2354 /*
2355 * We want to prevent any device associated with an RMRR from
2356 * getting placed into the SI Domain. This is done because
2357 * problems exist when devices are moved in and out of domains
2358 * and their respective RMRR info is lost. We exempt USB devices
2359 * from this process due to their usage of RMRRs that are known
2360 * to not be needed after BIOS hand-off to OS.
2361 */
2362 if (device_has_rmrr(pdev) &&
2363 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2364 return 0;
2365
David Woodhousee0fc7e02009-09-30 09:12:17 -07002366 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2367 return 1;
2368
2369 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2370 return 1;
2371
2372 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2373 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002374
David Woodhouse3dfc8132009-07-04 19:11:08 +01002375 /*
2376 * We want to start off with all devices in the 1:1 domain, and
2377 * take them out later if we find they can't access all of memory.
2378 *
2379 * However, we can't do this for PCI devices behind bridges,
2380 * because all PCI devices behind the same bridge will end up
2381 * with the same source-id on their transactions.
2382 *
2383 * Practically speaking, we can't change things around for these
2384 * devices at run-time, because we can't be sure there'll be no
2385 * DMA transactions in flight for any of their siblings.
2386 *
2387 * So PCI devices (unless they're on the root bus) as well as
2388 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2389 * the 1:1 domain, just in _case_ one of their siblings turns out
2390 * not to be able to map all of memory.
2391 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002392 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002393 if (!pci_is_root_bus(pdev->bus))
2394 return 0;
2395 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2396 return 0;
Yijing Wang62f87c02012-07-24 17:20:03 +08002397 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
David Woodhouse3dfc8132009-07-04 19:11:08 +01002398 return 0;
2399
2400 /*
2401 * At boot time, we don't yet know if devices will be 64-bit capable.
2402 * Assume that they will -- if they turn out not to be, then we can
2403 * take them out of the 1:1 domain later.
2404 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002405 if (!startup) {
2406 /*
2407 * If the device's dma_mask is less than the system's memory
2408 * size then this is not a candidate for identity mapping.
2409 */
2410 u64 dma_mask = pdev->dma_mask;
2411
2412 if (pdev->dev.coherent_dma_mask &&
2413 pdev->dev.coherent_dma_mask < dma_mask)
2414 dma_mask = pdev->dev.coherent_dma_mask;
2415
2416 return dma_mask >= dma_get_required_mask(&pdev->dev);
2417 }
David Woodhouse6941af22009-07-04 18:24:27 +01002418
2419 return 1;
2420}
2421
Matt Kraai071e1372009-08-23 22:30:22 -07002422static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002423{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002424 struct pci_dev *pdev = NULL;
2425 int ret;
2426
David Woodhouse19943b02009-08-04 16:19:20 +01002427 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002428 if (ret)
2429 return -EFAULT;
2430
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002431 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002432 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002433 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002434 hw ? CONTEXT_TT_PASS_THROUGH :
2435 CONTEXT_TT_MULTI_LEVEL);
2436 if (ret) {
2437 /* device not associated with an iommu */
2438 if (ret == -ENODEV)
2439 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002440 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002441 }
2442 pr_info("IOMMU: %s identity mapping for device %s\n",
2443 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002444 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002445 }
2446
2447 return 0;
2448}
2449
Joseph Cihulab7792602011-05-03 00:08:37 -07002450static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002451{
2452 struct dmar_drhd_unit *drhd;
2453 struct dmar_rmrr_unit *rmrr;
2454 struct pci_dev *pdev;
2455 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002456 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002457
2458 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002459 * for each drhd
2460 * allocate root
2461 * initialize and program root entry to not present
2462 * endfor
2463 */
2464 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002465 /*
2466 * lock not needed as this is only incremented in the single
2467 * threaded kernel __init code path all other access are read
2468 * only
2469 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002470 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2471 g_num_of_iommus++;
2472 continue;
2473 }
2474 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2475 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002476 }
2477
Weidong Hand9630fe2008-12-08 11:06:32 +08002478 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2479 GFP_KERNEL);
2480 if (!g_iommus) {
2481 printk(KERN_ERR "Allocating global iommu array failed\n");
2482 ret = -ENOMEM;
2483 goto error;
2484 }
2485
mark gross80b20dd2008-04-18 13:53:58 -07002486 deferred_flush = kzalloc(g_num_of_iommus *
2487 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2488 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002489 ret = -ENOMEM;
Jiang Liu989d51f2014-02-19 14:07:21 +08002490 goto free_g_iommus;
mark gross5e0d2a62008-03-04 15:22:08 -08002491 }
2492
Jiang Liu7c919772014-01-06 14:18:18 +08002493 for_each_active_iommu(iommu, drhd) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002494 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002495
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002496 ret = iommu_init_domains(iommu);
2497 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002498 goto free_iommu;
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002499
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002500 /*
2501 * TBD:
2502 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002503 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002504 */
2505 ret = iommu_alloc_root_entry(iommu);
2506 if (ret) {
2507 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002508 goto free_iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002509 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002510 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002511 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002512 }
2513
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002514 /*
2515 * Start from the sane iommu hardware state.
2516 */
Jiang Liu7c919772014-01-06 14:18:18 +08002517 for_each_active_iommu(iommu, drhd) {
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002518 /*
2519 * If the queued invalidation is already initialized by us
2520 * (for example, while enabling interrupt-remapping) then
2521 * we got the things already rolling from a sane state.
2522 */
2523 if (iommu->qi)
2524 continue;
2525
2526 /*
2527 * Clear any previous faults.
2528 */
2529 dmar_fault(-1, iommu);
2530 /*
2531 * Disable queued invalidation if supported and already enabled
2532 * before OS handover.
2533 */
2534 dmar_disable_qi(iommu);
2535 }
2536
Jiang Liu7c919772014-01-06 14:18:18 +08002537 for_each_active_iommu(iommu, drhd) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002538 if (dmar_enable_qi(iommu)) {
2539 /*
2540 * Queued Invalidate not enabled, use Register Based
2541 * Invalidate
2542 */
2543 iommu->flush.flush_context = __iommu_flush_context;
2544 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002545 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
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 } else {
2550 iommu->flush.flush_context = qi_flush_context;
2551 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002552 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002553 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002554 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002555 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002556 }
2557 }
2558
David Woodhouse19943b02009-08-04 16:19:20 +01002559 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002560 iommu_identity_mapping |= IDENTMAP_ALL;
2561
Suresh Siddhad3f13812011-08-23 17:05:25 -07002562#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002563 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002564#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002565
2566 check_tylersburg_isoch();
2567
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002568 /*
2569 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002570 * identity mappings for rmrr, gfx, and isa and may fall back to static
2571 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002572 */
David Woodhouse19943b02009-08-04 16:19:20 +01002573 if (iommu_identity_mapping) {
2574 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2575 if (ret) {
2576 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002577 goto free_iommu;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002578 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002579 }
David Woodhouse19943b02009-08-04 16:19:20 +01002580 /*
2581 * For each rmrr
2582 * for each dev attached to rmrr
2583 * do
2584 * locate drhd for dev, alloc domain for dev
2585 * allocate free domain
2586 * allocate page table entries for rmrr
2587 * if context not allocated for bus
2588 * allocate and init context
2589 * set present in root table for this bus
2590 * init context with domain, translation etc
2591 * endfor
2592 * endfor
2593 */
2594 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2595 for_each_rmrr_units(rmrr) {
2596 for (i = 0; i < rmrr->devices_cnt; i++) {
2597 pdev = rmrr->devices[i];
2598 /*
2599 * some BIOS lists non-exist devices in DMAR
2600 * table.
2601 */
2602 if (!pdev)
2603 continue;
2604 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2605 if (ret)
2606 printk(KERN_ERR
2607 "IOMMU: mapping reserved region failed\n");
2608 }
2609 }
2610
2611 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002612
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002613 /*
2614 * for each drhd
2615 * enable fault log
2616 * global invalidate context cache
2617 * global invalidate iotlb
2618 * enable translation
2619 */
Jiang Liu7c919772014-01-06 14:18:18 +08002620 for_each_iommu(iommu, drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002621 if (drhd->ignored) {
2622 /*
2623 * we always have to disable PMRs or DMA may fail on
2624 * this device
2625 */
2626 if (force_on)
Jiang Liu7c919772014-01-06 14:18:18 +08002627 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002628 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002629 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002630
2631 iommu_flush_write_buffer(iommu);
2632
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002633 ret = dmar_set_interrupt(iommu);
2634 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002635 goto free_iommu;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002636
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002637 iommu_set_root_entry(iommu);
2638
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002639 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002640 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002641
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002642 ret = iommu_enable_translation(iommu);
2643 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002644 goto free_iommu;
David Woodhouseb94996c2009-09-19 15:28:12 -07002645
2646 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002647 }
2648
2649 return 0;
Jiang Liu989d51f2014-02-19 14:07:21 +08002650
2651free_iommu:
Jiang Liu7c919772014-01-06 14:18:18 +08002652 for_each_active_iommu(iommu, drhd)
Jiang Liua868e6b2014-01-06 14:18:20 +08002653 free_dmar_iommu(iommu);
Jiang Liu9bdc5312014-01-06 14:18:27 +08002654 kfree(deferred_flush);
Jiang Liu989d51f2014-02-19 14:07:21 +08002655free_g_iommus:
Weidong Hand9630fe2008-12-08 11:06:32 +08002656 kfree(g_iommus);
Jiang Liu989d51f2014-02-19 14:07:21 +08002657error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002658 return ret;
2659}
2660
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002661/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002662static struct iova *intel_alloc_iova(struct device *dev,
2663 struct dmar_domain *domain,
2664 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002665{
2666 struct pci_dev *pdev = to_pci_dev(dev);
2667 struct iova *iova = NULL;
2668
David Woodhouse875764d2009-06-28 21:20:51 +01002669 /* Restrict dma_mask to the width that the iommu can handle */
2670 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2671
2672 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002673 /*
2674 * First try to allocate an io virtual address in
Yang Hongyang284901a92009-04-06 19:01:15 -07002675 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002676 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002677 */
David Woodhouse875764d2009-06-28 21:20:51 +01002678 iova = alloc_iova(&domain->iovad, nrpages,
2679 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2680 if (iova)
2681 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002682 }
David Woodhouse875764d2009-06-28 21:20:51 +01002683 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2684 if (unlikely(!iova)) {
2685 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2686 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002687 return NULL;
2688 }
2689
2690 return iova;
2691}
2692
David Woodhouse147202a2009-07-07 19:43:20 +01002693static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002694{
2695 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002696 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002697
2698 domain = get_domain_for_dev(pdev,
2699 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2700 if (!domain) {
2701 printk(KERN_ERR
2702 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002703 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002704 }
2705
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002706 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002707 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002708 ret = domain_context_mapping(domain, pdev,
2709 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002710 if (ret) {
2711 printk(KERN_ERR
2712 "Domain context map for %s failed",
2713 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002714 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002715 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002716 }
2717
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002718 return domain;
2719}
2720
David Woodhouse147202a2009-07-07 19:43:20 +01002721static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2722{
2723 struct device_domain_info *info;
2724
2725 /* No lock here, assumes no domain exit in normal case */
2726 info = dev->dev.archdata.iommu;
2727 if (likely(info))
2728 return info->domain;
2729
2730 return __get_valid_domain_for_dev(dev);
2731}
2732
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002733static int iommu_dummy(struct pci_dev *pdev)
2734{
2735 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2736}
2737
2738/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002739static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002740{
David Woodhouse73676832009-07-04 14:08:36 +01002741 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002742 int found;
2743
Yijing Wangdbad0862013-12-05 19:43:42 +08002744 if (unlikely(!dev_is_pci(dev)))
David Woodhouse73676832009-07-04 14:08:36 +01002745 return 1;
2746
2747 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002748 if (iommu_dummy(pdev))
2749 return 1;
2750
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002751 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002752 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002753
2754 found = identity_mapping(pdev);
2755 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002756 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002757 return 1;
2758 else {
2759 /*
2760 * 32 bit DMA is removed from si_domain and fall back
2761 * to non-identity mapping.
2762 */
2763 domain_remove_one_dev_info(si_domain, pdev);
2764 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2765 pci_name(pdev));
2766 return 0;
2767 }
2768 } else {
2769 /*
2770 * In case of a detached 64 bit DMA device from vm, the device
2771 * is put into si_domain for identity mapping.
2772 */
David Woodhouse6941af22009-07-04 18:24:27 +01002773 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002774 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002775 ret = domain_add_dev_info(si_domain, pdev,
2776 hw_pass_through ?
2777 CONTEXT_TT_PASS_THROUGH :
2778 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002779 if (!ret) {
2780 printk(KERN_INFO "64bit %s uses identity mapping\n",
2781 pci_name(pdev));
2782 return 1;
2783 }
2784 }
2785 }
2786
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002787 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002788}
2789
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002790static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2791 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002792{
2793 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002794 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002795 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002796 struct iova *iova;
2797 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002798 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002799 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002800 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002801
2802 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002803
David Woodhouse73676832009-07-04 14:08:36 +01002804 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002805 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002806
2807 domain = get_valid_domain_for_dev(pdev);
2808 if (!domain)
2809 return 0;
2810
Weidong Han8c11e792008-12-08 15:29:22 +08002811 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002812 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002813
Mike Travisc681d0b2011-05-28 13:15:05 -05002814 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002815 if (!iova)
2816 goto error;
2817
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002818 /*
2819 * Check if DMAR supports zero-length reads on write only
2820 * mappings..
2821 */
2822 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002823 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002824 prot |= DMA_PTE_READ;
2825 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2826 prot |= DMA_PTE_WRITE;
2827 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002828 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002829 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002830 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002831 * is not a big problem
2832 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002833 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002834 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002835 if (ret)
2836 goto error;
2837
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002838 /* it's a non-present to present mapping. Only flush if caching mode */
2839 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002840 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002841 else
Weidong Han8c11e792008-12-08 15:29:22 +08002842 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002843
David Woodhouse03d6a242009-06-28 15:33:46 +01002844 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2845 start_paddr += paddr & ~PAGE_MASK;
2846 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002847
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002848error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002849 if (iova)
2850 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002851 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002852 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002853 return 0;
2854}
2855
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002856static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2857 unsigned long offset, size_t size,
2858 enum dma_data_direction dir,
2859 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002860{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002861 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2862 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002863}
2864
mark gross5e0d2a62008-03-04 15:22:08 -08002865static void flush_unmaps(void)
2866{
mark gross80b20dd2008-04-18 13:53:58 -07002867 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002868
mark gross5e0d2a62008-03-04 15:22:08 -08002869 timer_on = 0;
2870
2871 /* just flush them all */
2872 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002873 struct intel_iommu *iommu = g_iommus[i];
2874 if (!iommu)
2875 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002876
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002877 if (!deferred_flush[i].next)
2878 continue;
2879
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002880 /* In caching mode, global flushes turn emulation expensive */
2881 if (!cap_caching_mode(iommu->cap))
2882 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002883 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002884 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002885 unsigned long mask;
2886 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002887 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002888
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002889 /* On real hardware multiple invalidations are expensive */
2890 if (cap_caching_mode(iommu->cap))
2891 iommu_flush_iotlb_psi(iommu, domain->id,
2892 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2893 else {
2894 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2895 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2896 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2897 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002898 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002899 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002900 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002901 }
2902
mark gross5e0d2a62008-03-04 15:22:08 -08002903 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002904}
2905
2906static void flush_unmaps_timeout(unsigned long data)
2907{
mark gross80b20dd2008-04-18 13:53:58 -07002908 unsigned long flags;
2909
2910 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002911 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002912 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002913}
2914
2915static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2916{
2917 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002918 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002919 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002920
2921 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002922 if (list_size == HIGH_WATER_MARK)
2923 flush_unmaps();
2924
Weidong Han8c11e792008-12-08 15:29:22 +08002925 iommu = domain_get_iommu(dom);
2926 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002927
mark gross80b20dd2008-04-18 13:53:58 -07002928 next = deferred_flush[iommu_id].next;
2929 deferred_flush[iommu_id].domain[next] = dom;
2930 deferred_flush[iommu_id].iova[next] = iova;
2931 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002932
2933 if (!timer_on) {
2934 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2935 timer_on = 1;
2936 }
2937 list_size++;
2938 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2939}
2940
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002941static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2942 size_t size, enum dma_data_direction dir,
2943 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002944{
2945 struct pci_dev *pdev = to_pci_dev(dev);
2946 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002947 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002948 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002949 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002950
David Woodhouse73676832009-07-04 14:08:36 +01002951 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002952 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002953
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002954 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002955 BUG_ON(!domain);
2956
Weidong Han8c11e792008-12-08 15:29:22 +08002957 iommu = domain_get_iommu(domain);
2958
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002959 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002960 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2961 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002962 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002963
David Woodhoused794dc92009-06-28 00:27:49 +01002964 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2965 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002966
David Woodhoused794dc92009-06-28 00:27:49 +01002967 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2968 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002969
2970 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002971 dma_pte_clear_range(domain, start_pfn, last_pfn);
2972
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002973 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002974 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2975
mark gross5e0d2a62008-03-04 15:22:08 -08002976 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002977 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002978 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002979 /* free iova */
2980 __free_iova(&domain->iovad, iova);
2981 } else {
2982 add_unmap(domain, iova);
2983 /*
2984 * queue up the release of the unmap to save the 1/6th of the
2985 * cpu used up by the iotlb flush operation...
2986 */
mark gross5e0d2a62008-03-04 15:22:08 -08002987 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002988}
2989
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002990static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02002991 dma_addr_t *dma_handle, gfp_t flags,
2992 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002993{
2994 void *vaddr;
2995 int order;
2996
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002997 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002998 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002999
3000 if (!iommu_no_mapping(hwdev))
3001 flags &= ~(GFP_DMA | GFP_DMA32);
3002 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
3003 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
3004 flags |= GFP_DMA;
3005 else
3006 flags |= GFP_DMA32;
3007 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003008
3009 vaddr = (void *)__get_free_pages(flags, order);
3010 if (!vaddr)
3011 return NULL;
3012 memset(vaddr, 0, size);
3013
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003014 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
3015 DMA_BIDIRECTIONAL,
3016 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003017 if (*dma_handle)
3018 return vaddr;
3019 free_pages((unsigned long)vaddr, order);
3020 return NULL;
3021}
3022
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003023static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003024 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003025{
3026 int order;
3027
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003028 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003029 order = get_order(size);
3030
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003031 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003032 free_pages((unsigned long)vaddr, order);
3033}
3034
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003035static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3036 int nelems, enum dma_data_direction dir,
3037 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003038{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003039 struct pci_dev *pdev = to_pci_dev(hwdev);
3040 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003041 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003042 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003043 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003044
David Woodhouse73676832009-07-04 14:08:36 +01003045 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003046 return;
3047
3048 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003049 BUG_ON(!domain);
3050
3051 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003052
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003053 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003054 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3055 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003056 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003057
David Woodhoused794dc92009-06-28 00:27:49 +01003058 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3059 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003060
3061 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003062 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003063
David Woodhoused794dc92009-06-28 00:27:49 +01003064 /* free page tables */
3065 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3066
David Woodhouseacea0012009-07-14 01:55:11 +01003067 if (intel_iommu_strict) {
3068 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003069 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003070 /* free iova */
3071 __free_iova(&domain->iovad, iova);
3072 } else {
3073 add_unmap(domain, iova);
3074 /*
3075 * queue up the release of the unmap to save the 1/6th of the
3076 * cpu used up by the iotlb flush operation...
3077 */
3078 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003079}
3080
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003081static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003082 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003083{
3084 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003085 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003086
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003087 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003088 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003089 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003090 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003091 }
3092 return nelems;
3093}
3094
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003095static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3096 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003097{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003098 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003099 struct pci_dev *pdev = to_pci_dev(hwdev);
3100 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003101 size_t size = 0;
3102 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003103 struct iova *iova = NULL;
3104 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003105 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003106 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003107 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003108
3109 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003110 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003111 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003112
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003113 domain = get_valid_domain_for_dev(pdev);
3114 if (!domain)
3115 return 0;
3116
Weidong Han8c11e792008-12-08 15:29:22 +08003117 iommu = domain_get_iommu(domain);
3118
David Woodhouseb536d242009-06-28 14:49:31 +01003119 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003120 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003121
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003122 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3123 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003124 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003125 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003126 return 0;
3127 }
3128
3129 /*
3130 * Check if DMAR supports zero-length reads on write only
3131 * mappings..
3132 */
3133 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003134 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003135 prot |= DMA_PTE_READ;
3136 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3137 prot |= DMA_PTE_WRITE;
3138
David Woodhouseb536d242009-06-28 14:49:31 +01003139 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003140
Fenghua Yuf5329592009-08-04 15:09:37 -07003141 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003142 if (unlikely(ret)) {
3143 /* clear the page */
3144 dma_pte_clear_range(domain, start_vpfn,
3145 start_vpfn + size - 1);
3146 /* free page tables */
3147 dma_pte_free_pagetable(domain, start_vpfn,
3148 start_vpfn + size - 1);
3149 /* free iova */
3150 __free_iova(&domain->iovad, iova);
3151 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003152 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003153
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003154 /* it's a non-present to present mapping. Only flush if caching mode */
3155 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003156 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003157 else
Weidong Han8c11e792008-12-08 15:29:22 +08003158 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003159
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003160 return nelems;
3161}
3162
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003163static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3164{
3165 return !dma_addr;
3166}
3167
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003168struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003169 .alloc = intel_alloc_coherent,
3170 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003171 .map_sg = intel_map_sg,
3172 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003173 .map_page = intel_map_page,
3174 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003175 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003176};
3177
3178static inline int iommu_domain_cache_init(void)
3179{
3180 int ret = 0;
3181
3182 iommu_domain_cache = kmem_cache_create("iommu_domain",
3183 sizeof(struct dmar_domain),
3184 0,
3185 SLAB_HWCACHE_ALIGN,
3186
3187 NULL);
3188 if (!iommu_domain_cache) {
3189 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3190 ret = -ENOMEM;
3191 }
3192
3193 return ret;
3194}
3195
3196static inline int iommu_devinfo_cache_init(void)
3197{
3198 int ret = 0;
3199
3200 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3201 sizeof(struct device_domain_info),
3202 0,
3203 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003204 NULL);
3205 if (!iommu_devinfo_cache) {
3206 printk(KERN_ERR "Couldn't create devinfo cache\n");
3207 ret = -ENOMEM;
3208 }
3209
3210 return ret;
3211}
3212
3213static inline int iommu_iova_cache_init(void)
3214{
3215 int ret = 0;
3216
3217 iommu_iova_cache = kmem_cache_create("iommu_iova",
3218 sizeof(struct iova),
3219 0,
3220 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003221 NULL);
3222 if (!iommu_iova_cache) {
3223 printk(KERN_ERR "Couldn't create iova cache\n");
3224 ret = -ENOMEM;
3225 }
3226
3227 return ret;
3228}
3229
3230static int __init iommu_init_mempool(void)
3231{
3232 int ret;
3233 ret = iommu_iova_cache_init();
3234 if (ret)
3235 return ret;
3236
3237 ret = iommu_domain_cache_init();
3238 if (ret)
3239 goto domain_error;
3240
3241 ret = iommu_devinfo_cache_init();
3242 if (!ret)
3243 return ret;
3244
3245 kmem_cache_destroy(iommu_domain_cache);
3246domain_error:
3247 kmem_cache_destroy(iommu_iova_cache);
3248
3249 return -ENOMEM;
3250}
3251
3252static void __init iommu_exit_mempool(void)
3253{
3254 kmem_cache_destroy(iommu_devinfo_cache);
3255 kmem_cache_destroy(iommu_domain_cache);
3256 kmem_cache_destroy(iommu_iova_cache);
3257
3258}
3259
Dan Williams556ab452010-07-23 15:47:56 -07003260static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3261{
3262 struct dmar_drhd_unit *drhd;
3263 u32 vtbar;
3264 int rc;
3265
3266 /* We know that this device on this chipset has its own IOMMU.
3267 * If we find it under a different IOMMU, then the BIOS is lying
3268 * to us. Hope that the IOMMU for this device is actually
3269 * disabled, and it needs no translation...
3270 */
3271 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3272 if (rc) {
3273 /* "can't" happen */
3274 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3275 return;
3276 }
3277 vtbar &= 0xffff0000;
3278
3279 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3280 drhd = dmar_find_matched_drhd_unit(pdev);
3281 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3282 TAINT_FIRMWARE_WORKAROUND,
3283 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3284 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3285}
3286DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3287
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003288static void __init init_no_remapping_devices(void)
3289{
3290 struct dmar_drhd_unit *drhd;
3291
3292 for_each_drhd_unit(drhd) {
3293 if (!drhd->include_all) {
3294 int i;
3295 for (i = 0; i < drhd->devices_cnt; i++)
3296 if (drhd->devices[i] != NULL)
3297 break;
3298 /* ignore DMAR unit if no pci devices exist */
3299 if (i == drhd->devices_cnt)
3300 drhd->ignored = 1;
3301 }
3302 }
3303
Jiang Liu7c919772014-01-06 14:18:18 +08003304 for_each_active_drhd_unit(drhd) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003305 int i;
Jiang Liu7c919772014-01-06 14:18:18 +08003306 if (drhd->include_all)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003307 continue;
3308
3309 for (i = 0; i < drhd->devices_cnt; i++)
3310 if (drhd->devices[i] &&
David Woodhousec0771df2011-10-14 20:59:46 +01003311 !IS_GFX_DEVICE(drhd->devices[i]))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003312 break;
3313
3314 if (i < drhd->devices_cnt)
3315 continue;
3316
David Woodhousec0771df2011-10-14 20:59:46 +01003317 /* This IOMMU has *only* gfx devices. Either bypass it or
3318 set the gfx_mapped flag, as appropriate */
3319 if (dmar_map_gfx) {
3320 intel_iommu_gfx_mapped = 1;
3321 } else {
3322 drhd->ignored = 1;
3323 for (i = 0; i < drhd->devices_cnt; i++) {
3324 if (!drhd->devices[i])
3325 continue;
3326 drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3327 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003328 }
3329 }
3330}
3331
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003332#ifdef CONFIG_SUSPEND
3333static int init_iommu_hw(void)
3334{
3335 struct dmar_drhd_unit *drhd;
3336 struct intel_iommu *iommu = NULL;
3337
3338 for_each_active_iommu(iommu, drhd)
3339 if (iommu->qi)
3340 dmar_reenable_qi(iommu);
3341
Joseph Cihulab7792602011-05-03 00:08:37 -07003342 for_each_iommu(iommu, drhd) {
3343 if (drhd->ignored) {
3344 /*
3345 * we always have to disable PMRs or DMA may fail on
3346 * this device
3347 */
3348 if (force_on)
3349 iommu_disable_protect_mem_regions(iommu);
3350 continue;
3351 }
3352
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003353 iommu_flush_write_buffer(iommu);
3354
3355 iommu_set_root_entry(iommu);
3356
3357 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003358 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003359 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003360 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003361 if (iommu_enable_translation(iommu))
3362 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003363 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003364 }
3365
3366 return 0;
3367}
3368
3369static void iommu_flush_all(void)
3370{
3371 struct dmar_drhd_unit *drhd;
3372 struct intel_iommu *iommu;
3373
3374 for_each_active_iommu(iommu, drhd) {
3375 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003376 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003377 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003378 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003379 }
3380}
3381
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003382static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003383{
3384 struct dmar_drhd_unit *drhd;
3385 struct intel_iommu *iommu = NULL;
3386 unsigned long flag;
3387
3388 for_each_active_iommu(iommu, drhd) {
3389 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3390 GFP_ATOMIC);
3391 if (!iommu->iommu_state)
3392 goto nomem;
3393 }
3394
3395 iommu_flush_all();
3396
3397 for_each_active_iommu(iommu, drhd) {
3398 iommu_disable_translation(iommu);
3399
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003400 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003401
3402 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3403 readl(iommu->reg + DMAR_FECTL_REG);
3404 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3405 readl(iommu->reg + DMAR_FEDATA_REG);
3406 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3407 readl(iommu->reg + DMAR_FEADDR_REG);
3408 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3409 readl(iommu->reg + DMAR_FEUADDR_REG);
3410
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003411 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003412 }
3413 return 0;
3414
3415nomem:
3416 for_each_active_iommu(iommu, drhd)
3417 kfree(iommu->iommu_state);
3418
3419 return -ENOMEM;
3420}
3421
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003422static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003423{
3424 struct dmar_drhd_unit *drhd;
3425 struct intel_iommu *iommu = NULL;
3426 unsigned long flag;
3427
3428 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003429 if (force_on)
3430 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3431 else
3432 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003433 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003434 }
3435
3436 for_each_active_iommu(iommu, drhd) {
3437
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003438 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003439
3440 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3441 iommu->reg + DMAR_FECTL_REG);
3442 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3443 iommu->reg + DMAR_FEDATA_REG);
3444 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3445 iommu->reg + DMAR_FEADDR_REG);
3446 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3447 iommu->reg + DMAR_FEUADDR_REG);
3448
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003449 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003450 }
3451
3452 for_each_active_iommu(iommu, drhd)
3453 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003454}
3455
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003456static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003457 .resume = iommu_resume,
3458 .suspend = iommu_suspend,
3459};
3460
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003461static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003462{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003463 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003464}
3465
3466#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003467static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003468#endif /* CONFIG_PM */
3469
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003470static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3471{
3472 list_add(&rmrr->list, &dmar_rmrr_units);
3473}
3474
3475
3476int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3477{
3478 struct acpi_dmar_reserved_memory *rmrr;
3479 struct dmar_rmrr_unit *rmrru;
3480
3481 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3482 if (!rmrru)
3483 return -ENOMEM;
3484
3485 rmrru->hdr = header;
3486 rmrr = (struct acpi_dmar_reserved_memory *)header;
3487 rmrru->base_address = rmrr->base_address;
3488 rmrru->end_address = rmrr->end_address;
3489
3490 dmar_register_rmrr_unit(rmrru);
3491 return 0;
3492}
3493
3494static int __init
3495rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3496{
3497 struct acpi_dmar_reserved_memory *rmrr;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003498
3499 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003500 return dmar_parse_dev_scope((void *)(rmrr + 1),
3501 ((void *)rmrr) + rmrr->header.length,
3502 &rmrru->devices_cnt, &rmrru->devices,
3503 rmrr->segment);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003504}
3505
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003506int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3507{
3508 struct acpi_dmar_atsr *atsr;
3509 struct dmar_atsr_unit *atsru;
3510
3511 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3512 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3513 if (!atsru)
3514 return -ENOMEM;
3515
3516 atsru->hdr = hdr;
3517 atsru->include_all = atsr->flags & 0x1;
3518
3519 list_add(&atsru->list, &dmar_atsr_units);
3520
3521 return 0;
3522}
3523
3524static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3525{
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003526 struct acpi_dmar_atsr *atsr;
3527
3528 if (atsru->include_all)
3529 return 0;
3530
3531 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
Jiang Liu9bdc5312014-01-06 14:18:27 +08003532 return dmar_parse_dev_scope((void *)(atsr + 1),
3533 (void *)atsr + atsr->header.length,
3534 &atsru->devices_cnt, &atsru->devices,
3535 atsr->segment);
3536}
3537
3538static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
3539{
3540 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
3541 kfree(atsru);
3542}
3543
3544static void intel_iommu_free_dmars(void)
3545{
3546 struct dmar_rmrr_unit *rmrru, *rmrr_n;
3547 struct dmar_atsr_unit *atsru, *atsr_n;
3548
3549 list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
3550 list_del(&rmrru->list);
3551 dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
3552 kfree(rmrru);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003553 }
3554
Jiang Liu9bdc5312014-01-06 14:18:27 +08003555 list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
3556 list_del(&atsru->list);
3557 intel_iommu_free_atsr(atsru);
3558 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003559}
3560
3561int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3562{
3563 int i;
3564 struct pci_bus *bus;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003565 struct pci_dev *bridge = NULL;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003566 struct acpi_dmar_atsr *atsr;
3567 struct dmar_atsr_unit *atsru;
3568
3569 dev = pci_physfn(dev);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003570 for (bus = dev->bus; bus; bus = bus->parent) {
Jiang Liub5f82dd2014-02-19 14:07:31 +08003571 bridge = bus->self;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003572 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003573 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003574 return 0;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003575 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003576 break;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003577 }
Jiang Liub5f82dd2014-02-19 14:07:31 +08003578 if (!bridge)
3579 return 0;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003580
Jiang Liub5f82dd2014-02-19 14:07:31 +08003581 list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
3582 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3583 if (atsr->segment != pci_domain_nr(dev->bus))
3584 continue;
3585
3586 for (i = 0; i < atsru->devices_cnt; i++)
3587 if (atsru->devices[i] == bridge)
3588 return 1;
3589
3590 if (atsru->include_all)
3591 return 1;
3592 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003593
3594 return 0;
3595}
3596
Sergey Senozhatskyc8f369a2011-10-26 18:45:39 +03003597int __init dmar_parse_rmrr_atsr_dev(void)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003598{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003599 struct dmar_rmrr_unit *rmrr;
3600 struct dmar_atsr_unit *atsr;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003601 int ret = 0;
3602
Jiang Liu9bdc5312014-01-06 14:18:27 +08003603 list_for_each_entry(rmrr, &dmar_rmrr_units, list) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003604 ret = rmrr_parse_dev(rmrr);
3605 if (ret)
3606 return ret;
3607 }
3608
Jiang Liu9bdc5312014-01-06 14:18:27 +08003609 list_for_each_entry(atsr, &dmar_atsr_units, list) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003610 ret = atsr_parse_dev(atsr);
3611 if (ret)
3612 return ret;
3613 }
3614
3615 return ret;
3616}
3617
Fenghua Yu99dcade2009-11-11 07:23:06 -08003618/*
3619 * Here we only respond to action of unbound device from driver.
3620 *
3621 * Added device is not attached to its DMAR domain here yet. That will happen
3622 * when mapping the device to iova.
3623 */
3624static int device_notifier(struct notifier_block *nb,
3625 unsigned long action, void *data)
3626{
3627 struct device *dev = data;
3628 struct pci_dev *pdev = to_pci_dev(dev);
3629 struct dmar_domain *domain;
3630
Jiang Liu816997d2014-02-19 14:07:22 +08003631 if (iommu_dummy(pdev))
David Woodhouse44cd6132009-12-02 10:18:30 +00003632 return 0;
3633
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003634 if (action != BUS_NOTIFY_UNBOUND_DRIVER &&
3635 action != BUS_NOTIFY_DEL_DEVICE)
3636 return 0;
3637
Fenghua Yu99dcade2009-11-11 07:23:06 -08003638 domain = find_domain(pdev);
3639 if (!domain)
3640 return 0;
3641
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003642 domain_remove_one_dev_info(domain, pdev);
3643 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3644 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3645 list_empty(&domain->devices))
3646 domain_exit(domain);
Alex Williamsona97590e2011-03-04 14:52:16 -07003647
Fenghua Yu99dcade2009-11-11 07:23:06 -08003648 return 0;
3649}
3650
3651static struct notifier_block device_nb = {
3652 .notifier_call = device_notifier,
3653};
3654
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003655int __init intel_iommu_init(void)
3656{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003657 int ret = -ENODEV;
Takao Indoh3a93c842013-04-23 17:35:03 +09003658 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +08003659 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003660
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003661 /* VT-d is required for a TXT/tboot launch, so enforce that */
3662 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003663
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003664 if (dmar_table_init()) {
3665 if (force_on)
3666 panic("tboot: Failed to initialize DMAR table\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003667 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003668 }
3669
Takao Indoh3a93c842013-04-23 17:35:03 +09003670 /*
3671 * Disable translation if already enabled prior to OS handover.
3672 */
Jiang Liu7c919772014-01-06 14:18:18 +08003673 for_each_active_iommu(iommu, drhd)
Takao Indoh3a93c842013-04-23 17:35:03 +09003674 if (iommu->gcmd & DMA_GCMD_TE)
3675 iommu_disable_translation(iommu);
Takao Indoh3a93c842013-04-23 17:35:03 +09003676
Suresh Siddhac2c72862011-08-23 17:05:19 -07003677 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003678 if (force_on)
3679 panic("tboot: Failed to initialize DMAR device scope\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003680 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003681 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003682
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003683 if (no_iommu || dmar_disabled)
Jiang Liu9bdc5312014-01-06 14:18:27 +08003684 goto out_free_dmar;
Suresh Siddha2ae21012008-07-10 11:16:43 -07003685
Joseph Cihula51a63e62011-03-21 11:04:24 -07003686 if (iommu_init_mempool()) {
3687 if (force_on)
3688 panic("tboot: Failed to initialize iommu memory\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003689 goto out_free_dmar;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003690 }
3691
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003692 if (list_empty(&dmar_rmrr_units))
3693 printk(KERN_INFO "DMAR: No RMRR found\n");
3694
3695 if (list_empty(&dmar_atsr_units))
3696 printk(KERN_INFO "DMAR: No ATSR found\n");
3697
Joseph Cihula51a63e62011-03-21 11:04:24 -07003698 if (dmar_init_reserved_ranges()) {
3699 if (force_on)
3700 panic("tboot: Failed to reserve iommu ranges\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003701 goto out_free_mempool;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003702 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003703
3704 init_no_remapping_devices();
3705
Joseph Cihulab7792602011-05-03 00:08:37 -07003706 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003707 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003708 if (force_on)
3709 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003710 printk(KERN_ERR "IOMMU: dmar init failed\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003711 goto out_free_reserved_range;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003712 }
3713 printk(KERN_INFO
3714 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3715
mark gross5e0d2a62008-03-04 15:22:08 -08003716 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003717#ifdef CONFIG_SWIOTLB
3718 swiotlb = 0;
3719#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003720 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003721
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003722 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003723
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003724 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003725
Fenghua Yu99dcade2009-11-11 07:23:06 -08003726 bus_register_notifier(&pci_bus_type, &device_nb);
3727
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003728 intel_iommu_enabled = 1;
3729
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003730 return 0;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003731
3732out_free_reserved_range:
3733 put_iova_domain(&reserved_iova_list);
3734out_free_mempool:
3735 iommu_exit_mempool();
3736out_free_dmar:
3737 intel_iommu_free_dmars();
3738 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003739}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003740
Han, Weidong3199aa62009-02-26 17:31:12 +08003741static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3742 struct pci_dev *pdev)
3743{
3744 struct pci_dev *tmp, *parent;
3745
3746 if (!iommu || !pdev)
3747 return;
3748
3749 /* dependent device detach */
3750 tmp = pci_find_upstream_pcie_bridge(pdev);
3751 /* Secondary interface's bus number and devfn 0 */
3752 if (tmp) {
3753 parent = pdev->bus->self;
3754 while (parent != tmp) {
3755 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf92009-04-04 01:45:37 +01003756 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003757 parent = parent->bus->self;
3758 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003759 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003760 iommu_detach_dev(iommu,
3761 tmp->subordinate->number, 0);
3762 else /* this is a legacy PCI bridge */
David Woodhouse276dbf92009-04-04 01:45:37 +01003763 iommu_detach_dev(iommu, tmp->bus->number,
3764 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003765 }
3766}
3767
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003768static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003769 struct pci_dev *pdev)
3770{
Yijing Wangbca2b912013-10-31 17:26:04 +08003771 struct device_domain_info *info, *tmp;
Weidong Hanc7151a82008-12-08 22:51:37 +08003772 struct intel_iommu *iommu;
3773 unsigned long flags;
3774 int found = 0;
Weidong Hanc7151a82008-12-08 22:51:37 +08003775
David Woodhouse276dbf92009-04-04 01:45:37 +01003776 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3777 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003778 if (!iommu)
3779 return;
3780
3781 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wangbca2b912013-10-31 17:26:04 +08003782 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
Mike Habeck8519dc42011-05-28 13:15:07 -05003783 if (info->segment == pci_domain_nr(pdev->bus) &&
3784 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003785 info->devfn == pdev->devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01003786 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003787 spin_unlock_irqrestore(&device_domain_lock, flags);
3788
Yu Zhao93a23a72009-05-18 13:51:37 +08003789 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003790 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003791 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003792 free_devinfo_mem(info);
3793
3794 spin_lock_irqsave(&device_domain_lock, flags);
3795
3796 if (found)
3797 break;
3798 else
3799 continue;
3800 }
3801
3802 /* if there is no other devices under the same iommu
3803 * owned by this domain, clear this iommu in iommu_bmp
3804 * update iommu count and coherency
3805 */
David Woodhouse276dbf92009-04-04 01:45:37 +01003806 if (iommu == device_to_iommu(info->segment, info->bus,
3807 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003808 found = 1;
3809 }
3810
Roland Dreier3e7abe22011-07-20 06:22:21 -07003811 spin_unlock_irqrestore(&device_domain_lock, flags);
3812
Weidong Hanc7151a82008-12-08 22:51:37 +08003813 if (found == 0) {
3814 unsigned long tmp_flags;
3815 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003816 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003817 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003818 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003819 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003820
Alex Williamson9b4554b2011-05-24 12:19:04 -04003821 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3822 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3823 spin_lock_irqsave(&iommu->lock, tmp_flags);
3824 clear_bit(domain->id, iommu->domain_ids);
3825 iommu->domains[domain->id] = NULL;
3826 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3827 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003828 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003829}
3830
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003831static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003832{
3833 int adjust_width;
3834
3835 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003836 domain_reserve_special_ranges(domain);
3837
3838 /* calculate AGAW */
3839 domain->gaw = guest_width;
3840 adjust_width = guestwidth_to_adjustwidth(guest_width);
3841 domain->agaw = width_to_agaw(adjust_width);
3842
Weidong Han5e98c4b2008-12-08 23:03:27 +08003843 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003844 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003845 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003846 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003847 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003848
3849 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003850 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003851 if (!domain->pgd)
3852 return -ENOMEM;
3853 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3854 return 0;
3855}
3856
Joerg Roedel5d450802008-12-03 14:52:32 +01003857static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003858{
Joerg Roedel5d450802008-12-03 14:52:32 +01003859 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003860
Jiang Liu92d03cc2014-02-19 14:07:28 +08003861 dmar_domain = alloc_domain(true);
Joerg Roedel5d450802008-12-03 14:52:32 +01003862 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003863 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003864 "intel_iommu_domain_init: dmar_domain == NULL\n");
3865 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003866 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003867 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003868 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003869 "intel_iommu_domain_init() failed\n");
Jiang Liu92d03cc2014-02-19 14:07:28 +08003870 domain_exit(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003871 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003872 }
Allen Kay8140a952011-10-14 12:32:17 -07003873 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003874 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003875
Joerg Roedel8a0e7152012-01-26 19:40:54 +01003876 domain->geometry.aperture_start = 0;
3877 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
3878 domain->geometry.force_aperture = true;
3879
Joerg Roedel5d450802008-12-03 14:52:32 +01003880 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003881}
Kay, Allen M38717942008-09-09 18:37:29 +03003882
Joerg Roedel5d450802008-12-03 14:52:32 +01003883static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003884{
Joerg Roedel5d450802008-12-03 14:52:32 +01003885 struct dmar_domain *dmar_domain = domain->priv;
3886
3887 domain->priv = NULL;
Jiang Liu92d03cc2014-02-19 14:07:28 +08003888 domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003889}
Kay, Allen M38717942008-09-09 18:37:29 +03003890
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003891static int intel_iommu_attach_device(struct iommu_domain *domain,
3892 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003893{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003894 struct dmar_domain *dmar_domain = domain->priv;
3895 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003896 struct intel_iommu *iommu;
3897 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03003898
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003899 /* normally pdev is not mapped */
3900 if (unlikely(domain_context_mapped(pdev))) {
3901 struct dmar_domain *old_domain;
3902
3903 old_domain = find_domain(pdev);
3904 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003905 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3906 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3907 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003908 else
3909 domain_remove_dev_info(old_domain);
3910 }
3911 }
3912
David Woodhouse276dbf92009-04-04 01:45:37 +01003913 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3914 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003915 if (!iommu)
3916 return -ENODEV;
3917
3918 /* check if this iommu agaw is sufficient for max mapped address */
3919 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01003920 if (addr_width > cap_mgaw(iommu->cap))
3921 addr_width = cap_mgaw(iommu->cap);
3922
3923 if (dmar_domain->max_addr > (1LL << addr_width)) {
3924 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003925 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01003926 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003927 return -EFAULT;
3928 }
Tom Lyona99c47a2010-05-17 08:20:45 +01003929 dmar_domain->gaw = addr_width;
3930
3931 /*
3932 * Knock out extra levels of page tables if necessary
3933 */
3934 while (iommu->agaw < dmar_domain->agaw) {
3935 struct dma_pte *pte;
3936
3937 pte = dmar_domain->pgd;
3938 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08003939 dmar_domain->pgd = (struct dma_pte *)
3940 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01003941 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01003942 }
3943 dmar_domain->agaw--;
3944 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003945
David Woodhouse5fe60f42009-08-09 10:53:41 +01003946 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003947}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003948
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003949static void intel_iommu_detach_device(struct iommu_domain *domain,
3950 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003951{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003952 struct dmar_domain *dmar_domain = domain->priv;
3953 struct pci_dev *pdev = to_pci_dev(dev);
3954
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003955 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003956}
Kay, Allen M38717942008-09-09 18:37:29 +03003957
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003958static int intel_iommu_map(struct iommu_domain *domain,
3959 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02003960 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003961{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003962 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003963 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003964 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003965 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003966
Joerg Roedeldde57a22008-12-03 15:04:09 +01003967 if (iommu_prot & IOMMU_READ)
3968 prot |= DMA_PTE_READ;
3969 if (iommu_prot & IOMMU_WRITE)
3970 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08003971 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
3972 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003973
David Woodhouse163cc522009-06-28 00:51:17 +01003974 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003975 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003976 u64 end;
3977
3978 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01003979 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003980 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01003981 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003982 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01003983 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003984 return -EFAULT;
3985 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003986 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003987 }
David Woodhousead051222009-06-28 14:22:28 +01003988 /* Round up size to next multiple of PAGE_SIZE, if it and
3989 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01003990 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01003991 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
3992 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003993 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003994}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003995
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02003996static size_t intel_iommu_unmap(struct iommu_domain *domain,
3997 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003998{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003999 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07004000 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01004001
Allen Kay292827c2011-10-14 12:31:54 -07004002 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004003 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004004
David Woodhouse163cc522009-06-28 00:51:17 +01004005 if (dmar_domain->max_addr == iova + size)
4006 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004007
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004008 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004009}
Kay, Allen M38717942008-09-09 18:37:29 +03004010
Joerg Roedeld14d6572008-12-03 15:06:57 +01004011static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
Varun Sethibb5547ac2013-03-29 01:23:58 +05304012 dma_addr_t iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004013{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004014 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004015 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004016 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004017
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004018 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004019 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004020 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004021
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004022 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004023}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004024
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004025static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4026 unsigned long cap)
4027{
4028 struct dmar_domain *dmar_domain = domain->priv;
4029
4030 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4031 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004032 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004033 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004034
4035 return 0;
4036}
4037
Alex Williamson783f1572012-05-30 14:19:43 -06004038#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4039
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004040static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004041{
4042 struct pci_dev *pdev = to_pci_dev(dev);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004043 struct pci_dev *bridge, *dma_pdev = NULL;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004044 struct iommu_group *group;
4045 int ret;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004046
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004047 if (!device_to_iommu(pci_domain_nr(pdev->bus),
4048 pdev->bus->number, pdev->devfn))
Alex Williamson70ae6f02011-10-21 15:56:11 -04004049 return -ENODEV;
4050
4051 bridge = pci_find_upstream_pcie_bridge(pdev);
4052 if (bridge) {
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004053 if (pci_is_pcie(bridge))
4054 dma_pdev = pci_get_domain_bus_and_slot(
4055 pci_domain_nr(pdev->bus),
4056 bridge->subordinate->number, 0);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004057 if (!dma_pdev)
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004058 dma_pdev = pci_dev_get(bridge);
4059 } else
4060 dma_pdev = pci_dev_get(pdev);
4061
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004062 /* Account for quirked devices */
Alex Williamson783f1572012-05-30 14:19:43 -06004063 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4064
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004065 /*
4066 * If it's a multifunction device that does not support our
Alex Williamsonc14d2692013-05-30 12:39:18 -06004067 * required ACS flags, add to the same group as lowest numbered
4068 * function that also does not suport the required ACS flags.
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004069 */
Alex Williamson783f1572012-05-30 14:19:43 -06004070 if (dma_pdev->multifunction &&
Alex Williamsonc14d2692013-05-30 12:39:18 -06004071 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
4072 u8 i, slot = PCI_SLOT(dma_pdev->devfn);
4073
4074 for (i = 0; i < 8; i++) {
4075 struct pci_dev *tmp;
4076
4077 tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
4078 if (!tmp)
4079 continue;
4080
4081 if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
4082 swap_pci_ref(&dma_pdev, tmp);
4083 break;
4084 }
4085 pci_dev_put(tmp);
4086 }
4087 }
Alex Williamson783f1572012-05-30 14:19:43 -06004088
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004089 /*
4090 * Devices on the root bus go through the iommu. If that's not us,
4091 * find the next upstream device and test ACS up to the root bus.
4092 * Finding the next device may require skipping virtual buses.
4093 */
Alex Williamson783f1572012-05-30 14:19:43 -06004094 while (!pci_is_root_bus(dma_pdev->bus)) {
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004095 struct pci_bus *bus = dma_pdev->bus;
4096
4097 while (!bus->self) {
4098 if (!pci_is_root_bus(bus))
4099 bus = bus->parent;
4100 else
4101 goto root_bus;
4102 }
4103
4104 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
Alex Williamson783f1572012-05-30 14:19:43 -06004105 break;
4106
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004107 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
Alex Williamson70ae6f02011-10-21 15:56:11 -04004108 }
4109
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004110root_bus:
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004111 group = iommu_group_get(&dma_pdev->dev);
4112 pci_dev_put(dma_pdev);
4113 if (!group) {
4114 group = iommu_group_alloc();
4115 if (IS_ERR(group))
4116 return PTR_ERR(group);
4117 }
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004118
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004119 ret = iommu_group_add_device(group, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004120
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004121 iommu_group_put(group);
4122 return ret;
4123}
4124
4125static void intel_iommu_remove_device(struct device *dev)
4126{
4127 iommu_group_remove_device(dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004128}
4129
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004130static struct iommu_ops intel_iommu_ops = {
4131 .domain_init = intel_iommu_domain_init,
4132 .domain_destroy = intel_iommu_domain_destroy,
4133 .attach_dev = intel_iommu_attach_device,
4134 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004135 .map = intel_iommu_map,
4136 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004137 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004138 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004139 .add_device = intel_iommu_add_device,
4140 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004141 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004142};
David Woodhouse9af88142009-02-13 23:18:03 +00004143
Daniel Vetter94526182013-01-20 23:50:13 +01004144static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4145{
4146 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4147 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4148 dmar_map_gfx = 0;
4149}
4150
4151DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4152DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4153DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4154DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4155DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4156DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4157DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4158
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004159static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004160{
4161 /*
4162 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004163 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004164 */
4165 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4166 rwbf_quirk = 1;
4167}
4168
4169DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004170DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4171DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4172DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4173DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4174DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4175DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004176
Adam Jacksoneecfd572010-08-25 21:17:34 +01004177#define GGC 0x52
4178#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4179#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4180#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4181#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4182#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4183#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4184#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4185#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4186
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004187static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004188{
4189 unsigned short ggc;
4190
Adam Jacksoneecfd572010-08-25 21:17:34 +01004191 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004192 return;
4193
Adam Jacksoneecfd572010-08-25 21:17:34 +01004194 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004195 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4196 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004197 } else if (dmar_map_gfx) {
4198 /* we have to ensure the gfx device is idle before we flush */
4199 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4200 intel_iommu_strict = 1;
4201 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004202}
4203DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4204DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4205DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4206DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4207
David Woodhousee0fc7e02009-09-30 09:12:17 -07004208/* On Tylersburg chipsets, some BIOSes have been known to enable the
4209 ISOCH DMAR unit for the Azalia sound device, but not give it any
4210 TLB entries, which causes it to deadlock. Check for that. We do
4211 this in a function called from init_dmars(), instead of in a PCI
4212 quirk, because we don't want to print the obnoxious "BIOS broken"
4213 message if VT-d is actually disabled.
4214*/
4215static void __init check_tylersburg_isoch(void)
4216{
4217 struct pci_dev *pdev;
4218 uint32_t vtisochctrl;
4219
4220 /* If there's no Azalia in the system anyway, forget it. */
4221 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4222 if (!pdev)
4223 return;
4224 pci_dev_put(pdev);
4225
4226 /* System Management Registers. Might be hidden, in which case
4227 we can't do the sanity check. But that's OK, because the
4228 known-broken BIOSes _don't_ actually hide it, so far. */
4229 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4230 if (!pdev)
4231 return;
4232
4233 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4234 pci_dev_put(pdev);
4235 return;
4236 }
4237
4238 pci_dev_put(pdev);
4239
4240 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4241 if (vtisochctrl & 1)
4242 return;
4243
4244 /* Drop all bits other than the number of TLB entries */
4245 vtisochctrl &= 0x1c;
4246
4247 /* If we have the recommended number of TLB entries (16), fine. */
4248 if (vtisochctrl == 0x10)
4249 return;
4250
4251 /* Zero TLB entries? You get to ride the short bus to school. */
4252 if (!vtisochctrl) {
4253 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4254 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4255 dmi_get_system_info(DMI_BIOS_VENDOR),
4256 dmi_get_system_info(DMI_BIOS_VERSION),
4257 dmi_get_system_info(DMI_PRODUCT_VERSION));
4258 iommu_identity_mapping |= IDENTMAP_AZALIA;
4259 return;
4260 }
4261
4262 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4263 vtisochctrl);
4264}