blob: bb98e37f2cf720f091b3c453f41149fbbaacc32f [file] [log] [blame]
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001/*
2 * Copyright (c) 2006, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
mark gross98bcef52008-02-23 15:23:35 -080017 * Copyright (C) 2006-2008 Intel Corporation
18 * Author: Ashok Raj <ashok.raj@intel.com>
19 * Author: Shaohua Li <shaohua.li@intel.com>
20 * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Fenghua Yu5b6985c2008-10-16 18:02:32 -070021 * Author: Fenghua Yu <fenghua.yu@intel.com>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070022 */
23
24#include <linux/init.h>
25#include <linux/bitmap.h>
mark gross5e0d2a62008-03-04 15:22:08 -080026#include <linux/debugfs.h>
Paul Gortmaker54485c32011-10-29 10:26:25 -040027#include <linux/export.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070028#include <linux/slab.h>
29#include <linux/irq.h>
30#include <linux/interrupt.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070031#include <linux/spinlock.h>
32#include <linux/pci.h>
33#include <linux/dmar.h>
34#include <linux/dma-mapping.h>
35#include <linux/mempool.h>
mark gross5e0d2a62008-03-04 15:22:08 -080036#include <linux/timer.h>
Kay, Allen M38717942008-09-09 18:37:29 +030037#include <linux/iova.h>
Joerg Roedel5d450802008-12-03 14:52:32 +010038#include <linux/iommu.h>
Kay, Allen M38717942008-09-09 18:37:29 +030039#include <linux/intel-iommu.h>
Rafael J. Wysocki134fac32011-03-23 22:16:14 +010040#include <linux/syscore_ops.h>
Shane Wang69575d32009-09-01 18:25:07 -070041#include <linux/tboot.h>
Stephen Rothwelladb2fe02009-08-31 15:24:23 +100042#include <linux/dmi.h>
Joerg Roedel5cdede22011-04-04 15:55:18 +020043#include <linux/pci-ats.h>
Tejun Heo0ee332c2011-12-08 10:22:09 -080044#include <linux/memblock.h>
Suresh Siddha8a8f4222012-03-30 11:47:08 -070045#include <asm/irq_remapping.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070046#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090047#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070048
Joerg Roedel078e1ee2012-09-26 12:44:43 +020049#include "irq_remapping.h"
Varun Sethi61e015a2013-04-23 10:05:24 +053050#include "pci.h"
Joerg Roedel078e1ee2012-09-26 12:44:43 +020051
Fenghua Yu5b6985c2008-10-16 18:02:32 -070052#define ROOT_SIZE VTD_PAGE_SIZE
53#define CONTEXT_SIZE VTD_PAGE_SIZE
54
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070055#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
56#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070057#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070058
59#define IOAPIC_RANGE_START (0xfee00000)
60#define IOAPIC_RANGE_END (0xfeefffff)
61#define IOVA_START_ADDR (0x1000)
62
63#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
64
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070065#define MAX_AGAW_WIDTH 64
Jiang Liu5c645b32014-01-06 14:18:12 +080066#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070067
David Woodhouse2ebe3152009-09-19 07:34:04 -070068#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
69#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
70
71/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
72 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
73#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
74 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
75#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070076
Mark McLoughlinf27be032008-11-20 15:49:43 +000077#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070078#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070079#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080080
Andrew Mortondf08cdc2010-09-22 13:05:11 -070081/* page table handling */
82#define LEVEL_STRIDE (9)
83#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
84
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +020085/*
86 * This bitmap is used to advertise the page sizes our hardware support
87 * to the IOMMU core, which will then use this information to split
88 * physically contiguous memory regions it is mapping into page sizes
89 * that we support.
90 *
91 * Traditionally the IOMMU core just handed us the mappings directly,
92 * after making sure the size is an order of a 4KiB page and that the
93 * mapping has natural alignment.
94 *
95 * To retain this behavior, we currently advertise that we support
96 * all page sizes that are an order of 4KiB.
97 *
98 * If at some point we'd like to utilize the IOMMU core's new behavior,
99 * we could change this to advertise the real page sizes we support.
100 */
101#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
102
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700103static inline int agaw_to_level(int agaw)
104{
105 return agaw + 2;
106}
107
108static inline int agaw_to_width(int agaw)
109{
Jiang Liu5c645b32014-01-06 14:18:12 +0800110 return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700111}
112
113static inline int width_to_agaw(int width)
114{
Jiang Liu5c645b32014-01-06 14:18:12 +0800115 return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700116}
117
118static inline unsigned int level_to_offset_bits(int level)
119{
120 return (level - 1) * LEVEL_STRIDE;
121}
122
123static inline int pfn_level_offset(unsigned long pfn, int level)
124{
125 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
126}
127
128static inline unsigned long level_mask(int level)
129{
130 return -1UL << level_to_offset_bits(level);
131}
132
133static inline unsigned long level_size(int level)
134{
135 return 1UL << level_to_offset_bits(level);
136}
137
138static inline unsigned long align_to_level(unsigned long pfn, int level)
139{
140 return (pfn + level_size(level) - 1) & level_mask(level);
141}
David Woodhousefd18de52009-05-10 23:57:41 +0100142
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100143static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
144{
Jiang Liu5c645b32014-01-06 14:18:12 +0800145 return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100146}
147
David Woodhousedd4e8312009-06-27 16:21:20 +0100148/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
149 are never going to work. */
150static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
151{
152 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
153}
154
155static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
156{
157 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
158}
159static inline unsigned long page_to_dma_pfn(struct page *pg)
160{
161 return mm_to_dma_pfn(page_to_pfn(pg));
162}
163static inline unsigned long virt_to_dma_pfn(void *p)
164{
165 return page_to_dma_pfn(virt_to_page(p));
166}
167
Weidong Hand9630fe2008-12-08 11:06:32 +0800168/* global iommu list, set NULL for ignored DMAR units */
169static struct intel_iommu **g_iommus;
170
David Woodhousee0fc7e02009-09-30 09:12:17 -0700171static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000172static int rwbf_quirk;
173
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000174/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700175 * set to 1 to panic kernel if can't successfully enable VT-d
176 * (used when kernel is launched w/ TXT)
177 */
178static int force_on = 0;
179
180/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000181 * 0: Present
182 * 1-11: Reserved
183 * 12-63: Context Ptr (12 - (haw-1))
184 * 64-127: Reserved
185 */
186struct root_entry {
187 u64 val;
188 u64 rsvd1;
189};
190#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
191static inline bool root_present(struct root_entry *root)
192{
193 return (root->val & 1);
194}
195static inline void set_root_present(struct root_entry *root)
196{
197 root->val |= 1;
198}
199static inline void set_root_value(struct root_entry *root, unsigned long value)
200{
201 root->val |= value & VTD_PAGE_MASK;
202}
203
204static inline struct context_entry *
205get_context_addr_from_root(struct root_entry *root)
206{
207 return (struct context_entry *)
208 (root_present(root)?phys_to_virt(
209 root->val & VTD_PAGE_MASK) :
210 NULL);
211}
212
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000213/*
214 * low 64 bits:
215 * 0: present
216 * 1: fault processing disable
217 * 2-3: translation type
218 * 12-63: address space root
219 * high 64 bits:
220 * 0-2: address width
221 * 3-6: aval
222 * 8-23: domain id
223 */
224struct context_entry {
225 u64 lo;
226 u64 hi;
227};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000228
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000229static inline bool context_present(struct context_entry *context)
230{
231 return (context->lo & 1);
232}
233static inline void context_set_present(struct context_entry *context)
234{
235 context->lo |= 1;
236}
237
238static inline void context_set_fault_enable(struct context_entry *context)
239{
240 context->lo &= (((u64)-1) << 2) | 1;
241}
242
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000243static inline void context_set_translation_type(struct context_entry *context,
244 unsigned long value)
245{
246 context->lo &= (((u64)-1) << 4) | 3;
247 context->lo |= (value & 3) << 2;
248}
249
250static inline void context_set_address_root(struct context_entry *context,
251 unsigned long value)
252{
253 context->lo |= value & VTD_PAGE_MASK;
254}
255
256static inline void context_set_address_width(struct context_entry *context,
257 unsigned long value)
258{
259 context->hi |= value & 7;
260}
261
262static inline void context_set_domain_id(struct context_entry *context,
263 unsigned long value)
264{
265 context->hi |= (value & ((1 << 16) - 1)) << 8;
266}
267
268static inline void context_clear_entry(struct context_entry *context)
269{
270 context->lo = 0;
271 context->hi = 0;
272}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000273
Mark McLoughlin622ba122008-11-20 15:49:46 +0000274/*
275 * 0: readable
276 * 1: writable
277 * 2-6: reserved
278 * 7: super page
Sheng 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 McLoughlina647dacb2008-11-20 15:49:48 +0000371/* PCI domain-device relationship */
372struct device_domain_info {
373 struct list_head link; /* link to domain siblings */
374 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100375 int segment; /* PCI domain */
376 u8 bus; /* PCI bus number */
Mark McLoughlina647dacb2008-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 McLoughlina647dacb2008-11-20 15:49:48 +0000380 struct dmar_domain *domain; /* pointer to domain */
381};
382
Jiang Liub94e4112014-02-19 14:07:25 +0800383struct dmar_rmrr_unit {
384 struct list_head list; /* list of rmrr units */
385 struct acpi_dmar_header *hdr; /* ACPI header */
386 u64 base_address; /* reserved base address*/
387 u64 end_address; /* reserved end address */
388 struct pci_dev **devices; /* target devices */
389 int devices_cnt; /* target device count */
390};
391
392struct dmar_atsr_unit {
393 struct list_head list; /* list of ATSR units */
394 struct acpi_dmar_header *hdr; /* ACPI header */
395 struct pci_dev **devices; /* target devices */
396 int devices_cnt; /* target device count */
397 u8 include_all:1; /* include all ports */
398};
399
400static LIST_HEAD(dmar_atsr_units);
401static LIST_HEAD(dmar_rmrr_units);
402
403#define for_each_rmrr_units(rmrr) \
404 list_for_each_entry(rmrr, &dmar_rmrr_units, list)
405
mark gross5e0d2a62008-03-04 15:22:08 -0800406static void flush_unmaps_timeout(unsigned long data);
407
Jiang Liub707cb02014-01-06 14:18:26 +0800408static DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
mark gross5e0d2a62008-03-04 15:22:08 -0800409
mark gross80b20dd2008-04-18 13:53:58 -0700410#define HIGH_WATER_MARK 250
411struct deferred_flush_tables {
412 int next;
413 struct iova *iova[HIGH_WATER_MARK];
414 struct dmar_domain *domain[HIGH_WATER_MARK];
415};
416
417static struct deferred_flush_tables *deferred_flush;
418
mark gross5e0d2a62008-03-04 15:22:08 -0800419/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800420static int g_num_of_iommus;
421
422static DEFINE_SPINLOCK(async_umap_flush_lock);
423static LIST_HEAD(unmaps_to_do);
424
425static int timer_on;
426static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800427
Jiang Liu92d03cc2014-02-19 14:07:28 +0800428static void domain_exit(struct dmar_domain *domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700429static void domain_remove_dev_info(struct dmar_domain *domain);
Jiang Liub94e4112014-02-19 14:07:25 +0800430static void domain_remove_one_dev_info(struct dmar_domain *domain,
431 struct pci_dev *pdev);
Jiang Liu92d03cc2014-02-19 14:07:28 +0800432static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
433 struct pci_dev *pdev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700434
Suresh Siddhad3f13812011-08-23 17:05:25 -0700435#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800436int dmar_disabled = 0;
437#else
438int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700439#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800440
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200441int intel_iommu_enabled = 0;
442EXPORT_SYMBOL_GPL(intel_iommu_enabled);
443
David Woodhouse2d9e6672010-06-15 10:57:57 +0100444static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700445static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800446static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100447static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700448
David Woodhousec0771df2011-10-14 20:59:46 +0100449int intel_iommu_gfx_mapped;
450EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
451
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700452#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
453static DEFINE_SPINLOCK(device_domain_lock);
454static LIST_HEAD(device_domain_list);
455
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100456static struct iommu_ops intel_iommu_ops;
457
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700458static int __init intel_iommu_setup(char *str)
459{
460 if (!str)
461 return -EINVAL;
462 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800463 if (!strncmp(str, "on", 2)) {
464 dmar_disabled = 0;
465 printk(KERN_INFO "Intel-IOMMU: enabled\n");
466 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700467 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800468 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700469 } else if (!strncmp(str, "igfx_off", 8)) {
470 dmar_map_gfx = 0;
471 printk(KERN_INFO
472 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700473 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800474 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700475 "Intel-IOMMU: Forcing DAC for PCI devices\n");
476 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800477 } else if (!strncmp(str, "strict", 6)) {
478 printk(KERN_INFO
479 "Intel-IOMMU: disable batched IOTLB flush\n");
480 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100481 } else if (!strncmp(str, "sp_off", 6)) {
482 printk(KERN_INFO
483 "Intel-IOMMU: disable supported super page\n");
484 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700485 }
486
487 str += strcspn(str, ",");
488 while (*str == ',')
489 str++;
490 }
491 return 0;
492}
493__setup("intel_iommu=", intel_iommu_setup);
494
495static struct kmem_cache *iommu_domain_cache;
496static struct kmem_cache *iommu_devinfo_cache;
497static struct kmem_cache *iommu_iova_cache;
498
Suresh Siddha4c923d42009-10-02 11:01:24 -0700499static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700500{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700501 struct page *page;
502 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700503
Suresh Siddha4c923d42009-10-02 11:01:24 -0700504 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
505 if (page)
506 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700507 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700508}
509
510static inline void free_pgtable_page(void *vaddr)
511{
512 free_page((unsigned long)vaddr);
513}
514
515static inline void *alloc_domain_mem(void)
516{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900517 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700518}
519
Kay, Allen M38717942008-09-09 18:37:29 +0300520static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700521{
522 kmem_cache_free(iommu_domain_cache, vaddr);
523}
524
525static inline void * alloc_devinfo_mem(void)
526{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900527 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700528}
529
530static inline void free_devinfo_mem(void *vaddr)
531{
532 kmem_cache_free(iommu_devinfo_cache, vaddr);
533}
534
535struct iova *alloc_iova_mem(void)
536{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900537 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700538}
539
540void free_iova_mem(struct iova *iova)
541{
542 kmem_cache_free(iommu_iova_cache, iova);
543}
544
Weidong Han1b573682008-12-08 15:34:06 +0800545
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700546static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800547{
548 unsigned long sagaw;
549 int agaw = -1;
550
551 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700552 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800553 agaw >= 0; agaw--) {
554 if (test_bit(agaw, &sagaw))
555 break;
556 }
557
558 return agaw;
559}
560
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700561/*
562 * Calculate max SAGAW for each iommu.
563 */
564int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
565{
566 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
567}
568
569/*
570 * calculate agaw for each iommu.
571 * "SAGAW" may be different across iommus, use a default agaw, and
572 * get a supported less agaw for iommus that don't support the default agaw.
573 */
574int iommu_calculate_agaw(struct intel_iommu *iommu)
575{
576 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
577}
578
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700579/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800580static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
581{
582 int iommu_id;
583
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700584 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800585 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700586 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800587
Mike Travis1b198bb2012-03-05 15:05:16 -0800588 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800589 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
590 return NULL;
591
592 return g_iommus[iommu_id];
593}
594
Weidong Han8e6040972008-12-08 15:49:06 +0800595static void domain_update_iommu_coherency(struct dmar_domain *domain)
596{
597 int i;
598
Alex Williamson2e12bc22011-11-11 17:26:44 -0700599 i = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
600
601 domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0;
Weidong Han8e6040972008-12-08 15:49:06 +0800602
Mike Travis1b198bb2012-03-05 15:05:16 -0800603 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e6040972008-12-08 15:49:06 +0800604 if (!ecap_coherent(g_iommus[i]->ecap)) {
605 domain->iommu_coherency = 0;
606 break;
607 }
Weidong Han8e6040972008-12-08 15:49:06 +0800608 }
609}
610
Sheng Yang58c610b2009-03-18 15:33:05 +0800611static void domain_update_iommu_snooping(struct dmar_domain *domain)
612{
613 int i;
614
615 domain->iommu_snooping = 1;
616
Mike Travis1b198bb2012-03-05 15:05:16 -0800617 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800618 if (!ecap_sc_support(g_iommus[i]->ecap)) {
619 domain->iommu_snooping = 0;
620 break;
621 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800622 }
623}
624
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100625static void domain_update_iommu_superpage(struct dmar_domain *domain)
626{
Allen Kay8140a952011-10-14 12:32:17 -0700627 struct dmar_drhd_unit *drhd;
628 struct intel_iommu *iommu = NULL;
629 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100630
631 if (!intel_iommu_superpage) {
632 domain->iommu_superpage = 0;
633 return;
634 }
635
Allen Kay8140a952011-10-14 12:32:17 -0700636 /* set iommu_superpage to the smallest common denominator */
637 for_each_active_iommu(iommu, drhd) {
638 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100639 if (!mask) {
640 break;
641 }
642 }
643 domain->iommu_superpage = fls(mask);
644}
645
Sheng Yang58c610b2009-03-18 15:33:05 +0800646/* Some capabilities may be different across iommus */
647static void domain_update_iommu_cap(struct dmar_domain *domain)
648{
649 domain_update_iommu_coherency(domain);
650 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100651 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800652}
653
David Woodhouse276dbf992009-04-04 01:45:37 +0100654static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800655{
656 struct dmar_drhd_unit *drhd = NULL;
Jiang Liub683b232014-02-19 14:07:32 +0800657 struct intel_iommu *iommu;
658 struct pci_dev *dev;
Weidong Hanc7151a82008-12-08 22:51:37 +0800659 int i;
660
Jiang Liub683b232014-02-19 14:07:32 +0800661 for_each_active_iommu(iommu, drhd) {
David Woodhouse276dbf992009-04-04 01:45:37 +0100662 if (segment != drhd->segment)
663 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800664
Jiang Liub683b232014-02-19 14:07:32 +0800665 for_each_active_dev_scope(drhd->devices,
666 drhd->devices_cnt, i, dev) {
667 if (dev->bus->number == bus && dev->devfn == devfn)
668 goto out;
669 if (dev->subordinate &&
670 dev->subordinate->number <= bus &&
671 dev->subordinate->busn_res.end >= bus)
672 goto out;
David Woodhouse924b6232009-04-04 00:39:25 +0100673 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800674
675 if (drhd->include_all)
Jiang Liub683b232014-02-19 14:07:32 +0800676 goto out;
Weidong Hanc7151a82008-12-08 22:51:37 +0800677 }
Jiang Liub683b232014-02-19 14:07:32 +0800678 iommu = NULL;
679out:
Weidong Hanc7151a82008-12-08 22:51:37 +0800680
Jiang Liub683b232014-02-19 14:07:32 +0800681 return iommu;
Weidong Hanc7151a82008-12-08 22:51:37 +0800682}
683
Weidong Han5331fe62008-12-08 23:00:00 +0800684static void domain_flush_cache(struct dmar_domain *domain,
685 void *addr, int size)
686{
687 if (!domain->iommu_coherency)
688 clflush_cache_range(addr, size);
689}
690
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700691/* Gets context entry for a given bus and devfn */
692static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
693 u8 bus, u8 devfn)
694{
695 struct root_entry *root;
696 struct context_entry *context;
697 unsigned long phy_addr;
698 unsigned long flags;
699
700 spin_lock_irqsave(&iommu->lock, flags);
701 root = &iommu->root_entry[bus];
702 context = get_context_addr_from_root(root);
703 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700704 context = (struct context_entry *)
705 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700706 if (!context) {
707 spin_unlock_irqrestore(&iommu->lock, flags);
708 return NULL;
709 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700710 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700711 phy_addr = virt_to_phys((void *)context);
712 set_root_value(root, phy_addr);
713 set_root_present(root);
714 __iommu_flush_cache(iommu, root, sizeof(*root));
715 }
716 spin_unlock_irqrestore(&iommu->lock, flags);
717 return &context[devfn];
718}
719
720static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
721{
722 struct root_entry *root;
723 struct context_entry *context;
724 int ret;
725 unsigned long flags;
726
727 spin_lock_irqsave(&iommu->lock, flags);
728 root = &iommu->root_entry[bus];
729 context = get_context_addr_from_root(root);
730 if (!context) {
731 ret = 0;
732 goto out;
733 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000734 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700735out:
736 spin_unlock_irqrestore(&iommu->lock, flags);
737 return ret;
738}
739
740static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
741{
742 struct root_entry *root;
743 struct context_entry *context;
744 unsigned long flags;
745
746 spin_lock_irqsave(&iommu->lock, flags);
747 root = &iommu->root_entry[bus];
748 context = get_context_addr_from_root(root);
749 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000750 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700751 __iommu_flush_cache(iommu, &context[devfn], \
752 sizeof(*context));
753 }
754 spin_unlock_irqrestore(&iommu->lock, flags);
755}
756
757static void free_context_table(struct intel_iommu *iommu)
758{
759 struct root_entry *root;
760 int i;
761 unsigned long flags;
762 struct context_entry *context;
763
764 spin_lock_irqsave(&iommu->lock, flags);
765 if (!iommu->root_entry) {
766 goto out;
767 }
768 for (i = 0; i < ROOT_ENTRY_NR; i++) {
769 root = &iommu->root_entry[i];
770 context = get_context_addr_from_root(root);
771 if (context)
772 free_pgtable_page(context);
773 }
774 free_pgtable_page(iommu->root_entry);
775 iommu->root_entry = NULL;
776out:
777 spin_unlock_irqrestore(&iommu->lock, flags);
778}
779
David Woodhouseb026fd22009-06-28 10:37:25 +0100780static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
Allen Kay4399c8b2011-10-14 12:32:46 -0700781 unsigned long pfn, int target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700782{
David Woodhouseb026fd22009-06-28 10:37:25 +0100783 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700784 struct dma_pte *parent, *pte = NULL;
785 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700786 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700787
788 BUG_ON(!domain->pgd);
Julian Stecklinaf9423602013-10-09 10:03:52 +0200789
790 if (addr_width < BITS_PER_LONG && pfn >> addr_width)
791 /* Address beyond IOMMU's addressing capabilities. */
792 return NULL;
793
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700794 parent = domain->pgd;
795
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700796 while (level > 0) {
797 void *tmp_page;
798
David Woodhouseb026fd22009-06-28 10:37:25 +0100799 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700800 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700801 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100802 break;
803 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700804 break;
805
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000806 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100807 uint64_t pteval;
808
Suresh Siddha4c923d42009-10-02 11:01:24 -0700809 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700810
David Woodhouse206a73c2009-07-01 19:30:28 +0100811 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700812 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100813
David Woodhousec85994e2009-07-01 19:21:24 +0100814 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400815 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 +0100816 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
817 /* Someone else set it while we were thinking; use theirs. */
818 free_pgtable_page(tmp_page);
819 } else {
820 dma_pte_addr(pte);
821 domain_flush_cache(domain, pte, sizeof(*pte));
822 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700823 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000824 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700825 level--;
826 }
827
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700828 return pte;
829}
830
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100831
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700832/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100833static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
834 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100835 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700836{
837 struct dma_pte *parent, *pte = NULL;
838 int total = agaw_to_level(domain->agaw);
839 int offset;
840
841 parent = domain->pgd;
842 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100843 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700844 pte = &parent[offset];
845 if (level == total)
846 return pte;
847
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100848 if (!dma_pte_present(pte)) {
849 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700850 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100851 }
852
853 if (pte->val & DMA_PTE_LARGE_PAGE) {
854 *large_page = total;
855 return pte;
856 }
857
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000858 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700859 total--;
860 }
861 return NULL;
862}
863
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700864/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700865static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf52009-06-27 22:09:11 +0100866 unsigned long start_pfn,
867 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700868{
David Woodhouse04b18e62009-06-27 19:15:01 +0100869 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100870 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100871 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700872
David Woodhouse04b18e62009-06-27 19:15:01 +0100873 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf52009-06-27 22:09:11 +0100874 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700875 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100876
David Woodhouse04b18e62009-06-27 19:15:01 +0100877 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700878 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100879 large_page = 1;
880 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100881 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100882 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100883 continue;
884 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100885 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100886 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100887 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100888 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100889 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
890
David Woodhouse310a5ab2009-06-28 18:52:20 +0100891 domain_flush_cache(domain, first_pte,
892 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700893
894 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700895
Jiang Liu5c645b32014-01-06 14:18:12 +0800896 return min_t(int, (large_page - 1) * 9, MAX_AGAW_PFN_WIDTH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700897}
898
Alex Williamson3269ee02013-06-15 10:27:19 -0600899static void dma_pte_free_level(struct dmar_domain *domain, int level,
900 struct dma_pte *pte, unsigned long pfn,
901 unsigned long start_pfn, unsigned long last_pfn)
902{
903 pfn = max(start_pfn, pfn);
904 pte = &pte[pfn_level_offset(pfn, level)];
905
906 do {
907 unsigned long level_pfn;
908 struct dma_pte *level_pte;
909
910 if (!dma_pte_present(pte) || dma_pte_superpage(pte))
911 goto next;
912
913 level_pfn = pfn & level_mask(level - 1);
914 level_pte = phys_to_virt(dma_pte_addr(pte));
915
916 if (level > 2)
917 dma_pte_free_level(domain, level - 1, level_pte,
918 level_pfn, start_pfn, last_pfn);
919
920 /* If range covers entire pagetable, free it */
921 if (!(start_pfn > level_pfn ||
Alex Williamson08336fd2014-01-21 15:48:18 -0800922 last_pfn < level_pfn + level_size(level) - 1)) {
Alex Williamson3269ee02013-06-15 10:27:19 -0600923 dma_clear_pte(pte);
924 domain_flush_cache(domain, pte, sizeof(*pte));
925 free_pgtable_page(level_pte);
926 }
927next:
928 pfn += level_size(level);
929 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
930}
931
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700932/* free page table pages. last level pte should already be cleared */
933static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100934 unsigned long start_pfn,
935 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700936{
David Woodhouse6660c632009-06-27 22:41:00 +0100937 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700938
David Woodhouse6660c632009-06-27 22:41:00 +0100939 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
940 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700941 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700942
David Woodhousef3a0a522009-06-30 03:40:07 +0100943 /* We don't need lock here; nobody else touches the iova range */
Alex Williamson3269ee02013-06-15 10:27:19 -0600944 dma_pte_free_level(domain, agaw_to_level(domain->agaw),
945 domain->pgd, 0, start_pfn, last_pfn);
David Woodhouse6660c632009-06-27 22:41:00 +0100946
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700947 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100948 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700949 free_pgtable_page(domain->pgd);
950 domain->pgd = NULL;
951 }
952}
953
954/* iommu handling */
955static int iommu_alloc_root_entry(struct intel_iommu *iommu)
956{
957 struct root_entry *root;
958 unsigned long flags;
959
Suresh Siddha4c923d42009-10-02 11:01:24 -0700960 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700961 if (!root)
962 return -ENOMEM;
963
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700964 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700965
966 spin_lock_irqsave(&iommu->lock, flags);
967 iommu->root_entry = root;
968 spin_unlock_irqrestore(&iommu->lock, flags);
969
970 return 0;
971}
972
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700973static void iommu_set_root_entry(struct intel_iommu *iommu)
974{
975 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100976 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700977 unsigned long flag;
978
979 addr = iommu->root_entry;
980
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200981 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700982 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
983
David Woodhousec416daa2009-05-10 20:30:58 +0100984 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700985
986 /* Make sure hardware complete it */
987 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100988 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700989
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200990 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700991}
992
993static void iommu_flush_write_buffer(struct intel_iommu *iommu)
994{
995 u32 val;
996 unsigned long flag;
997
David Woodhouse9af88142009-02-13 23:18:03 +0000998 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700999 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001000
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001001 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +01001002 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001003
1004 /* Make sure hardware complete it */
1005 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001006 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001007
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001008 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001009}
1010
1011/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001012static void __iommu_flush_context(struct intel_iommu *iommu,
1013 u16 did, u16 source_id, u8 function_mask,
1014 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001015{
1016 u64 val = 0;
1017 unsigned long flag;
1018
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001019 switch (type) {
1020 case DMA_CCMD_GLOBAL_INVL:
1021 val = DMA_CCMD_GLOBAL_INVL;
1022 break;
1023 case DMA_CCMD_DOMAIN_INVL:
1024 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1025 break;
1026 case DMA_CCMD_DEVICE_INVL:
1027 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1028 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1029 break;
1030 default:
1031 BUG();
1032 }
1033 val |= DMA_CCMD_ICC;
1034
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001035 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001036 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1037
1038 /* Make sure hardware complete it */
1039 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1040 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1041
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001042 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001043}
1044
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001045/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001046static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1047 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001048{
1049 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1050 u64 val = 0, val_iva = 0;
1051 unsigned long flag;
1052
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001053 switch (type) {
1054 case DMA_TLB_GLOBAL_FLUSH:
1055 /* global flush doesn't need set IVA_REG */
1056 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1057 break;
1058 case DMA_TLB_DSI_FLUSH:
1059 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1060 break;
1061 case DMA_TLB_PSI_FLUSH:
1062 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1063 /* Note: always flush non-leaf currently */
1064 val_iva = size_order | addr;
1065 break;
1066 default:
1067 BUG();
1068 }
1069 /* Note: set drain read/write */
1070#if 0
1071 /*
1072 * This is probably to be super secure.. Looks like we can
1073 * ignore it without any impact.
1074 */
1075 if (cap_read_drain(iommu->cap))
1076 val |= DMA_TLB_READ_DRAIN;
1077#endif
1078 if (cap_write_drain(iommu->cap))
1079 val |= DMA_TLB_WRITE_DRAIN;
1080
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001081 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001082 /* Note: Only uses first TLB reg currently */
1083 if (val_iva)
1084 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1085 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1086
1087 /* Make sure hardware complete it */
1088 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1089 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1090
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001091 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001092
1093 /* check IOTLB invalidation granularity */
1094 if (DMA_TLB_IAIG(val) == 0)
1095 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1096 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1097 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001098 (unsigned long long)DMA_TLB_IIRG(type),
1099 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001100}
1101
Yu Zhao93a23a72009-05-18 13:51:37 +08001102static struct device_domain_info *iommu_support_dev_iotlb(
1103 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001104{
Yu Zhao93a23a72009-05-18 13:51:37 +08001105 int found = 0;
1106 unsigned long flags;
1107 struct device_domain_info *info;
1108 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1109
1110 if (!ecap_dev_iotlb_support(iommu->ecap))
1111 return NULL;
1112
1113 if (!iommu->qi)
1114 return NULL;
1115
1116 spin_lock_irqsave(&device_domain_lock, flags);
1117 list_for_each_entry(info, &domain->devices, link)
1118 if (info->bus == bus && info->devfn == devfn) {
1119 found = 1;
1120 break;
1121 }
1122 spin_unlock_irqrestore(&device_domain_lock, flags);
1123
1124 if (!found || !info->dev)
1125 return NULL;
1126
1127 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1128 return NULL;
1129
1130 if (!dmar_find_matched_atsr_unit(info->dev))
1131 return NULL;
1132
1133 info->iommu = iommu;
1134
1135 return info;
1136}
1137
1138static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1139{
1140 if (!info)
1141 return;
1142
1143 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1144}
1145
1146static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1147{
1148 if (!info->dev || !pci_ats_enabled(info->dev))
1149 return;
1150
1151 pci_disable_ats(info->dev);
1152}
1153
1154static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1155 u64 addr, unsigned mask)
1156{
1157 u16 sid, qdep;
1158 unsigned long flags;
1159 struct device_domain_info *info;
1160
1161 spin_lock_irqsave(&device_domain_lock, flags);
1162 list_for_each_entry(info, &domain->devices, link) {
1163 if (!info->dev || !pci_ats_enabled(info->dev))
1164 continue;
1165
1166 sid = info->bus << 8 | info->devfn;
1167 qdep = pci_ats_queue_depth(info->dev);
1168 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1169 }
1170 spin_unlock_irqrestore(&device_domain_lock, flags);
1171}
1172
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001173static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001174 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001175{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001176 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001177 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001178
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001179 BUG_ON(pages == 0);
1180
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001181 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001182 * Fallback to domain selective flush if no PSI support or the size is
1183 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001184 * PSI requires page size to be 2 ^ x, and the base address is naturally
1185 * aligned to the size
1186 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001187 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1188 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001189 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001190 else
1191 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1192 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001193
1194 /*
Nadav Amit82653632010-04-01 13:24:40 +03001195 * In caching mode, changes of pages from non-present to present require
1196 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001197 */
Nadav Amit82653632010-04-01 13:24:40 +03001198 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001199 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001200}
1201
mark grossf8bab732008-02-08 04:18:38 -08001202static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1203{
1204 u32 pmen;
1205 unsigned long flags;
1206
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001207 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001208 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1209 pmen &= ~DMA_PMEN_EPM;
1210 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1211
1212 /* wait for the protected region status bit to clear */
1213 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1214 readl, !(pmen & DMA_PMEN_PRS), pmen);
1215
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001216 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001217}
1218
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001219static int iommu_enable_translation(struct intel_iommu *iommu)
1220{
1221 u32 sts;
1222 unsigned long flags;
1223
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001224 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001225 iommu->gcmd |= DMA_GCMD_TE;
1226 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001227
1228 /* Make sure hardware complete it */
1229 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001230 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001231
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001232 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001233 return 0;
1234}
1235
1236static int iommu_disable_translation(struct intel_iommu *iommu)
1237{
1238 u32 sts;
1239 unsigned long flag;
1240
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001241 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001242 iommu->gcmd &= ~DMA_GCMD_TE;
1243 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1244
1245 /* Make sure hardware complete it */
1246 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001247 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001248
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001249 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001250 return 0;
1251}
1252
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001253
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001254static int iommu_init_domains(struct intel_iommu *iommu)
1255{
1256 unsigned long ndomains;
1257 unsigned long nlongs;
1258
1259 ndomains = cap_ndoms(iommu->cap);
Jiang Liu852bdb02014-01-06 14:18:11 +08001260 pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
1261 iommu->seq_id, ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001262 nlongs = BITS_TO_LONGS(ndomains);
1263
Donald Dutile94a91b502009-08-20 16:51:34 -04001264 spin_lock_init(&iommu->lock);
1265
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001266 /* TBD: there might be 64K domains,
1267 * consider other allocation for future chip
1268 */
1269 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1270 if (!iommu->domain_ids) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001271 pr_err("IOMMU%d: allocating domain id array failed\n",
1272 iommu->seq_id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001273 return -ENOMEM;
1274 }
1275 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1276 GFP_KERNEL);
1277 if (!iommu->domains) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001278 pr_err("IOMMU%d: allocating domain array failed\n",
1279 iommu->seq_id);
1280 kfree(iommu->domain_ids);
1281 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001282 return -ENOMEM;
1283 }
1284
1285 /*
1286 * if Caching mode is set, then invalid translations are tagged
1287 * with domainid 0. Hence we need to pre-allocate it.
1288 */
1289 if (cap_caching_mode(iommu->cap))
1290 set_bit(0, iommu->domain_ids);
1291 return 0;
1292}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001293
Jiang Liua868e6b2014-01-06 14:18:20 +08001294static void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001295{
1296 struct dmar_domain *domain;
Jiang Liu5ced12a2014-01-06 14:18:22 +08001297 int i, count;
Weidong Hanc7151a82008-12-08 22:51:37 +08001298 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001299
Donald Dutile94a91b502009-08-20 16:51:34 -04001300 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001301 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Jiang Liua4eaa862014-02-19 14:07:30 +08001302 /*
1303 * Domain id 0 is reserved for invalid translation
1304 * if hardware supports caching mode.
1305 */
1306 if (cap_caching_mode(iommu->cap) && i == 0)
1307 continue;
1308
Donald Dutile94a91b502009-08-20 16:51:34 -04001309 domain = iommu->domains[i];
1310 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001311
Donald Dutile94a91b502009-08-20 16:51:34 -04001312 spin_lock_irqsave(&domain->iommu_lock, flags);
Jiang Liu5ced12a2014-01-06 14:18:22 +08001313 count = --domain->iommu_count;
1314 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001315 if (count == 0)
1316 domain_exit(domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001317 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001318 }
1319
1320 if (iommu->gcmd & DMA_GCMD_TE)
1321 iommu_disable_translation(iommu);
1322
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001323 kfree(iommu->domains);
1324 kfree(iommu->domain_ids);
Jiang Liua868e6b2014-01-06 14:18:20 +08001325 iommu->domains = NULL;
1326 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001327
Weidong Hand9630fe2008-12-08 11:06:32 +08001328 g_iommus[iommu->seq_id] = NULL;
1329
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001330 /* free context mapping */
1331 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001332}
1333
Jiang Liu92d03cc2014-02-19 14:07:28 +08001334static struct dmar_domain *alloc_domain(bool vm)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001335{
Jiang Liu92d03cc2014-02-19 14:07:28 +08001336 /* domain id for virtual machine, it won't be set in context */
1337 static atomic_t vm_domid = ATOMIC_INIT(0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001338 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001339
1340 domain = alloc_domain_mem();
1341 if (!domain)
1342 return NULL;
1343
Suresh Siddha4c923d42009-10-02 11:01:24 -07001344 domain->nid = -1;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001345 domain->iommu_count = 0;
Mike Travis1b198bb2012-03-05 15:05:16 -08001346 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001347 domain->flags = 0;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001348 spin_lock_init(&domain->iommu_lock);
1349 INIT_LIST_HEAD(&domain->devices);
1350 if (vm) {
1351 domain->id = atomic_inc_return(&vm_domid);
1352 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
1353 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001354
1355 return domain;
1356}
1357
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001358static int iommu_attach_domain(struct dmar_domain *domain,
1359 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001360{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001361 int num;
1362 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001363 unsigned long flags;
1364
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001365 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001366
1367 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001368
1369 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1370 if (num >= ndomains) {
1371 spin_unlock_irqrestore(&iommu->lock, flags);
1372 printk(KERN_ERR "IOMMU: no free domain ids\n");
1373 return -ENOMEM;
1374 }
1375
1376 domain->id = num;
Jiang Liu9ebd6822014-02-19 14:07:29 +08001377 domain->iommu_count++;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001378 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001379 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001380 iommu->domains[num] = domain;
1381 spin_unlock_irqrestore(&iommu->lock, flags);
1382
1383 return 0;
1384}
1385
1386static void iommu_detach_domain(struct dmar_domain *domain,
1387 struct intel_iommu *iommu)
1388{
1389 unsigned long flags;
1390 int num, ndomains;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001391
1392 spin_lock_irqsave(&iommu->lock, flags);
1393 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001394 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001395 if (iommu->domains[num] == domain) {
Jiang Liu92d03cc2014-02-19 14:07:28 +08001396 clear_bit(num, iommu->domain_ids);
1397 iommu->domains[num] = NULL;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001398 break;
1399 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001400 }
Weidong Han8c11e792008-12-08 15:29:22 +08001401 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001402}
1403
1404static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001405static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001406
Joseph Cihula51a63e62011-03-21 11:04:24 -07001407static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001408{
1409 struct pci_dev *pdev = NULL;
1410 struct iova *iova;
1411 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001412
David Millerf6611972008-02-06 01:36:23 -08001413 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001414
Mark Gross8a443df2008-03-04 14:59:31 -08001415 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1416 &reserved_rbtree_key);
1417
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001418 /* IOAPIC ranges shouldn't be accessed by DMA */
1419 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1420 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001421 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001422 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001423 return -ENODEV;
1424 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001425
1426 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1427 for_each_pci_dev(pdev) {
1428 struct resource *r;
1429
1430 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1431 r = &pdev->resource[i];
1432 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1433 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001434 iova = reserve_iova(&reserved_iova_list,
1435 IOVA_PFN(r->start),
1436 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001437 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001438 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001439 return -ENODEV;
1440 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001441 }
1442 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001443 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001444}
1445
1446static void domain_reserve_special_ranges(struct dmar_domain *domain)
1447{
1448 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1449}
1450
1451static inline int guestwidth_to_adjustwidth(int gaw)
1452{
1453 int agaw;
1454 int r = (gaw - 12) % 9;
1455
1456 if (r == 0)
1457 agaw = gaw;
1458 else
1459 agaw = gaw + 9 - r;
1460 if (agaw > 64)
1461 agaw = 64;
1462 return agaw;
1463}
1464
1465static int domain_init(struct dmar_domain *domain, int guest_width)
1466{
1467 struct intel_iommu *iommu;
1468 int adjust_width, agaw;
1469 unsigned long sagaw;
1470
David Millerf6611972008-02-06 01:36:23 -08001471 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001472 domain_reserve_special_ranges(domain);
1473
1474 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001475 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001476 if (guest_width > cap_mgaw(iommu->cap))
1477 guest_width = cap_mgaw(iommu->cap);
1478 domain->gaw = guest_width;
1479 adjust_width = guestwidth_to_adjustwidth(guest_width);
1480 agaw = width_to_agaw(adjust_width);
1481 sagaw = cap_sagaw(iommu->cap);
1482 if (!test_bit(agaw, &sagaw)) {
1483 /* hardware doesn't support it, choose a bigger one */
1484 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1485 agaw = find_next_bit(&sagaw, 5, agaw);
1486 if (agaw >= 5)
1487 return -ENODEV;
1488 }
1489 domain->agaw = agaw;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001490
Weidong Han8e6040972008-12-08 15:49:06 +08001491 if (ecap_coherent(iommu->ecap))
1492 domain->iommu_coherency = 1;
1493 else
1494 domain->iommu_coherency = 0;
1495
Sheng Yang58c610b2009-03-18 15:33:05 +08001496 if (ecap_sc_support(iommu->ecap))
1497 domain->iommu_snooping = 1;
1498 else
1499 domain->iommu_snooping = 0;
1500
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001501 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Suresh Siddha4c923d42009-10-02 11:01:24 -07001502 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001503
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001504 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001505 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001506 if (!domain->pgd)
1507 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001508 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001509 return 0;
1510}
1511
1512static void domain_exit(struct dmar_domain *domain)
1513{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001514 struct dmar_drhd_unit *drhd;
1515 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001516
1517 /* Domain 0 is reserved, so dont process it */
1518 if (!domain)
1519 return;
1520
Alex Williamson7b668352011-05-24 12:02:41 +01001521 /* Flush any lazy unmaps that may reference this domain */
1522 if (!intel_iommu_strict)
1523 flush_unmaps_timeout(0);
1524
Jiang Liu92d03cc2014-02-19 14:07:28 +08001525 /* remove associated devices */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001526 domain_remove_dev_info(domain);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001527
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001528 /* destroy iovas */
1529 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001530
1531 /* clear ptes */
David Woodhouse595badf52009-06-27 22:09:11 +01001532 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001533
1534 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001535 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001536
Jiang Liu92d03cc2014-02-19 14:07:28 +08001537 /* clear attached or cached domains */
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001538 for_each_active_iommu(iommu, drhd)
Jiang Liu92d03cc2014-02-19 14:07:28 +08001539 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1540 test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001541 iommu_detach_domain(domain, iommu);
1542
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001543 free_domain_mem(domain);
1544}
1545
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001546static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1547 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001548{
1549 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001550 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001551 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001552 struct dma_pte *pgd;
1553 unsigned long num;
1554 unsigned long ndomains;
1555 int id;
1556 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001557 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001558
1559 pr_debug("Set context mapping for %02x:%02x.%d\n",
1560 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001561
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001562 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001563 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1564 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001565
David Woodhouse276dbf992009-04-04 01:45:37 +01001566 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001567 if (!iommu)
1568 return -ENODEV;
1569
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001570 context = device_to_context_entry(iommu, bus, devfn);
1571 if (!context)
1572 return -ENOMEM;
1573 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001574 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001575 spin_unlock_irqrestore(&iommu->lock, flags);
1576 return 0;
1577 }
1578
Weidong Hanea6606b2008-12-08 23:08:15 +08001579 id = domain->id;
1580 pgd = domain->pgd;
1581
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001582 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1583 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001584 int found = 0;
1585
1586 /* find an available domain id for this device in iommu */
1587 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001588 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001589 if (iommu->domains[num] == domain) {
1590 id = num;
1591 found = 1;
1592 break;
1593 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001594 }
1595
1596 if (found == 0) {
1597 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1598 if (num >= ndomains) {
1599 spin_unlock_irqrestore(&iommu->lock, flags);
1600 printk(KERN_ERR "IOMMU: no free domain ids\n");
1601 return -EFAULT;
1602 }
1603
1604 set_bit(num, iommu->domain_ids);
1605 iommu->domains[num] = domain;
1606 id = num;
1607 }
1608
1609 /* Skip top levels of page tables for
1610 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001611 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001612 */
Chris Wright1672af12009-12-02 12:06:34 -08001613 if (translation != CONTEXT_TT_PASS_THROUGH) {
1614 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1615 pgd = phys_to_virt(dma_pte_addr(pgd));
1616 if (!dma_pte_present(pgd)) {
1617 spin_unlock_irqrestore(&iommu->lock, flags);
1618 return -ENOMEM;
1619 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001620 }
1621 }
1622 }
1623
1624 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001625
Yu Zhao93a23a72009-05-18 13:51:37 +08001626 if (translation != CONTEXT_TT_PASS_THROUGH) {
1627 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1628 translation = info ? CONTEXT_TT_DEV_IOTLB :
1629 CONTEXT_TT_MULTI_LEVEL;
1630 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001631 /*
1632 * In pass through mode, AW must be programmed to indicate the largest
1633 * AGAW value supported by hardware. And ASR is ignored by hardware.
1634 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001635 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001636 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001637 else {
1638 context_set_address_root(context, virt_to_phys(pgd));
1639 context_set_address_width(context, iommu->agaw);
1640 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001641
1642 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001643 context_set_fault_enable(context);
1644 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001645 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001646
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001647 /*
1648 * It's a non-present to present mapping. If hardware doesn't cache
1649 * non-present entry we only need to flush the write-buffer. If the
1650 * _does_ cache non-present entries, then it does so in the special
1651 * domain #0, which we have to flush:
1652 */
1653 if (cap_caching_mode(iommu->cap)) {
1654 iommu->flush.flush_context(iommu, 0,
1655 (((u16)bus) << 8) | devfn,
1656 DMA_CCMD_MASK_NOBIT,
1657 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001658 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001659 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001660 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001661 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001662 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001663 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001664
1665 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001666 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001667 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001668 if (domain->iommu_count == 1)
1669 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001670 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001671 }
1672 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001673 return 0;
1674}
1675
1676static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001677domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1678 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001679{
1680 int ret;
1681 struct pci_dev *tmp, *parent;
1682
David Woodhouse276dbf992009-04-04 01:45:37 +01001683 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001684 pdev->bus->number, pdev->devfn,
1685 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001686 if (ret)
1687 return ret;
1688
1689 /* dependent device mapping */
1690 tmp = pci_find_upstream_pcie_bridge(pdev);
1691 if (!tmp)
1692 return 0;
1693 /* Secondary interface's bus number and devfn 0 */
1694 parent = pdev->bus->self;
1695 while (parent != tmp) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001696 ret = domain_context_mapping_one(domain,
1697 pci_domain_nr(parent->bus),
1698 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001699 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001700 if (ret)
1701 return ret;
1702 parent = parent->bus->self;
1703 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001704 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001705 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001706 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001707 tmp->subordinate->number, 0,
1708 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001709 else /* this is a legacy PCI bridge */
1710 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001711 pci_domain_nr(tmp->bus),
1712 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001713 tmp->devfn,
1714 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001715}
1716
Weidong Han5331fe62008-12-08 23:00:00 +08001717static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001718{
1719 int ret;
1720 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001721 struct intel_iommu *iommu;
1722
David Woodhouse276dbf992009-04-04 01:45:37 +01001723 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1724 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001725 if (!iommu)
1726 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001727
David Woodhouse276dbf992009-04-04 01:45:37 +01001728 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001729 if (!ret)
1730 return ret;
1731 /* dependent device mapping */
1732 tmp = pci_find_upstream_pcie_bridge(pdev);
1733 if (!tmp)
1734 return ret;
1735 /* Secondary interface's bus number and devfn 0 */
1736 parent = pdev->bus->self;
1737 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001738 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001739 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001740 if (!ret)
1741 return ret;
1742 parent = parent->bus->self;
1743 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001744 if (pci_is_pcie(tmp))
David Woodhouse276dbf992009-04-04 01:45:37 +01001745 return device_context_mapped(iommu, tmp->subordinate->number,
1746 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001747 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001748 return device_context_mapped(iommu, tmp->bus->number,
1749 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001750}
1751
Fenghua Yuf5329592009-08-04 15:09:37 -07001752/* Returns a number of VTD pages, but aligned to MM page size */
1753static inline unsigned long aligned_nrpages(unsigned long host_addr,
1754 size_t size)
1755{
1756 host_addr &= ~PAGE_MASK;
1757 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1758}
1759
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001760/* Return largest possible superpage level for a given mapping */
1761static inline int hardware_largepage_caps(struct dmar_domain *domain,
1762 unsigned long iov_pfn,
1763 unsigned long phy_pfn,
1764 unsigned long pages)
1765{
1766 int support, level = 1;
1767 unsigned long pfnmerge;
1768
1769 support = domain->iommu_superpage;
1770
1771 /* To use a large page, the virtual *and* physical addresses
1772 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1773 of them will mean we have to use smaller pages. So just
1774 merge them and check both at once. */
1775 pfnmerge = iov_pfn | phy_pfn;
1776
1777 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1778 pages >>= VTD_STRIDE_SHIFT;
1779 if (!pages)
1780 break;
1781 pfnmerge >>= VTD_STRIDE_SHIFT;
1782 level++;
1783 support--;
1784 }
1785 return level;
1786}
1787
David Woodhouse9051aa02009-06-29 12:30:54 +01001788static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1789 struct scatterlist *sg, unsigned long phys_pfn,
1790 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001791{
1792 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001793 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001794 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001795 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001796 unsigned int largepage_lvl = 0;
1797 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001798
1799 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1800
1801 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1802 return -EINVAL;
1803
1804 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1805
David Woodhouse9051aa02009-06-29 12:30:54 +01001806 if (sg)
1807 sg_res = 0;
1808 else {
1809 sg_res = nr_pages + 1;
1810 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1811 }
1812
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001813 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001814 uint64_t tmp;
1815
David Woodhousee1605492009-06-29 11:17:38 +01001816 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001817 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001818 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1819 sg->dma_length = sg->length;
1820 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001821 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001822 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001823
David Woodhousee1605492009-06-29 11:17:38 +01001824 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001825 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1826
1827 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001828 if (!pte)
1829 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001830 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001831 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001832 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001833 /* Ensure that old small page tables are removed to make room
1834 for superpage, if they exist. */
1835 dma_pte_clear_range(domain, iov_pfn,
1836 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1837 dma_pte_free_pagetable(domain, iov_pfn,
1838 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1839 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001840 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001841 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001842
David Woodhousee1605492009-06-29 11:17:38 +01001843 }
1844 /* We don't need lock here, nobody else
1845 * touches the iova range
1846 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001847 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001848 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001849 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001850 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1851 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001852 if (dumps) {
1853 dumps--;
1854 debug_dma_dump_mappings(NULL);
1855 }
1856 WARN_ON(1);
1857 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001858
1859 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1860
1861 BUG_ON(nr_pages < lvl_pages);
1862 BUG_ON(sg_res < lvl_pages);
1863
1864 nr_pages -= lvl_pages;
1865 iov_pfn += lvl_pages;
1866 phys_pfn += lvl_pages;
1867 pteval += lvl_pages * VTD_PAGE_SIZE;
1868 sg_res -= lvl_pages;
1869
1870 /* If the next PTE would be the first in a new page, then we
1871 need to flush the cache on the entries we've just written.
1872 And then we'll need to recalculate 'pte', so clear it and
1873 let it get set again in the if (!pte) block above.
1874
1875 If we're done (!nr_pages) we need to flush the cache too.
1876
1877 Also if we've been setting superpages, we may need to
1878 recalculate 'pte' and switch back to smaller pages for the
1879 end of the mapping, if the trailing size is not enough to
1880 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001881 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001882 if (!nr_pages || first_pte_in_page(pte) ||
1883 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001884 domain_flush_cache(domain, first_pte,
1885 (void *)pte - (void *)first_pte);
1886 pte = NULL;
1887 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001888
1889 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001890 sg = sg_next(sg);
1891 }
1892 return 0;
1893}
1894
David Woodhouse9051aa02009-06-29 12:30:54 +01001895static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1896 struct scatterlist *sg, unsigned long nr_pages,
1897 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001898{
David Woodhouse9051aa02009-06-29 12:30:54 +01001899 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1900}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001901
David Woodhouse9051aa02009-06-29 12:30:54 +01001902static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1903 unsigned long phys_pfn, unsigned long nr_pages,
1904 int prot)
1905{
1906 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001907}
1908
Weidong Hanc7151a82008-12-08 22:51:37 +08001909static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001910{
Weidong Hanc7151a82008-12-08 22:51:37 +08001911 if (!iommu)
1912 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001913
1914 clear_context_table(iommu, bus, devfn);
1915 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001916 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001917 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001918}
1919
David Woodhouse109b9b02012-05-25 17:43:02 +01001920static inline void unlink_domain_info(struct device_domain_info *info)
1921{
1922 assert_spin_locked(&device_domain_lock);
1923 list_del(&info->link);
1924 list_del(&info->global);
1925 if (info->dev)
1926 info->dev->dev.archdata.iommu = NULL;
1927}
1928
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001929static void domain_remove_dev_info(struct dmar_domain *domain)
1930{
1931 struct device_domain_info *info;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001932 unsigned long flags, flags2;
Weidong Hanc7151a82008-12-08 22:51:37 +08001933 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001934
1935 spin_lock_irqsave(&device_domain_lock, flags);
1936 while (!list_empty(&domain->devices)) {
1937 info = list_entry(domain->devices.next,
1938 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01001939 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001940 spin_unlock_irqrestore(&device_domain_lock, flags);
1941
Yu Zhao93a23a72009-05-18 13:51:37 +08001942 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01001943 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001944 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001945
Jiang Liu92d03cc2014-02-19 14:07:28 +08001946 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
1947 iommu_detach_dependent_devices(iommu, info->dev);
1948 /* clear this iommu in iommu_bmp, update iommu count
1949 * and capabilities
1950 */
1951 spin_lock_irqsave(&domain->iommu_lock, flags2);
1952 if (test_and_clear_bit(iommu->seq_id,
1953 domain->iommu_bmp)) {
1954 domain->iommu_count--;
1955 domain_update_iommu_cap(domain);
1956 }
1957 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
1958 }
1959
1960 free_devinfo_mem(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001961 spin_lock_irqsave(&device_domain_lock, flags);
1962 }
1963 spin_unlock_irqrestore(&device_domain_lock, flags);
1964}
1965
1966/*
1967 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001968 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001969 */
Kay, Allen M38717942008-09-09 18:37:29 +03001970static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001971find_domain(struct pci_dev *pdev)
1972{
1973 struct device_domain_info *info;
1974
1975 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001976 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001977 if (info)
1978 return info->domain;
1979 return NULL;
1980}
1981
Jiang Liu745f2582014-02-19 14:07:26 +08001982static inline struct dmar_domain *
1983dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
1984{
1985 struct device_domain_info *info;
1986
1987 list_for_each_entry(info, &device_domain_list, global)
1988 if (info->segment == segment && info->bus == bus &&
1989 info->devfn == devfn)
1990 return info->domain;
1991
1992 return NULL;
1993}
1994
1995static int dmar_insert_dev_info(int segment, int bus, int devfn,
1996 struct pci_dev *dev, struct dmar_domain **domp)
1997{
1998 struct dmar_domain *found, *domain = *domp;
1999 struct device_domain_info *info;
2000 unsigned long flags;
2001
2002 info = alloc_devinfo_mem();
2003 if (!info)
2004 return -ENOMEM;
2005
2006 info->segment = segment;
2007 info->bus = bus;
2008 info->devfn = devfn;
2009 info->dev = dev;
2010 info->domain = domain;
2011 if (!dev)
2012 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
2013
2014 spin_lock_irqsave(&device_domain_lock, flags);
2015 if (dev)
2016 found = find_domain(dev);
2017 else
2018 found = dmar_search_domain_by_dev_info(segment, bus, devfn);
2019 if (found) {
2020 spin_unlock_irqrestore(&device_domain_lock, flags);
2021 free_devinfo_mem(info);
2022 if (found != domain) {
2023 domain_exit(domain);
2024 *domp = found;
2025 }
2026 } else {
2027 list_add(&info->link, &domain->devices);
2028 list_add(&info->global, &device_domain_list);
2029 if (dev)
2030 dev->dev.archdata.iommu = info;
2031 spin_unlock_irqrestore(&device_domain_lock, flags);
2032 }
2033
2034 return 0;
2035}
2036
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002037/* domain is initialized */
2038static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
2039{
Jiang Liue85bb5d2014-02-19 14:07:27 +08002040 struct dmar_domain *domain, *free = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002041 struct intel_iommu *iommu;
2042 struct dmar_drhd_unit *drhd;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002043 struct pci_dev *dev_tmp;
2044 unsigned long flags;
2045 int bus = 0, devfn = 0;
David Woodhouse276dbf992009-04-04 01:45:37 +01002046 int segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002047
2048 domain = find_domain(pdev);
2049 if (domain)
2050 return domain;
2051
David Woodhouse276dbf992009-04-04 01:45:37 +01002052 segment = pci_domain_nr(pdev->bus);
2053
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002054 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
2055 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002056 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002057 bus = dev_tmp->subordinate->number;
2058 devfn = 0;
2059 } else {
2060 bus = dev_tmp->bus->number;
2061 devfn = dev_tmp->devfn;
2062 }
2063 spin_lock_irqsave(&device_domain_lock, flags);
Jiang Liu745f2582014-02-19 14:07:26 +08002064 domain = dmar_search_domain_by_dev_info(segment, bus, devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002065 spin_unlock_irqrestore(&device_domain_lock, flags);
2066 /* pcie-pci bridge already has a domain, uses it */
Jiang Liu745f2582014-02-19 14:07:26 +08002067 if (domain)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002068 goto found_domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002069 }
2070
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002071 drhd = dmar_find_matched_drhd_unit(pdev);
2072 if (!drhd) {
2073 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2074 pci_name(pdev));
2075 return NULL;
2076 }
2077 iommu = drhd->iommu;
2078
Jiang Liu745f2582014-02-19 14:07:26 +08002079 /* Allocate and intialize new domain for the device */
Jiang Liu92d03cc2014-02-19 14:07:28 +08002080 domain = alloc_domain(false);
Jiang Liu745f2582014-02-19 14:07:26 +08002081 if (!domain)
2082 goto error;
2083 if (iommu_attach_domain(domain, iommu)) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002084 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002085 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002086 }
Jiang Liue85bb5d2014-02-19 14:07:27 +08002087 free = domain;
2088 if (domain_init(domain, gaw))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002089 goto error;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002090
2091 /* register pcie-to-pci device */
2092 if (dev_tmp) {
Jiang Liue85bb5d2014-02-19 14:07:27 +08002093 if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002094 goto error;
Jiang Liue85bb5d2014-02-19 14:07:27 +08002095 else
2096 free = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002097 }
2098
2099found_domain:
Jiang Liu745f2582014-02-19 14:07:26 +08002100 if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
2101 pdev, &domain) == 0)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002102 return domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002103error:
Jiang Liue85bb5d2014-02-19 14:07:27 +08002104 if (free)
2105 domain_exit(free);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002106 /* recheck it here, maybe others set it */
2107 return find_domain(pdev);
2108}
2109
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002110static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002111#define IDENTMAP_ALL 1
2112#define IDENTMAP_GFX 2
2113#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002114
David Woodhouseb2132032009-06-26 18:50:28 +01002115static int iommu_domain_identity_map(struct dmar_domain *domain,
2116 unsigned long long start,
2117 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002118{
David Woodhousec5395d52009-06-28 16:35:56 +01002119 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2120 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002121
David Woodhousec5395d52009-06-28 16:35:56 +01002122 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2123 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002124 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002125 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002126 }
2127
David Woodhousec5395d52009-06-28 16:35:56 +01002128 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2129 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002130 /*
2131 * RMRR range might have overlap with physical memory range,
2132 * clear it first
2133 */
David Woodhousec5395d52009-06-28 16:35:56 +01002134 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002135
David Woodhousec5395d52009-06-28 16:35:56 +01002136 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2137 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002138 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002139}
2140
2141static int iommu_prepare_identity_map(struct pci_dev *pdev,
2142 unsigned long long start,
2143 unsigned long long end)
2144{
2145 struct dmar_domain *domain;
2146 int ret;
2147
David Woodhousec7ab48d2009-06-26 19:10:36 +01002148 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002149 if (!domain)
2150 return -ENOMEM;
2151
David Woodhouse19943b02009-08-04 16:19:20 +01002152 /* For _hardware_ passthrough, don't bother. But for software
2153 passthrough, we do it anyway -- it may indicate a memory
2154 range which is reserved in E820, so which didn't get set
2155 up to start with in si_domain */
2156 if (domain == si_domain && hw_pass_through) {
2157 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2158 pci_name(pdev), start, end);
2159 return 0;
2160 }
2161
2162 printk(KERN_INFO
2163 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2164 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002165
David Woodhouse5595b522009-12-02 09:21:55 +00002166 if (end < start) {
2167 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2168 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2169 dmi_get_system_info(DMI_BIOS_VENDOR),
2170 dmi_get_system_info(DMI_BIOS_VERSION),
2171 dmi_get_system_info(DMI_PRODUCT_VERSION));
2172 ret = -EIO;
2173 goto error;
2174 }
2175
David Woodhouse2ff729f2009-08-26 14:25:41 +01002176 if (end >> agaw_to_width(domain->agaw)) {
2177 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2178 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2179 agaw_to_width(domain->agaw),
2180 dmi_get_system_info(DMI_BIOS_VENDOR),
2181 dmi_get_system_info(DMI_BIOS_VERSION),
2182 dmi_get_system_info(DMI_PRODUCT_VERSION));
2183 ret = -EIO;
2184 goto error;
2185 }
David Woodhouse19943b02009-08-04 16:19:20 +01002186
David Woodhouseb2132032009-06-26 18:50:28 +01002187 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002188 if (ret)
2189 goto error;
2190
2191 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002192 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002193 if (ret)
2194 goto error;
2195
2196 return 0;
2197
2198 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002199 domain_exit(domain);
2200 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002201}
2202
2203static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2204 struct pci_dev *pdev)
2205{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002206 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002207 return 0;
2208 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002209 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002210}
2211
Suresh Siddhad3f13812011-08-23 17:05:25 -07002212#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002213static inline void iommu_prepare_isa(void)
2214{
2215 struct pci_dev *pdev;
2216 int ret;
2217
2218 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2219 if (!pdev)
2220 return;
2221
David Woodhousec7ab48d2009-06-26 19:10:36 +01002222 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002223 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002224
2225 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002226 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2227 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002228
2229}
2230#else
2231static inline void iommu_prepare_isa(void)
2232{
2233 return;
2234}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002235#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002236
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002237static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002238
Matt Kraai071e1372009-08-23 22:30:22 -07002239static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002240{
2241 struct dmar_drhd_unit *drhd;
2242 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002243 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002244
Jiang Liu92d03cc2014-02-19 14:07:28 +08002245 si_domain = alloc_domain(false);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002246 if (!si_domain)
2247 return -EFAULT;
2248
Jiang Liu92d03cc2014-02-19 14:07:28 +08002249 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2250
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002251 for_each_active_iommu(iommu, drhd) {
2252 ret = iommu_attach_domain(si_domain, iommu);
2253 if (ret) {
2254 domain_exit(si_domain);
2255 return -EFAULT;
2256 }
2257 }
2258
2259 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2260 domain_exit(si_domain);
2261 return -EFAULT;
2262 }
2263
Jiang Liu9544c002014-01-06 14:18:13 +08002264 pr_debug("IOMMU: identity mapping domain is domain %d\n",
2265 si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002266
David Woodhouse19943b02009-08-04 16:19:20 +01002267 if (hw)
2268 return 0;
2269
David Woodhousec7ab48d2009-06-26 19:10:36 +01002270 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002271 unsigned long start_pfn, end_pfn;
2272 int i;
2273
2274 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2275 ret = iommu_domain_identity_map(si_domain,
2276 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2277 if (ret)
2278 return ret;
2279 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002280 }
2281
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002282 return 0;
2283}
2284
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002285static int identity_mapping(struct pci_dev *pdev)
2286{
2287 struct device_domain_info *info;
2288
2289 if (likely(!iommu_identity_mapping))
2290 return 0;
2291
Mike Traviscb452a42011-05-28 13:15:03 -05002292 info = pdev->dev.archdata.iommu;
2293 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2294 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002295
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002296 return 0;
2297}
2298
2299static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002300 struct pci_dev *pdev,
2301 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002302{
2303 struct device_domain_info *info;
2304 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002305 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002306
2307 info = alloc_devinfo_mem();
2308 if (!info)
2309 return -ENOMEM;
2310
2311 info->segment = pci_domain_nr(pdev->bus);
2312 info->bus = pdev->bus->number;
2313 info->devfn = pdev->devfn;
2314 info->dev = pdev;
2315 info->domain = domain;
2316
2317 spin_lock_irqsave(&device_domain_lock, flags);
2318 list_add(&info->link, &domain->devices);
2319 list_add(&info->global, &device_domain_list);
2320 pdev->dev.archdata.iommu = info;
2321 spin_unlock_irqrestore(&device_domain_lock, flags);
2322
David Woodhousee2ad23d2012-05-25 17:42:54 +01002323 ret = domain_context_mapping(domain, pdev, translation);
2324 if (ret) {
2325 spin_lock_irqsave(&device_domain_lock, flags);
David Woodhouse109b9b02012-05-25 17:43:02 +01002326 unlink_domain_info(info);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002327 spin_unlock_irqrestore(&device_domain_lock, flags);
2328 free_devinfo_mem(info);
2329 return ret;
2330 }
2331
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002332 return 0;
2333}
2334
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002335static bool device_has_rmrr(struct pci_dev *dev)
2336{
2337 struct dmar_rmrr_unit *rmrr;
Jiang Liub683b232014-02-19 14:07:32 +08002338 struct pci_dev *tmp;
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002339 int i;
2340
2341 for_each_rmrr_units(rmrr) {
Jiang Liub683b232014-02-19 14:07:32 +08002342 /*
2343 * Return TRUE if this RMRR contains the device that
2344 * is passed in.
2345 */
2346 for_each_active_dev_scope(rmrr->devices,
2347 rmrr->devices_cnt, i, tmp)
2348 if (tmp == dev) {
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002349 return true;
Jiang Liub683b232014-02-19 14:07:32 +08002350 }
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002351 }
2352 return false;
2353}
2354
David Woodhouse6941af22009-07-04 18:24:27 +01002355static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2356{
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002357
2358 /*
2359 * We want to prevent any device associated with an RMRR from
2360 * getting placed into the SI Domain. This is done because
2361 * problems exist when devices are moved in and out of domains
2362 * and their respective RMRR info is lost. We exempt USB devices
2363 * from this process due to their usage of RMRRs that are known
2364 * to not be needed after BIOS hand-off to OS.
2365 */
2366 if (device_has_rmrr(pdev) &&
2367 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2368 return 0;
2369
David Woodhousee0fc7e02009-09-30 09:12:17 -07002370 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2371 return 1;
2372
2373 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2374 return 1;
2375
2376 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2377 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002378
David Woodhouse3dfc8132009-07-04 19:11:08 +01002379 /*
2380 * We want to start off with all devices in the 1:1 domain, and
2381 * take them out later if we find they can't access all of memory.
2382 *
2383 * However, we can't do this for PCI devices behind bridges,
2384 * because all PCI devices behind the same bridge will end up
2385 * with the same source-id on their transactions.
2386 *
2387 * Practically speaking, we can't change things around for these
2388 * devices at run-time, because we can't be sure there'll be no
2389 * DMA transactions in flight for any of their siblings.
2390 *
2391 * So PCI devices (unless they're on the root bus) as well as
2392 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2393 * the 1:1 domain, just in _case_ one of their siblings turns out
2394 * not to be able to map all of memory.
2395 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002396 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002397 if (!pci_is_root_bus(pdev->bus))
2398 return 0;
2399 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2400 return 0;
Yijing Wang62f87c02012-07-24 17:20:03 +08002401 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
David Woodhouse3dfc8132009-07-04 19:11:08 +01002402 return 0;
2403
2404 /*
2405 * At boot time, we don't yet know if devices will be 64-bit capable.
2406 * Assume that they will -- if they turn out not to be, then we can
2407 * take them out of the 1:1 domain later.
2408 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002409 if (!startup) {
2410 /*
2411 * If the device's dma_mask is less than the system's memory
2412 * size then this is not a candidate for identity mapping.
2413 */
2414 u64 dma_mask = pdev->dma_mask;
2415
2416 if (pdev->dev.coherent_dma_mask &&
2417 pdev->dev.coherent_dma_mask < dma_mask)
2418 dma_mask = pdev->dev.coherent_dma_mask;
2419
2420 return dma_mask >= dma_get_required_mask(&pdev->dev);
2421 }
David Woodhouse6941af22009-07-04 18:24:27 +01002422
2423 return 1;
2424}
2425
Matt Kraai071e1372009-08-23 22:30:22 -07002426static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002427{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002428 struct pci_dev *pdev = NULL;
2429 int ret;
2430
David Woodhouse19943b02009-08-04 16:19:20 +01002431 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002432 if (ret)
2433 return -EFAULT;
2434
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002435 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002436 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002437 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002438 hw ? CONTEXT_TT_PASS_THROUGH :
2439 CONTEXT_TT_MULTI_LEVEL);
2440 if (ret) {
2441 /* device not associated with an iommu */
2442 if (ret == -ENODEV)
2443 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002444 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002445 }
2446 pr_info("IOMMU: %s identity mapping for device %s\n",
2447 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002448 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002449 }
2450
2451 return 0;
2452}
2453
Joseph Cihulab7792602011-05-03 00:08:37 -07002454static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002455{
2456 struct dmar_drhd_unit *drhd;
2457 struct dmar_rmrr_unit *rmrr;
2458 struct pci_dev *pdev;
2459 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002460 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002461
2462 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002463 * for each drhd
2464 * allocate root
2465 * initialize and program root entry to not present
2466 * endfor
2467 */
2468 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002469 /*
2470 * lock not needed as this is only incremented in the single
2471 * threaded kernel __init code path all other access are read
2472 * only
2473 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002474 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2475 g_num_of_iommus++;
2476 continue;
2477 }
2478 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2479 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002480 }
2481
Weidong Hand9630fe2008-12-08 11:06:32 +08002482 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2483 GFP_KERNEL);
2484 if (!g_iommus) {
2485 printk(KERN_ERR "Allocating global iommu array failed\n");
2486 ret = -ENOMEM;
2487 goto error;
2488 }
2489
mark gross80b20dd2008-04-18 13:53:58 -07002490 deferred_flush = kzalloc(g_num_of_iommus *
2491 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2492 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002493 ret = -ENOMEM;
Jiang Liu989d51f2014-02-19 14:07:21 +08002494 goto free_g_iommus;
mark gross5e0d2a62008-03-04 15:22:08 -08002495 }
2496
Jiang Liu7c919772014-01-06 14:18:18 +08002497 for_each_active_iommu(iommu, drhd) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002498 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002499
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002500 ret = iommu_init_domains(iommu);
2501 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002502 goto free_iommu;
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002503
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002504 /*
2505 * TBD:
2506 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002507 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002508 */
2509 ret = iommu_alloc_root_entry(iommu);
2510 if (ret) {
2511 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002512 goto free_iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002513 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002514 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002515 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002516 }
2517
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002518 /*
2519 * Start from the sane iommu hardware state.
2520 */
Jiang Liu7c919772014-01-06 14:18:18 +08002521 for_each_active_iommu(iommu, drhd) {
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002522 /*
2523 * If the queued invalidation is already initialized by us
2524 * (for example, while enabling interrupt-remapping) then
2525 * we got the things already rolling from a sane state.
2526 */
2527 if (iommu->qi)
2528 continue;
2529
2530 /*
2531 * Clear any previous faults.
2532 */
2533 dmar_fault(-1, iommu);
2534 /*
2535 * Disable queued invalidation if supported and already enabled
2536 * before OS handover.
2537 */
2538 dmar_disable_qi(iommu);
2539 }
2540
Jiang Liu7c919772014-01-06 14:18:18 +08002541 for_each_active_iommu(iommu, drhd) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002542 if (dmar_enable_qi(iommu)) {
2543 /*
2544 * Queued Invalidate not enabled, use Register Based
2545 * Invalidate
2546 */
2547 iommu->flush.flush_context = __iommu_flush_context;
2548 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002549 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002550 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002551 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002552 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002553 } else {
2554 iommu->flush.flush_context = qi_flush_context;
2555 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002556 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002557 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002558 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002559 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002560 }
2561 }
2562
David Woodhouse19943b02009-08-04 16:19:20 +01002563 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002564 iommu_identity_mapping |= IDENTMAP_ALL;
2565
Suresh Siddhad3f13812011-08-23 17:05:25 -07002566#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002567 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002568#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002569
2570 check_tylersburg_isoch();
2571
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002572 /*
2573 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002574 * identity mappings for rmrr, gfx, and isa and may fall back to static
2575 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002576 */
David Woodhouse19943b02009-08-04 16:19:20 +01002577 if (iommu_identity_mapping) {
2578 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2579 if (ret) {
2580 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002581 goto free_iommu;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002582 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002583 }
David Woodhouse19943b02009-08-04 16:19:20 +01002584 /*
2585 * For each rmrr
2586 * for each dev attached to rmrr
2587 * do
2588 * locate drhd for dev, alloc domain for dev
2589 * allocate free domain
2590 * allocate page table entries for rmrr
2591 * if context not allocated for bus
2592 * allocate and init context
2593 * set present in root table for this bus
2594 * init context with domain, translation etc
2595 * endfor
2596 * endfor
2597 */
2598 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2599 for_each_rmrr_units(rmrr) {
Jiang Liub683b232014-02-19 14:07:32 +08002600 /* some BIOS lists non-exist devices in DMAR table. */
2601 for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
2602 i, pdev) {
David Woodhouse19943b02009-08-04 16:19:20 +01002603 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2604 if (ret)
2605 printk(KERN_ERR
2606 "IOMMU: mapping reserved region failed\n");
2607 }
2608 }
2609
2610 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002611
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002612 /*
2613 * for each drhd
2614 * enable fault log
2615 * global invalidate context cache
2616 * global invalidate iotlb
2617 * enable translation
2618 */
Jiang Liu7c919772014-01-06 14:18:18 +08002619 for_each_iommu(iommu, drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002620 if (drhd->ignored) {
2621 /*
2622 * we always have to disable PMRs or DMA may fail on
2623 * this device
2624 */
2625 if (force_on)
Jiang Liu7c919772014-01-06 14:18:18 +08002626 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002627 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002628 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002629
2630 iommu_flush_write_buffer(iommu);
2631
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002632 ret = dmar_set_interrupt(iommu);
2633 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002634 goto free_iommu;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002635
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002636 iommu_set_root_entry(iommu);
2637
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002638 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002639 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002640
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002641 ret = iommu_enable_translation(iommu);
2642 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002643 goto free_iommu;
David Woodhouseb94996c2009-09-19 15:28:12 -07002644
2645 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002646 }
2647
2648 return 0;
Jiang Liu989d51f2014-02-19 14:07:21 +08002649
2650free_iommu:
Jiang Liu7c919772014-01-06 14:18:18 +08002651 for_each_active_iommu(iommu, drhd)
Jiang Liua868e6b2014-01-06 14:18:20 +08002652 free_dmar_iommu(iommu);
Jiang Liu9bdc5312014-01-06 14:18:27 +08002653 kfree(deferred_flush);
Jiang Liu989d51f2014-02-19 14:07:21 +08002654free_g_iommus:
Weidong Hand9630fe2008-12-08 11:06:32 +08002655 kfree(g_iommus);
Jiang Liu989d51f2014-02-19 14:07:21 +08002656error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002657 return ret;
2658}
2659
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002660/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002661static struct iova *intel_alloc_iova(struct device *dev,
2662 struct dmar_domain *domain,
2663 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002664{
2665 struct pci_dev *pdev = to_pci_dev(dev);
2666 struct iova *iova = NULL;
2667
David Woodhouse875764d2009-06-28 21:20:51 +01002668 /* Restrict dma_mask to the width that the iommu can handle */
2669 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2670
2671 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002672 /*
2673 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002674 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002675 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002676 */
David Woodhouse875764d2009-06-28 21:20:51 +01002677 iova = alloc_iova(&domain->iovad, nrpages,
2678 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2679 if (iova)
2680 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002681 }
David Woodhouse875764d2009-06-28 21:20:51 +01002682 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2683 if (unlikely(!iova)) {
2684 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2685 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002686 return NULL;
2687 }
2688
2689 return iova;
2690}
2691
David Woodhouse147202a2009-07-07 19:43:20 +01002692static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002693{
2694 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002695 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002696
2697 domain = get_domain_for_dev(pdev,
2698 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2699 if (!domain) {
2700 printk(KERN_ERR
2701 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002702 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002703 }
2704
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002705 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002706 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002707 ret = domain_context_mapping(domain, pdev,
2708 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002709 if (ret) {
2710 printk(KERN_ERR
2711 "Domain context map for %s failed",
2712 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002713 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002714 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002715 }
2716
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002717 return domain;
2718}
2719
David Woodhouse147202a2009-07-07 19:43:20 +01002720static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2721{
2722 struct device_domain_info *info;
2723
2724 /* No lock here, assumes no domain exit in normal case */
2725 info = dev->dev.archdata.iommu;
2726 if (likely(info))
2727 return info->domain;
2728
2729 return __get_valid_domain_for_dev(dev);
2730}
2731
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002732static int iommu_dummy(struct pci_dev *pdev)
2733{
2734 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2735}
2736
2737/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002738static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002739{
David Woodhouse73676832009-07-04 14:08:36 +01002740 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002741 int found;
2742
Yijing Wangdbad0862013-12-05 19:43:42 +08002743 if (unlikely(!dev_is_pci(dev)))
David Woodhouse73676832009-07-04 14:08:36 +01002744 return 1;
2745
2746 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002747 if (iommu_dummy(pdev))
2748 return 1;
2749
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002750 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002751 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002752
2753 found = identity_mapping(pdev);
2754 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002755 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002756 return 1;
2757 else {
2758 /*
2759 * 32 bit DMA is removed from si_domain and fall back
2760 * to non-identity mapping.
2761 */
2762 domain_remove_one_dev_info(si_domain, pdev);
2763 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2764 pci_name(pdev));
2765 return 0;
2766 }
2767 } else {
2768 /*
2769 * In case of a detached 64 bit DMA device from vm, the device
2770 * is put into si_domain for identity mapping.
2771 */
David Woodhouse6941af22009-07-04 18:24:27 +01002772 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002773 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002774 ret = domain_add_dev_info(si_domain, pdev,
2775 hw_pass_through ?
2776 CONTEXT_TT_PASS_THROUGH :
2777 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002778 if (!ret) {
2779 printk(KERN_INFO "64bit %s uses identity mapping\n",
2780 pci_name(pdev));
2781 return 1;
2782 }
2783 }
2784 }
2785
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002786 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002787}
2788
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002789static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2790 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002791{
2792 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002793 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002794 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002795 struct iova *iova;
2796 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002797 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002798 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002799 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002800
2801 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002802
David Woodhouse73676832009-07-04 14:08:36 +01002803 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002804 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002805
2806 domain = get_valid_domain_for_dev(pdev);
2807 if (!domain)
2808 return 0;
2809
Weidong Han8c11e792008-12-08 15:29:22 +08002810 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002811 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002812
Mike Travisc681d0b2011-05-28 13:15:05 -05002813 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002814 if (!iova)
2815 goto error;
2816
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002817 /*
2818 * Check if DMAR supports zero-length reads on write only
2819 * mappings..
2820 */
2821 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002822 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002823 prot |= DMA_PTE_READ;
2824 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2825 prot |= DMA_PTE_WRITE;
2826 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002827 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002828 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002829 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002830 * is not a big problem
2831 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002832 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002833 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002834 if (ret)
2835 goto error;
2836
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002837 /* it's a non-present to present mapping. Only flush if caching mode */
2838 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002839 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002840 else
Weidong Han8c11e792008-12-08 15:29:22 +08002841 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002842
David Woodhouse03d6a242009-06-28 15:33:46 +01002843 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2844 start_paddr += paddr & ~PAGE_MASK;
2845 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002846
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002847error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002848 if (iova)
2849 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002850 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002851 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002852 return 0;
2853}
2854
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002855static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2856 unsigned long offset, size_t size,
2857 enum dma_data_direction dir,
2858 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002859{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002860 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2861 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002862}
2863
mark gross5e0d2a62008-03-04 15:22:08 -08002864static void flush_unmaps(void)
2865{
mark gross80b20dd2008-04-18 13:53:58 -07002866 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002867
mark gross5e0d2a62008-03-04 15:22:08 -08002868 timer_on = 0;
2869
2870 /* just flush them all */
2871 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002872 struct intel_iommu *iommu = g_iommus[i];
2873 if (!iommu)
2874 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002875
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002876 if (!deferred_flush[i].next)
2877 continue;
2878
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002879 /* In caching mode, global flushes turn emulation expensive */
2880 if (!cap_caching_mode(iommu->cap))
2881 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002882 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002883 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002884 unsigned long mask;
2885 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002886 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002887
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002888 /* On real hardware multiple invalidations are expensive */
2889 if (cap_caching_mode(iommu->cap))
2890 iommu_flush_iotlb_psi(iommu, domain->id,
2891 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2892 else {
2893 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2894 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2895 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2896 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002897 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002898 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002899 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002900 }
2901
mark gross5e0d2a62008-03-04 15:22:08 -08002902 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002903}
2904
2905static void flush_unmaps_timeout(unsigned long data)
2906{
mark gross80b20dd2008-04-18 13:53:58 -07002907 unsigned long flags;
2908
2909 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002910 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002911 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002912}
2913
2914static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2915{
2916 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002917 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002918 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002919
2920 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002921 if (list_size == HIGH_WATER_MARK)
2922 flush_unmaps();
2923
Weidong Han8c11e792008-12-08 15:29:22 +08002924 iommu = domain_get_iommu(dom);
2925 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002926
mark gross80b20dd2008-04-18 13:53:58 -07002927 next = deferred_flush[iommu_id].next;
2928 deferred_flush[iommu_id].domain[next] = dom;
2929 deferred_flush[iommu_id].iova[next] = iova;
2930 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002931
2932 if (!timer_on) {
2933 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2934 timer_on = 1;
2935 }
2936 list_size++;
2937 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2938}
2939
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002940static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2941 size_t size, enum dma_data_direction dir,
2942 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002943{
2944 struct pci_dev *pdev = to_pci_dev(dev);
2945 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002946 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002947 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002948 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002949
David Woodhouse73676832009-07-04 14:08:36 +01002950 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002951 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002952
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002953 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002954 BUG_ON(!domain);
2955
Weidong Han8c11e792008-12-08 15:29:22 +08002956 iommu = domain_get_iommu(domain);
2957
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002958 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002959 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2960 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002961 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002962
David Woodhoused794dc92009-06-28 00:27:49 +01002963 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2964 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002965
David Woodhoused794dc92009-06-28 00:27:49 +01002966 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2967 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002968
2969 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002970 dma_pte_clear_range(domain, start_pfn, last_pfn);
2971
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002972 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002973 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2974
mark gross5e0d2a62008-03-04 15:22:08 -08002975 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002976 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002977 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002978 /* free iova */
2979 __free_iova(&domain->iovad, iova);
2980 } else {
2981 add_unmap(domain, iova);
2982 /*
2983 * queue up the release of the unmap to save the 1/6th of the
2984 * cpu used up by the iotlb flush operation...
2985 */
mark gross5e0d2a62008-03-04 15:22:08 -08002986 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002987}
2988
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09002989static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02002990 dma_addr_t *dma_handle, gfp_t flags,
2991 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002992{
2993 void *vaddr;
2994 int order;
2995
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002996 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002997 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07002998
2999 if (!iommu_no_mapping(hwdev))
3000 flags &= ~(GFP_DMA | GFP_DMA32);
3001 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
3002 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
3003 flags |= GFP_DMA;
3004 else
3005 flags |= GFP_DMA32;
3006 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003007
3008 vaddr = (void *)__get_free_pages(flags, order);
3009 if (!vaddr)
3010 return NULL;
3011 memset(vaddr, 0, size);
3012
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003013 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
3014 DMA_BIDIRECTIONAL,
3015 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003016 if (*dma_handle)
3017 return vaddr;
3018 free_pages((unsigned long)vaddr, order);
3019 return NULL;
3020}
3021
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003022static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003023 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003024{
3025 int order;
3026
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003027 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003028 order = get_order(size);
3029
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003030 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003031 free_pages((unsigned long)vaddr, order);
3032}
3033
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003034static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3035 int nelems, enum dma_data_direction dir,
3036 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003037{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003038 struct pci_dev *pdev = to_pci_dev(hwdev);
3039 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003040 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003041 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003042 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003043
David Woodhouse73676832009-07-04 14:08:36 +01003044 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003045 return;
3046
3047 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003048 BUG_ON(!domain);
3049
3050 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003051
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003052 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003053 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3054 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003055 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003056
David Woodhoused794dc92009-06-28 00:27:49 +01003057 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3058 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003059
3060 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003061 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003062
David Woodhoused794dc92009-06-28 00:27:49 +01003063 /* free page tables */
3064 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3065
David Woodhouseacea0012009-07-14 01:55:11 +01003066 if (intel_iommu_strict) {
3067 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003068 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003069 /* free iova */
3070 __free_iova(&domain->iovad, iova);
3071 } else {
3072 add_unmap(domain, iova);
3073 /*
3074 * queue up the release of the unmap to save the 1/6th of the
3075 * cpu used up by the iotlb flush operation...
3076 */
3077 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003078}
3079
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003080static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003081 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003082{
3083 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003084 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003085
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003086 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003087 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003088 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003089 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003090 }
3091 return nelems;
3092}
3093
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003094static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3095 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003096{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003097 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003098 struct pci_dev *pdev = to_pci_dev(hwdev);
3099 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003100 size_t size = 0;
3101 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003102 struct iova *iova = NULL;
3103 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003104 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003105 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003106 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003107
3108 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003109 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003110 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003111
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003112 domain = get_valid_domain_for_dev(pdev);
3113 if (!domain)
3114 return 0;
3115
Weidong Han8c11e792008-12-08 15:29:22 +08003116 iommu = domain_get_iommu(domain);
3117
David Woodhouseb536d242009-06-28 14:49:31 +01003118 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003119 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003120
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003121 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3122 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003123 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003124 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003125 return 0;
3126 }
3127
3128 /*
3129 * Check if DMAR supports zero-length reads on write only
3130 * mappings..
3131 */
3132 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003133 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003134 prot |= DMA_PTE_READ;
3135 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3136 prot |= DMA_PTE_WRITE;
3137
David Woodhouseb536d242009-06-28 14:49:31 +01003138 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003139
Fenghua Yuf5329592009-08-04 15:09:37 -07003140 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003141 if (unlikely(ret)) {
3142 /* clear the page */
3143 dma_pte_clear_range(domain, start_vpfn,
3144 start_vpfn + size - 1);
3145 /* free page tables */
3146 dma_pte_free_pagetable(domain, start_vpfn,
3147 start_vpfn + size - 1);
3148 /* free iova */
3149 __free_iova(&domain->iovad, iova);
3150 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003151 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003152
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003153 /* it's a non-present to present mapping. Only flush if caching mode */
3154 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003155 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003156 else
Weidong Han8c11e792008-12-08 15:29:22 +08003157 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003158
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003159 return nelems;
3160}
3161
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003162static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3163{
3164 return !dma_addr;
3165}
3166
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003167struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003168 .alloc = intel_alloc_coherent,
3169 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003170 .map_sg = intel_map_sg,
3171 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003172 .map_page = intel_map_page,
3173 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003174 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003175};
3176
3177static inline int iommu_domain_cache_init(void)
3178{
3179 int ret = 0;
3180
3181 iommu_domain_cache = kmem_cache_create("iommu_domain",
3182 sizeof(struct dmar_domain),
3183 0,
3184 SLAB_HWCACHE_ALIGN,
3185
3186 NULL);
3187 if (!iommu_domain_cache) {
3188 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3189 ret = -ENOMEM;
3190 }
3191
3192 return ret;
3193}
3194
3195static inline int iommu_devinfo_cache_init(void)
3196{
3197 int ret = 0;
3198
3199 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3200 sizeof(struct device_domain_info),
3201 0,
3202 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003203 NULL);
3204 if (!iommu_devinfo_cache) {
3205 printk(KERN_ERR "Couldn't create devinfo cache\n");
3206 ret = -ENOMEM;
3207 }
3208
3209 return ret;
3210}
3211
3212static inline int iommu_iova_cache_init(void)
3213{
3214 int ret = 0;
3215
3216 iommu_iova_cache = kmem_cache_create("iommu_iova",
3217 sizeof(struct iova),
3218 0,
3219 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003220 NULL);
3221 if (!iommu_iova_cache) {
3222 printk(KERN_ERR "Couldn't create iova cache\n");
3223 ret = -ENOMEM;
3224 }
3225
3226 return ret;
3227}
3228
3229static int __init iommu_init_mempool(void)
3230{
3231 int ret;
3232 ret = iommu_iova_cache_init();
3233 if (ret)
3234 return ret;
3235
3236 ret = iommu_domain_cache_init();
3237 if (ret)
3238 goto domain_error;
3239
3240 ret = iommu_devinfo_cache_init();
3241 if (!ret)
3242 return ret;
3243
3244 kmem_cache_destroy(iommu_domain_cache);
3245domain_error:
3246 kmem_cache_destroy(iommu_iova_cache);
3247
3248 return -ENOMEM;
3249}
3250
3251static void __init iommu_exit_mempool(void)
3252{
3253 kmem_cache_destroy(iommu_devinfo_cache);
3254 kmem_cache_destroy(iommu_domain_cache);
3255 kmem_cache_destroy(iommu_iova_cache);
3256
3257}
3258
Dan Williams556ab452010-07-23 15:47:56 -07003259static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3260{
3261 struct dmar_drhd_unit *drhd;
3262 u32 vtbar;
3263 int rc;
3264
3265 /* We know that this device on this chipset has its own IOMMU.
3266 * If we find it under a different IOMMU, then the BIOS is lying
3267 * to us. Hope that the IOMMU for this device is actually
3268 * disabled, and it needs no translation...
3269 */
3270 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3271 if (rc) {
3272 /* "can't" happen */
3273 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3274 return;
3275 }
3276 vtbar &= 0xffff0000;
3277
3278 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3279 drhd = dmar_find_matched_drhd_unit(pdev);
3280 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3281 TAINT_FIRMWARE_WORKAROUND,
3282 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3283 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3284}
3285DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3286
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003287static void __init init_no_remapping_devices(void)
3288{
3289 struct dmar_drhd_unit *drhd;
Jiang Liub683b232014-02-19 14:07:32 +08003290 struct pci_dev *dev;
3291 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003292
3293 for_each_drhd_unit(drhd) {
3294 if (!drhd->include_all) {
Jiang Liub683b232014-02-19 14:07:32 +08003295 for_each_active_dev_scope(drhd->devices,
3296 drhd->devices_cnt, i, dev)
3297 break;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003298 /* 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) {
Jiang Liu7c919772014-01-06 14:18:18 +08003305 if (drhd->include_all)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003306 continue;
3307
Jiang Liub683b232014-02-19 14:07:32 +08003308 for_each_active_dev_scope(drhd->devices,
3309 drhd->devices_cnt, i, dev)
3310 if (!IS_GFX_DEVICE(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003311 break;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003312 if (i < drhd->devices_cnt)
3313 continue;
3314
David Woodhousec0771df2011-10-14 20:59:46 +01003315 /* This IOMMU has *only* gfx devices. Either bypass it or
3316 set the gfx_mapped flag, as appropriate */
3317 if (dmar_map_gfx) {
3318 intel_iommu_gfx_mapped = 1;
3319 } else {
3320 drhd->ignored = 1;
Jiang Liub683b232014-02-19 14:07:32 +08003321 for_each_active_dev_scope(drhd->devices,
3322 drhd->devices_cnt, i, dev)
3323 dev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003324 }
3325 }
3326}
3327
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003328#ifdef CONFIG_SUSPEND
3329static int init_iommu_hw(void)
3330{
3331 struct dmar_drhd_unit *drhd;
3332 struct intel_iommu *iommu = NULL;
3333
3334 for_each_active_iommu(iommu, drhd)
3335 if (iommu->qi)
3336 dmar_reenable_qi(iommu);
3337
Joseph Cihulab7792602011-05-03 00:08:37 -07003338 for_each_iommu(iommu, drhd) {
3339 if (drhd->ignored) {
3340 /*
3341 * we always have to disable PMRs or DMA may fail on
3342 * this device
3343 */
3344 if (force_on)
3345 iommu_disable_protect_mem_regions(iommu);
3346 continue;
3347 }
3348
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003349 iommu_flush_write_buffer(iommu);
3350
3351 iommu_set_root_entry(iommu);
3352
3353 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003354 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003355 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003356 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003357 if (iommu_enable_translation(iommu))
3358 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003359 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003360 }
3361
3362 return 0;
3363}
3364
3365static void iommu_flush_all(void)
3366{
3367 struct dmar_drhd_unit *drhd;
3368 struct intel_iommu *iommu;
3369
3370 for_each_active_iommu(iommu, drhd) {
3371 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003372 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003373 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003374 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003375 }
3376}
3377
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003378static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003379{
3380 struct dmar_drhd_unit *drhd;
3381 struct intel_iommu *iommu = NULL;
3382 unsigned long flag;
3383
3384 for_each_active_iommu(iommu, drhd) {
3385 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3386 GFP_ATOMIC);
3387 if (!iommu->iommu_state)
3388 goto nomem;
3389 }
3390
3391 iommu_flush_all();
3392
3393 for_each_active_iommu(iommu, drhd) {
3394 iommu_disable_translation(iommu);
3395
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003396 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003397
3398 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3399 readl(iommu->reg + DMAR_FECTL_REG);
3400 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3401 readl(iommu->reg + DMAR_FEDATA_REG);
3402 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3403 readl(iommu->reg + DMAR_FEADDR_REG);
3404 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3405 readl(iommu->reg + DMAR_FEUADDR_REG);
3406
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003407 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003408 }
3409 return 0;
3410
3411nomem:
3412 for_each_active_iommu(iommu, drhd)
3413 kfree(iommu->iommu_state);
3414
3415 return -ENOMEM;
3416}
3417
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003418static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003419{
3420 struct dmar_drhd_unit *drhd;
3421 struct intel_iommu *iommu = NULL;
3422 unsigned long flag;
3423
3424 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003425 if (force_on)
3426 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3427 else
3428 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003429 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003430 }
3431
3432 for_each_active_iommu(iommu, drhd) {
3433
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003434 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003435
3436 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3437 iommu->reg + DMAR_FECTL_REG);
3438 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3439 iommu->reg + DMAR_FEDATA_REG);
3440 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3441 iommu->reg + DMAR_FEADDR_REG);
3442 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3443 iommu->reg + DMAR_FEUADDR_REG);
3444
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003445 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003446 }
3447
3448 for_each_active_iommu(iommu, drhd)
3449 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003450}
3451
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003452static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003453 .resume = iommu_resume,
3454 .suspend = iommu_suspend,
3455};
3456
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003457static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003458{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003459 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003460}
3461
3462#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003463static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003464#endif /* CONFIG_PM */
3465
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003466static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3467{
3468 list_add(&rmrr->list, &dmar_rmrr_units);
3469}
3470
3471
3472int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3473{
3474 struct acpi_dmar_reserved_memory *rmrr;
3475 struct dmar_rmrr_unit *rmrru;
3476
3477 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3478 if (!rmrru)
3479 return -ENOMEM;
3480
3481 rmrru->hdr = header;
3482 rmrr = (struct acpi_dmar_reserved_memory *)header;
3483 rmrru->base_address = rmrr->base_address;
3484 rmrru->end_address = rmrr->end_address;
3485
3486 dmar_register_rmrr_unit(rmrru);
3487 return 0;
3488}
3489
3490static int __init
3491rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3492{
3493 struct acpi_dmar_reserved_memory *rmrr;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003494
3495 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003496 return dmar_parse_dev_scope((void *)(rmrr + 1),
3497 ((void *)rmrr) + rmrr->header.length,
3498 &rmrru->devices_cnt, &rmrru->devices,
3499 rmrr->segment);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003500}
3501
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003502int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3503{
3504 struct acpi_dmar_atsr *atsr;
3505 struct dmar_atsr_unit *atsru;
3506
3507 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3508 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3509 if (!atsru)
3510 return -ENOMEM;
3511
3512 atsru->hdr = hdr;
3513 atsru->include_all = atsr->flags & 0x1;
3514
3515 list_add(&atsru->list, &dmar_atsr_units);
3516
3517 return 0;
3518}
3519
3520static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3521{
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003522 struct acpi_dmar_atsr *atsr;
3523
3524 if (atsru->include_all)
3525 return 0;
3526
3527 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
Jiang Liu9bdc5312014-01-06 14:18:27 +08003528 return dmar_parse_dev_scope((void *)(atsr + 1),
3529 (void *)atsr + atsr->header.length,
3530 &atsru->devices_cnt, &atsru->devices,
3531 atsr->segment);
3532}
3533
3534static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
3535{
3536 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
3537 kfree(atsru);
3538}
3539
3540static void intel_iommu_free_dmars(void)
3541{
3542 struct dmar_rmrr_unit *rmrru, *rmrr_n;
3543 struct dmar_atsr_unit *atsru, *atsr_n;
3544
3545 list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
3546 list_del(&rmrru->list);
3547 dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
3548 kfree(rmrru);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003549 }
3550
Jiang Liu9bdc5312014-01-06 14:18:27 +08003551 list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
3552 list_del(&atsru->list);
3553 intel_iommu_free_atsr(atsru);
3554 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003555}
3556
3557int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3558{
Jiang Liub683b232014-02-19 14:07:32 +08003559 int i, ret = 1;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003560 struct pci_bus *bus;
Jiang Liub683b232014-02-19 14:07:32 +08003561 struct pci_dev *bridge = NULL, *tmp;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003562 struct acpi_dmar_atsr *atsr;
3563 struct dmar_atsr_unit *atsru;
3564
3565 dev = pci_physfn(dev);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003566 for (bus = dev->bus; bus; bus = bus->parent) {
Jiang Liub5f82dd2014-02-19 14:07:31 +08003567 bridge = bus->self;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003568 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003569 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003570 return 0;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003571 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003572 break;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003573 }
Jiang Liub5f82dd2014-02-19 14:07:31 +08003574 if (!bridge)
3575 return 0;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003576
Jiang Liub5f82dd2014-02-19 14:07:31 +08003577 list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
3578 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3579 if (atsr->segment != pci_domain_nr(dev->bus))
3580 continue;
3581
Jiang Liub683b232014-02-19 14:07:32 +08003582 for_each_dev_scope(atsru->devices, atsru->devices_cnt, i, tmp)
3583 if (tmp == bridge)
3584 goto out;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003585
3586 if (atsru->include_all)
Jiang Liub683b232014-02-19 14:07:32 +08003587 goto out;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003588 }
Jiang Liub683b232014-02-19 14:07:32 +08003589 ret = 0;
3590out:
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003591
Jiang Liub683b232014-02-19 14:07:32 +08003592 return ret;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003593}
3594
Sergey Senozhatskyc8f369a2011-10-26 18:45:39 +03003595int __init dmar_parse_rmrr_atsr_dev(void)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003596{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003597 struct dmar_rmrr_unit *rmrr;
3598 struct dmar_atsr_unit *atsr;
Jiang Liub683b232014-02-19 14:07:32 +08003599 int ret;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003600
Jiang Liu9bdc5312014-01-06 14:18:27 +08003601 list_for_each_entry(rmrr, &dmar_rmrr_units, list) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003602 ret = rmrr_parse_dev(rmrr);
3603 if (ret)
3604 return ret;
3605 }
3606
Jiang Liu9bdc5312014-01-06 14:18:27 +08003607 list_for_each_entry(atsr, &dmar_atsr_units, list) {
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003608 ret = atsr_parse_dev(atsr);
3609 if (ret)
3610 return ret;
3611 }
3612
Jiang Liub683b232014-02-19 14:07:32 +08003613 return 0;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003614}
3615
Fenghua Yu99dcade2009-11-11 07:23:06 -08003616/*
3617 * Here we only respond to action of unbound device from driver.
3618 *
3619 * Added device is not attached to its DMAR domain here yet. That will happen
3620 * when mapping the device to iova.
3621 */
3622static int device_notifier(struct notifier_block *nb,
3623 unsigned long action, void *data)
3624{
3625 struct device *dev = data;
3626 struct pci_dev *pdev = to_pci_dev(dev);
3627 struct dmar_domain *domain;
3628
Jiang Liu816997d2014-02-19 14:07:22 +08003629 if (iommu_dummy(pdev))
David Woodhouse44cd6132009-12-02 10:18:30 +00003630 return 0;
3631
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003632 if (action != BUS_NOTIFY_UNBOUND_DRIVER &&
3633 action != BUS_NOTIFY_DEL_DEVICE)
3634 return 0;
3635
Fenghua Yu99dcade2009-11-11 07:23:06 -08003636 domain = find_domain(pdev);
3637 if (!domain)
3638 return 0;
3639
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003640 domain_remove_one_dev_info(domain, pdev);
3641 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3642 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3643 list_empty(&domain->devices))
3644 domain_exit(domain);
Alex Williamsona97590e2011-03-04 14:52:16 -07003645
Fenghua Yu99dcade2009-11-11 07:23:06 -08003646 return 0;
3647}
3648
3649static struct notifier_block device_nb = {
3650 .notifier_call = device_notifier,
3651};
3652
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003653int __init intel_iommu_init(void)
3654{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003655 int ret = -ENODEV;
Takao Indoh3a93c842013-04-23 17:35:03 +09003656 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +08003657 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003658
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003659 /* VT-d is required for a TXT/tboot launch, so enforce that */
3660 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003661
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003662 if (dmar_table_init()) {
3663 if (force_on)
3664 panic("tboot: Failed to initialize DMAR table\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003665 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003666 }
3667
Takao Indoh3a93c842013-04-23 17:35:03 +09003668 /*
3669 * Disable translation if already enabled prior to OS handover.
3670 */
Jiang Liu7c919772014-01-06 14:18:18 +08003671 for_each_active_iommu(iommu, drhd)
Takao Indoh3a93c842013-04-23 17:35:03 +09003672 if (iommu->gcmd & DMA_GCMD_TE)
3673 iommu_disable_translation(iommu);
Takao Indoh3a93c842013-04-23 17:35:03 +09003674
Suresh Siddhac2c72862011-08-23 17:05:19 -07003675 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003676 if (force_on)
3677 panic("tboot: Failed to initialize DMAR device scope\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003678 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003679 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003680
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003681 if (no_iommu || dmar_disabled)
Jiang Liu9bdc5312014-01-06 14:18:27 +08003682 goto out_free_dmar;
Suresh Siddha2ae21012008-07-10 11:16:43 -07003683
Joseph Cihula51a63e62011-03-21 11:04:24 -07003684 if (iommu_init_mempool()) {
3685 if (force_on)
3686 panic("tboot: Failed to initialize iommu memory\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003687 goto out_free_dmar;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003688 }
3689
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003690 if (list_empty(&dmar_rmrr_units))
3691 printk(KERN_INFO "DMAR: No RMRR found\n");
3692
3693 if (list_empty(&dmar_atsr_units))
3694 printk(KERN_INFO "DMAR: No ATSR found\n");
3695
Joseph Cihula51a63e62011-03-21 11:04:24 -07003696 if (dmar_init_reserved_ranges()) {
3697 if (force_on)
3698 panic("tboot: Failed to reserve iommu ranges\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003699 goto out_free_mempool;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003700 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003701
3702 init_no_remapping_devices();
3703
Joseph Cihulab7792602011-05-03 00:08:37 -07003704 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003705 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003706 if (force_on)
3707 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003708 printk(KERN_ERR "IOMMU: dmar init failed\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003709 goto out_free_reserved_range;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003710 }
3711 printk(KERN_INFO
3712 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3713
mark gross5e0d2a62008-03-04 15:22:08 -08003714 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003715#ifdef CONFIG_SWIOTLB
3716 swiotlb = 0;
3717#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003718 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003719
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003720 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003721
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003722 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003723
Fenghua Yu99dcade2009-11-11 07:23:06 -08003724 bus_register_notifier(&pci_bus_type, &device_nb);
3725
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003726 intel_iommu_enabled = 1;
3727
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003728 return 0;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003729
3730out_free_reserved_range:
3731 put_iova_domain(&reserved_iova_list);
3732out_free_mempool:
3733 iommu_exit_mempool();
3734out_free_dmar:
3735 intel_iommu_free_dmars();
3736 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003737}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003738
Han, Weidong3199aa62009-02-26 17:31:12 +08003739static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3740 struct pci_dev *pdev)
3741{
3742 struct pci_dev *tmp, *parent;
3743
3744 if (!iommu || !pdev)
3745 return;
3746
3747 /* dependent device detach */
3748 tmp = pci_find_upstream_pcie_bridge(pdev);
3749 /* Secondary interface's bus number and devfn 0 */
3750 if (tmp) {
3751 parent = pdev->bus->self;
3752 while (parent != tmp) {
3753 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01003754 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003755 parent = parent->bus->self;
3756 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003757 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003758 iommu_detach_dev(iommu,
3759 tmp->subordinate->number, 0);
3760 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01003761 iommu_detach_dev(iommu, tmp->bus->number,
3762 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003763 }
3764}
3765
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003766static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003767 struct pci_dev *pdev)
3768{
Yijing Wangbca2b912013-10-31 17:26:04 +08003769 struct device_domain_info *info, *tmp;
Weidong Hanc7151a82008-12-08 22:51:37 +08003770 struct intel_iommu *iommu;
3771 unsigned long flags;
3772 int found = 0;
Weidong Hanc7151a82008-12-08 22:51:37 +08003773
David Woodhouse276dbf992009-04-04 01:45:37 +01003774 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3775 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003776 if (!iommu)
3777 return;
3778
3779 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wangbca2b912013-10-31 17:26:04 +08003780 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
Mike Habeck8519dc42011-05-28 13:15:07 -05003781 if (info->segment == pci_domain_nr(pdev->bus) &&
3782 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003783 info->devfn == pdev->devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01003784 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003785 spin_unlock_irqrestore(&device_domain_lock, flags);
3786
Yu Zhao93a23a72009-05-18 13:51:37 +08003787 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003788 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003789 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003790 free_devinfo_mem(info);
3791
3792 spin_lock_irqsave(&device_domain_lock, flags);
3793
3794 if (found)
3795 break;
3796 else
3797 continue;
3798 }
3799
3800 /* if there is no other devices under the same iommu
3801 * owned by this domain, clear this iommu in iommu_bmp
3802 * update iommu count and coherency
3803 */
David Woodhouse276dbf992009-04-04 01:45:37 +01003804 if (iommu == device_to_iommu(info->segment, info->bus,
3805 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003806 found = 1;
3807 }
3808
Roland Dreier3e7abe22011-07-20 06:22:21 -07003809 spin_unlock_irqrestore(&device_domain_lock, flags);
3810
Weidong Hanc7151a82008-12-08 22:51:37 +08003811 if (found == 0) {
3812 unsigned long tmp_flags;
3813 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003814 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003815 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003816 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003817 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003818
Alex Williamson9b4554b2011-05-24 12:19:04 -04003819 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3820 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3821 spin_lock_irqsave(&iommu->lock, tmp_flags);
3822 clear_bit(domain->id, iommu->domain_ids);
3823 iommu->domains[domain->id] = NULL;
3824 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3825 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003826 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003827}
3828
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003829static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003830{
3831 int adjust_width;
3832
3833 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003834 domain_reserve_special_ranges(domain);
3835
3836 /* calculate AGAW */
3837 domain->gaw = guest_width;
3838 adjust_width = guestwidth_to_adjustwidth(guest_width);
3839 domain->agaw = width_to_agaw(adjust_width);
3840
Weidong Han5e98c4b2008-12-08 23:03:27 +08003841 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003842 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003843 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003844 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003845 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003846
3847 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003848 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003849 if (!domain->pgd)
3850 return -ENOMEM;
3851 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3852 return 0;
3853}
3854
Joerg Roedel5d450802008-12-03 14:52:32 +01003855static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003856{
Joerg Roedel5d450802008-12-03 14:52:32 +01003857 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003858
Jiang Liu92d03cc2014-02-19 14:07:28 +08003859 dmar_domain = alloc_domain(true);
Joerg Roedel5d450802008-12-03 14:52:32 +01003860 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003861 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003862 "intel_iommu_domain_init: dmar_domain == NULL\n");
3863 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003864 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003865 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003866 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003867 "intel_iommu_domain_init() failed\n");
Jiang Liu92d03cc2014-02-19 14:07:28 +08003868 domain_exit(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003869 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003870 }
Allen Kay8140a952011-10-14 12:32:17 -07003871 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003872 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003873
Joerg Roedel8a0e7152012-01-26 19:40:54 +01003874 domain->geometry.aperture_start = 0;
3875 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
3876 domain->geometry.force_aperture = true;
3877
Joerg Roedel5d450802008-12-03 14:52:32 +01003878 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003879}
Kay, Allen M38717942008-09-09 18:37:29 +03003880
Joerg Roedel5d450802008-12-03 14:52:32 +01003881static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003882{
Joerg Roedel5d450802008-12-03 14:52:32 +01003883 struct dmar_domain *dmar_domain = domain->priv;
3884
3885 domain->priv = NULL;
Jiang Liu92d03cc2014-02-19 14:07:28 +08003886 domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003887}
Kay, Allen M38717942008-09-09 18:37:29 +03003888
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003889static int intel_iommu_attach_device(struct iommu_domain *domain,
3890 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003891{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003892 struct dmar_domain *dmar_domain = domain->priv;
3893 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003894 struct intel_iommu *iommu;
3895 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03003896
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003897 /* normally pdev is not mapped */
3898 if (unlikely(domain_context_mapped(pdev))) {
3899 struct dmar_domain *old_domain;
3900
3901 old_domain = find_domain(pdev);
3902 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003903 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
3904 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
3905 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003906 else
3907 domain_remove_dev_info(old_domain);
3908 }
3909 }
3910
David Woodhouse276dbf992009-04-04 01:45:37 +01003911 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3912 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003913 if (!iommu)
3914 return -ENODEV;
3915
3916 /* check if this iommu agaw is sufficient for max mapped address */
3917 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01003918 if (addr_width > cap_mgaw(iommu->cap))
3919 addr_width = cap_mgaw(iommu->cap);
3920
3921 if (dmar_domain->max_addr > (1LL << addr_width)) {
3922 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003923 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01003924 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003925 return -EFAULT;
3926 }
Tom Lyona99c47a2010-05-17 08:20:45 +01003927 dmar_domain->gaw = addr_width;
3928
3929 /*
3930 * Knock out extra levels of page tables if necessary
3931 */
3932 while (iommu->agaw < dmar_domain->agaw) {
3933 struct dma_pte *pte;
3934
3935 pte = dmar_domain->pgd;
3936 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08003937 dmar_domain->pgd = (struct dma_pte *)
3938 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01003939 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01003940 }
3941 dmar_domain->agaw--;
3942 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003943
David Woodhouse5fe60f42009-08-09 10:53:41 +01003944 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003945}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003946
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003947static void intel_iommu_detach_device(struct iommu_domain *domain,
3948 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003949{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003950 struct dmar_domain *dmar_domain = domain->priv;
3951 struct pci_dev *pdev = to_pci_dev(dev);
3952
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003953 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03003954}
Kay, Allen M38717942008-09-09 18:37:29 +03003955
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01003956static int intel_iommu_map(struct iommu_domain *domain,
3957 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02003958 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03003959{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003960 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003961 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003962 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003963 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003964
Joerg Roedeldde57a22008-12-03 15:04:09 +01003965 if (iommu_prot & IOMMU_READ)
3966 prot |= DMA_PTE_READ;
3967 if (iommu_prot & IOMMU_WRITE)
3968 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08003969 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
3970 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003971
David Woodhouse163cc522009-06-28 00:51:17 +01003972 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01003973 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003974 u64 end;
3975
3976 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01003977 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003978 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01003979 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003980 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01003981 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003982 return -EFAULT;
3983 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01003984 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003985 }
David Woodhousead051222009-06-28 14:22:28 +01003986 /* Round up size to next multiple of PAGE_SIZE, if it and
3987 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01003988 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01003989 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
3990 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003991 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03003992}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003993
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02003994static size_t intel_iommu_unmap(struct iommu_domain *domain,
3995 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003996{
Joerg Roedeldde57a22008-12-03 15:04:09 +01003997 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07003998 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01003999
Allen Kay292827c2011-10-14 12:31:54 -07004000 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004001 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004002
David Woodhouse163cc522009-06-28 00:51:17 +01004003 if (dmar_domain->max_addr == iova + size)
4004 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004005
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004006 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004007}
Kay, Allen M38717942008-09-09 18:37:29 +03004008
Joerg Roedeld14d6572008-12-03 15:06:57 +01004009static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
Varun Sethibb5547a2013-03-29 01:23:58 +05304010 dma_addr_t iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004011{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004012 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004013 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004014 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004015
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004016 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004017 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004018 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004019
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004020 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004021}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004022
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004023static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4024 unsigned long cap)
4025{
4026 struct dmar_domain *dmar_domain = domain->priv;
4027
4028 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4029 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004030 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004031 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004032
4033 return 0;
4034}
4035
Alex Williamson783f1572012-05-30 14:19:43 -06004036#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4037
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004038static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004039{
4040 struct pci_dev *pdev = to_pci_dev(dev);
Alex Williamson3da4af02012-11-13 10:22:03 -07004041 struct pci_dev *bridge, *dma_pdev = NULL;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004042 struct iommu_group *group;
4043 int ret;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004044
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004045 if (!device_to_iommu(pci_domain_nr(pdev->bus),
4046 pdev->bus->number, pdev->devfn))
Alex Williamson70ae6f02011-10-21 15:56:11 -04004047 return -ENODEV;
4048
4049 bridge = pci_find_upstream_pcie_bridge(pdev);
4050 if (bridge) {
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004051 if (pci_is_pcie(bridge))
4052 dma_pdev = pci_get_domain_bus_and_slot(
4053 pci_domain_nr(pdev->bus),
4054 bridge->subordinate->number, 0);
Alex Williamson3da4af02012-11-13 10:22:03 -07004055 if (!dma_pdev)
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004056 dma_pdev = pci_dev_get(bridge);
4057 } else
4058 dma_pdev = pci_dev_get(pdev);
4059
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004060 /* Account for quirked devices */
Alex Williamson783f1572012-05-30 14:19:43 -06004061 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4062
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004063 /*
4064 * If it's a multifunction device that does not support our
Alex Williamsonc14d2692013-05-30 12:39:18 -06004065 * required ACS flags, add to the same group as lowest numbered
4066 * function that also does not suport the required ACS flags.
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004067 */
Alex Williamson783f1572012-05-30 14:19:43 -06004068 if (dma_pdev->multifunction &&
Alex Williamsonc14d2692013-05-30 12:39:18 -06004069 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
4070 u8 i, slot = PCI_SLOT(dma_pdev->devfn);
4071
4072 for (i = 0; i < 8; i++) {
4073 struct pci_dev *tmp;
4074
4075 tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
4076 if (!tmp)
4077 continue;
4078
4079 if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
4080 swap_pci_ref(&dma_pdev, tmp);
4081 break;
4082 }
4083 pci_dev_put(tmp);
4084 }
4085 }
Alex Williamson783f1572012-05-30 14:19:43 -06004086
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004087 /*
4088 * Devices on the root bus go through the iommu. If that's not us,
4089 * find the next upstream device and test ACS up to the root bus.
4090 * Finding the next device may require skipping virtual buses.
4091 */
Alex Williamson783f1572012-05-30 14:19:43 -06004092 while (!pci_is_root_bus(dma_pdev->bus)) {
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004093 struct pci_bus *bus = dma_pdev->bus;
4094
4095 while (!bus->self) {
4096 if (!pci_is_root_bus(bus))
4097 bus = bus->parent;
4098 else
4099 goto root_bus;
4100 }
4101
4102 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
Alex Williamson783f1572012-05-30 14:19:43 -06004103 break;
4104
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004105 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
Alex Williamson70ae6f02011-10-21 15:56:11 -04004106 }
4107
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004108root_bus:
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004109 group = iommu_group_get(&dma_pdev->dev);
4110 pci_dev_put(dma_pdev);
4111 if (!group) {
4112 group = iommu_group_alloc();
4113 if (IS_ERR(group))
4114 return PTR_ERR(group);
4115 }
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004116
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004117 ret = iommu_group_add_device(group, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004118
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004119 iommu_group_put(group);
4120 return ret;
4121}
4122
4123static void intel_iommu_remove_device(struct device *dev)
4124{
4125 iommu_group_remove_device(dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004126}
4127
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004128static struct iommu_ops intel_iommu_ops = {
4129 .domain_init = intel_iommu_domain_init,
4130 .domain_destroy = intel_iommu_domain_destroy,
4131 .attach_dev = intel_iommu_attach_device,
4132 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004133 .map = intel_iommu_map,
4134 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004135 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004136 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004137 .add_device = intel_iommu_add_device,
4138 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004139 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004140};
David Woodhouse9af88142009-02-13 23:18:03 +00004141
Daniel Vetter94526182013-01-20 23:50:13 +01004142static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4143{
4144 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4145 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4146 dmar_map_gfx = 0;
4147}
4148
4149DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4150DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4151DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4152DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4153DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4154DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4155DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4156
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004157static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004158{
4159 /*
4160 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004161 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004162 */
4163 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4164 rwbf_quirk = 1;
4165}
4166
4167DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004168DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4169DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4170DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4171DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4172DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4173DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004174
Adam Jacksoneecfd572010-08-25 21:17:34 +01004175#define GGC 0x52
4176#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4177#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4178#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4179#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4180#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4181#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4182#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4183#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4184
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004185static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004186{
4187 unsigned short ggc;
4188
Adam Jacksoneecfd572010-08-25 21:17:34 +01004189 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004190 return;
4191
Adam Jacksoneecfd572010-08-25 21:17:34 +01004192 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004193 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4194 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004195 } else if (dmar_map_gfx) {
4196 /* we have to ensure the gfx device is idle before we flush */
4197 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4198 intel_iommu_strict = 1;
4199 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004200}
4201DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4202DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4203DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4204DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4205
David Woodhousee0fc7e02009-09-30 09:12:17 -07004206/* On Tylersburg chipsets, some BIOSes have been known to enable the
4207 ISOCH DMAR unit for the Azalia sound device, but not give it any
4208 TLB entries, which causes it to deadlock. Check for that. We do
4209 this in a function called from init_dmars(), instead of in a PCI
4210 quirk, because we don't want to print the obnoxious "BIOS broken"
4211 message if VT-d is actually disabled.
4212*/
4213static void __init check_tylersburg_isoch(void)
4214{
4215 struct pci_dev *pdev;
4216 uint32_t vtisochctrl;
4217
4218 /* If there's no Azalia in the system anyway, forget it. */
4219 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4220 if (!pdev)
4221 return;
4222 pci_dev_put(pdev);
4223
4224 /* System Management Registers. Might be hidden, in which case
4225 we can't do the sanity check. But that's OK, because the
4226 known-broken BIOSes _don't_ actually hide it, so far. */
4227 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4228 if (!pdev)
4229 return;
4230
4231 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4232 pci_dev_put(pdev);
4233 return;
4234 }
4235
4236 pci_dev_put(pdev);
4237
4238 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4239 if (vtisochctrl & 1)
4240 return;
4241
4242 /* Drop all bits other than the number of TLB entries */
4243 vtisochctrl &= 0x1c;
4244
4245 /* If we have the recommended number of TLB entries (16), fine. */
4246 if (vtisochctrl == 0x10)
4247 return;
4248
4249 /* Zero TLB entries? You get to ride the short bus to school. */
4250 if (!vtisochctrl) {
4251 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4252 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4253 dmi_get_system_info(DMI_BIOS_VENDOR),
4254 dmi_get_system_info(DMI_BIOS_VERSION),
4255 dmi_get_system_info(DMI_PRODUCT_VERSION));
4256 iommu_identity_mapping |= IDENTMAP_AZALIA;
4257 return;
4258 }
4259
4260 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4261 vtisochctrl);
4262}