blob: 484d669d27207572943fa48c02fc3f42e26749fe [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>
Jiang Liu75f05562014-02-19 14:07:37 +080036#include <linux/memory.h>
mark gross5e0d2a62008-03-04 15:22:08 -080037#include <linux/timer.h>
Kay, Allen M38717942008-09-09 18:37:29 +030038#include <linux/iova.h>
Joerg Roedel5d450802008-12-03 14:52:32 +010039#include <linux/iommu.h>
Kay, Allen M38717942008-09-09 18:37:29 +030040#include <linux/intel-iommu.h>
Rafael J. Wysocki134fac32011-03-23 22:16:14 +010041#include <linux/syscore_ops.h>
Shane Wang69575d32009-09-01 18:25:07 -070042#include <linux/tboot.h>
Stephen Rothwelladb2fe02009-08-31 15:24:23 +100043#include <linux/dmi.h>
Joerg Roedel5cdede22011-04-04 15:55:18 +020044#include <linux/pci-ats.h>
Tejun Heo0ee332c2011-12-08 10:22:09 -080045#include <linux/memblock.h>
Suresh Siddha8a8f4222012-03-30 11:47:08 -070046#include <asm/irq_remapping.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070047#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090048#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070049
Joerg Roedel078e1ee2012-09-26 12:44:43 +020050#include "irq_remapping.h"
Varun Sethi61e015a2013-04-23 10:05:24 +053051#include "pci.h"
Joerg Roedel078e1ee2012-09-26 12:44:43 +020052
Fenghua Yu5b6985c2008-10-16 18:02:32 -070053#define ROOT_SIZE VTD_PAGE_SIZE
54#define CONTEXT_SIZE VTD_PAGE_SIZE
55
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070056#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
57#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070058#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070059
60#define IOAPIC_RANGE_START (0xfee00000)
61#define IOAPIC_RANGE_END (0xfeefffff)
62#define IOVA_START_ADDR (0x1000)
63
64#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
65
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070066#define MAX_AGAW_WIDTH 64
Jiang Liu5c645b32014-01-06 14:18:12 +080067#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070068
David Woodhouse2ebe3152009-09-19 07:34:04 -070069#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
70#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
71
72/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
73 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
74#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
75 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
76#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070077
Mark McLoughlinf27be032008-11-20 15:49:43 +000078#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070079#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070080#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080081
Andrew Mortondf08cdc2010-09-22 13:05:11 -070082/* page table handling */
83#define LEVEL_STRIDE (9)
84#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
85
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +020086/*
87 * This bitmap is used to advertise the page sizes our hardware support
88 * to the IOMMU core, which will then use this information to split
89 * physically contiguous memory regions it is mapping into page sizes
90 * that we support.
91 *
92 * Traditionally the IOMMU core just handed us the mappings directly,
93 * after making sure the size is an order of a 4KiB page and that the
94 * mapping has natural alignment.
95 *
96 * To retain this behavior, we currently advertise that we support
97 * all page sizes that are an order of 4KiB.
98 *
99 * If at some point we'd like to utilize the IOMMU core's new behavior,
100 * we could change this to advertise the real page sizes we support.
101 */
102#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
103
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700104static inline int agaw_to_level(int agaw)
105{
106 return agaw + 2;
107}
108
109static inline int agaw_to_width(int agaw)
110{
Jiang Liu5c645b32014-01-06 14:18:12 +0800111 return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700112}
113
114static inline int width_to_agaw(int width)
115{
Jiang Liu5c645b32014-01-06 14:18:12 +0800116 return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700117}
118
119static inline unsigned int level_to_offset_bits(int level)
120{
121 return (level - 1) * LEVEL_STRIDE;
122}
123
124static inline int pfn_level_offset(unsigned long pfn, int level)
125{
126 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
127}
128
129static inline unsigned long level_mask(int level)
130{
131 return -1UL << level_to_offset_bits(level);
132}
133
134static inline unsigned long level_size(int level)
135{
136 return 1UL << level_to_offset_bits(level);
137}
138
139static inline unsigned long align_to_level(unsigned long pfn, int level)
140{
141 return (pfn + level_size(level) - 1) & level_mask(level);
142}
David Woodhousefd18de52009-05-10 23:57:41 +0100143
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100144static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
145{
Jiang Liu5c645b32014-01-06 14:18:12 +0800146 return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100147}
148
David Woodhousedd4e8312009-06-27 16:21:20 +0100149/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
150 are never going to work. */
151static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
152{
153 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
154}
155
156static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
157{
158 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
159}
160static inline unsigned long page_to_dma_pfn(struct page *pg)
161{
162 return mm_to_dma_pfn(page_to_pfn(pg));
163}
164static inline unsigned long virt_to_dma_pfn(void *p)
165{
166 return page_to_dma_pfn(virt_to_page(p));
167}
168
Weidong Hand9630fe2008-12-08 11:06:32 +0800169/* global iommu list, set NULL for ignored DMAR units */
170static struct intel_iommu **g_iommus;
171
David Woodhousee0fc7e02009-09-30 09:12:17 -0700172static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000173static int rwbf_quirk;
174
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000175/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700176 * set to 1 to panic kernel if can't successfully enable VT-d
177 * (used when kernel is launched w/ TXT)
178 */
179static int force_on = 0;
180
181/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000182 * 0: Present
183 * 1-11: Reserved
184 * 12-63: Context Ptr (12 - (haw-1))
185 * 64-127: Reserved
186 */
187struct root_entry {
188 u64 val;
189 u64 rsvd1;
190};
191#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
192static inline bool root_present(struct root_entry *root)
193{
194 return (root->val & 1);
195}
196static inline void set_root_present(struct root_entry *root)
197{
198 root->val |= 1;
199}
200static inline void set_root_value(struct root_entry *root, unsigned long value)
201{
202 root->val |= value & VTD_PAGE_MASK;
203}
204
205static inline struct context_entry *
206get_context_addr_from_root(struct root_entry *root)
207{
208 return (struct context_entry *)
209 (root_present(root)?phys_to_virt(
210 root->val & VTD_PAGE_MASK) :
211 NULL);
212}
213
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000214/*
215 * low 64 bits:
216 * 0: present
217 * 1: fault processing disable
218 * 2-3: translation type
219 * 12-63: address space root
220 * high 64 bits:
221 * 0-2: address width
222 * 3-6: aval
223 * 8-23: domain id
224 */
225struct context_entry {
226 u64 lo;
227 u64 hi;
228};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000229
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000230static inline bool context_present(struct context_entry *context)
231{
232 return (context->lo & 1);
233}
234static inline void context_set_present(struct context_entry *context)
235{
236 context->lo |= 1;
237}
238
239static inline void context_set_fault_enable(struct context_entry *context)
240{
241 context->lo &= (((u64)-1) << 2) | 1;
242}
243
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000244static inline void context_set_translation_type(struct context_entry *context,
245 unsigned long value)
246{
247 context->lo &= (((u64)-1) << 4) | 3;
248 context->lo |= (value & 3) << 2;
249}
250
251static inline void context_set_address_root(struct context_entry *context,
252 unsigned long value)
253{
254 context->lo |= value & VTD_PAGE_MASK;
255}
256
257static inline void context_set_address_width(struct context_entry *context,
258 unsigned long value)
259{
260 context->hi |= value & 7;
261}
262
263static inline void context_set_domain_id(struct context_entry *context,
264 unsigned long value)
265{
266 context->hi |= (value & ((1 << 16) - 1)) << 8;
267}
268
269static inline void context_clear_entry(struct context_entry *context)
270{
271 context->lo = 0;
272 context->hi = 0;
273}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000274
Mark McLoughlin622ba122008-11-20 15:49:46 +0000275/*
276 * 0: readable
277 * 1: writable
278 * 2-6: reserved
279 * 7: super page
Sheng Yang9cf066972009-03-18 15:33:07 +0800280 * 8-10: available
281 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000282 * 12-63: Host physcial address
283 */
284struct dma_pte {
285 u64 val;
286};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000287
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000288static inline void dma_clear_pte(struct dma_pte *pte)
289{
290 pte->val = 0;
291}
292
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000293static inline u64 dma_pte_addr(struct dma_pte *pte)
294{
David Woodhousec85994e2009-07-01 19:21:24 +0100295#ifdef CONFIG_64BIT
296 return pte->val & VTD_PAGE_MASK;
297#else
298 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100299 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100300#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000301}
302
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000303static inline bool dma_pte_present(struct dma_pte *pte)
304{
305 return (pte->val & 3) != 0;
306}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000307
Allen Kay4399c8b2011-10-14 12:32:46 -0700308static inline bool dma_pte_superpage(struct dma_pte *pte)
309{
310 return (pte->val & (1 << 7));
311}
312
David Woodhouse75e6bf92009-07-02 11:21:16 +0100313static inline int first_pte_in_page(struct dma_pte *pte)
314{
315 return !((unsigned long)pte & ~VTD_PAGE_MASK);
316}
317
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700318/*
319 * This domain is a statically identity mapping domain.
320 * 1. This domain creats a static 1:1 mapping to all usable memory.
321 * 2. It maps to each iommu if successful.
322 * 3. Each iommu mapps to this domain if successful.
323 */
David Woodhouse19943b02009-08-04 16:19:20 +0100324static struct dmar_domain *si_domain;
325static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700326
Weidong Han3b5410e2008-12-08 09:17:15 +0800327/* devices under the same p2p bridge are owned in one domain */
Mike Daycdc7b832008-12-12 17:16:30 +0100328#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
Weidong Han3b5410e2008-12-08 09:17:15 +0800329
Weidong Han1ce28fe2008-12-08 16:35:39 +0800330/* domain represents a virtual machine, more than one devices
331 * across iommus may be owned in one domain, e.g. kvm guest.
332 */
333#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1)
334
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700335/* si_domain contains mulitple devices */
336#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2)
337
Mike Travis1b198bb2012-03-05 15:05:16 -0800338/* define the limit of IOMMUs supported in each domain */
339#ifdef CONFIG_X86
340# define IOMMU_UNITS_SUPPORTED MAX_IO_APICS
341#else
342# define IOMMU_UNITS_SUPPORTED 64
343#endif
344
Mark McLoughlin99126f72008-11-20 15:49:47 +0000345struct dmar_domain {
346 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700347 int nid; /* node id */
Mike Travis1b198bb2012-03-05 15:05:16 -0800348 DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
349 /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000350
351 struct list_head devices; /* all devices' list */
352 struct iova_domain iovad; /* iova's that belong to this domain */
353
354 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000355 int gaw; /* max guest address width */
356
357 /* adjusted guest address width, 0 is level 2 30-bit */
358 int agaw;
359
Weidong Han3b5410e2008-12-08 09:17:15 +0800360 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800361
362 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800363 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800364 int iommu_count; /* reference count of iommu */
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100365 int iommu_superpage;/* Level of superpages supported:
366 0 == 4KiB (no superpages), 1 == 2MiB,
367 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
Weidong Hanc7151a82008-12-08 22:51:37 +0800368 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800369 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000370};
371
Mark McLoughlina647dac2008-11-20 15:49:48 +0000372/* PCI domain-device relationship */
373struct device_domain_info {
374 struct list_head link; /* link to domain siblings */
375 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100376 int segment; /* PCI domain */
377 u8 bus; /* PCI bus number */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000378 u8 devfn; /* PCI devfn number */
Stefan Assmann45e829e2009-12-03 06:49:24 -0500379 struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800380 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dac2008-11-20 15:49:48 +0000381 struct dmar_domain *domain; /* pointer to domain */
382};
383
Jiang Liub94e4112014-02-19 14:07:25 +0800384struct dmar_rmrr_unit {
385 struct list_head list; /* list of rmrr units */
386 struct acpi_dmar_header *hdr; /* ACPI header */
387 u64 base_address; /* reserved base address*/
388 u64 end_address; /* reserved end address */
Jiang Liu0e242612014-02-19 14:07:34 +0800389 struct pci_dev __rcu **devices; /* target devices */
Jiang Liub94e4112014-02-19 14:07:25 +0800390 int devices_cnt; /* target device count */
391};
392
393struct dmar_atsr_unit {
394 struct list_head list; /* list of ATSR units */
395 struct acpi_dmar_header *hdr; /* ACPI header */
Jiang Liu0e242612014-02-19 14:07:34 +0800396 struct pci_dev __rcu **devices; /* target devices */
Jiang Liub94e4112014-02-19 14:07:25 +0800397 int devices_cnt; /* target device count */
398 u8 include_all:1; /* include all ports */
399};
400
401static LIST_HEAD(dmar_atsr_units);
402static LIST_HEAD(dmar_rmrr_units);
403
404#define for_each_rmrr_units(rmrr) \
405 list_for_each_entry(rmrr, &dmar_rmrr_units, list)
406
mark gross5e0d2a62008-03-04 15:22:08 -0800407static void flush_unmaps_timeout(unsigned long data);
408
Jiang Liub707cb02014-01-06 14:18:26 +0800409static DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
mark gross5e0d2a62008-03-04 15:22:08 -0800410
mark gross80b20dd2008-04-18 13:53:58 -0700411#define HIGH_WATER_MARK 250
412struct deferred_flush_tables {
413 int next;
414 struct iova *iova[HIGH_WATER_MARK];
415 struct dmar_domain *domain[HIGH_WATER_MARK];
416};
417
418static struct deferred_flush_tables *deferred_flush;
419
mark gross5e0d2a62008-03-04 15:22:08 -0800420/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800421static int g_num_of_iommus;
422
423static DEFINE_SPINLOCK(async_umap_flush_lock);
424static LIST_HEAD(unmaps_to_do);
425
426static int timer_on;
427static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800428
Jiang Liu92d03cc2014-02-19 14:07:28 +0800429static void domain_exit(struct dmar_domain *domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700430static void domain_remove_dev_info(struct dmar_domain *domain);
Jiang Liub94e4112014-02-19 14:07:25 +0800431static void domain_remove_one_dev_info(struct dmar_domain *domain,
432 struct pci_dev *pdev);
Jiang Liu92d03cc2014-02-19 14:07:28 +0800433static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
434 struct pci_dev *pdev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700435
Suresh Siddhad3f13812011-08-23 17:05:25 -0700436#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800437int dmar_disabled = 0;
438#else
439int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700440#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800441
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200442int intel_iommu_enabled = 0;
443EXPORT_SYMBOL_GPL(intel_iommu_enabled);
444
David Woodhouse2d9e6672010-06-15 10:57:57 +0100445static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700446static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800447static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100448static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700449
David Woodhousec0771df2011-10-14 20:59:46 +0100450int intel_iommu_gfx_mapped;
451EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
452
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700453#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
454static DEFINE_SPINLOCK(device_domain_lock);
455static LIST_HEAD(device_domain_list);
456
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100457static struct iommu_ops intel_iommu_ops;
458
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700459static int __init intel_iommu_setup(char *str)
460{
461 if (!str)
462 return -EINVAL;
463 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800464 if (!strncmp(str, "on", 2)) {
465 dmar_disabled = 0;
466 printk(KERN_INFO "Intel-IOMMU: enabled\n");
467 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700468 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800469 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700470 } else if (!strncmp(str, "igfx_off", 8)) {
471 dmar_map_gfx = 0;
472 printk(KERN_INFO
473 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700474 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800475 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700476 "Intel-IOMMU: Forcing DAC for PCI devices\n");
477 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800478 } else if (!strncmp(str, "strict", 6)) {
479 printk(KERN_INFO
480 "Intel-IOMMU: disable batched IOTLB flush\n");
481 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100482 } else if (!strncmp(str, "sp_off", 6)) {
483 printk(KERN_INFO
484 "Intel-IOMMU: disable supported super page\n");
485 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700486 }
487
488 str += strcspn(str, ",");
489 while (*str == ',')
490 str++;
491 }
492 return 0;
493}
494__setup("intel_iommu=", intel_iommu_setup);
495
496static struct kmem_cache *iommu_domain_cache;
497static struct kmem_cache *iommu_devinfo_cache;
498static struct kmem_cache *iommu_iova_cache;
499
Suresh Siddha4c923d42009-10-02 11:01:24 -0700500static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700501{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700502 struct page *page;
503 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700504
Suresh Siddha4c923d42009-10-02 11:01:24 -0700505 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
506 if (page)
507 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700508 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700509}
510
511static inline void free_pgtable_page(void *vaddr)
512{
513 free_page((unsigned long)vaddr);
514}
515
516static inline void *alloc_domain_mem(void)
517{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900518 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700519}
520
Kay, Allen M38717942008-09-09 18:37:29 +0300521static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700522{
523 kmem_cache_free(iommu_domain_cache, vaddr);
524}
525
526static inline void * alloc_devinfo_mem(void)
527{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900528 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700529}
530
531static inline void free_devinfo_mem(void *vaddr)
532{
533 kmem_cache_free(iommu_devinfo_cache, vaddr);
534}
535
536struct iova *alloc_iova_mem(void)
537{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900538 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700539}
540
541void free_iova_mem(struct iova *iova)
542{
543 kmem_cache_free(iommu_iova_cache, iova);
544}
545
Weidong Han1b573682008-12-08 15:34:06 +0800546
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700547static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800548{
549 unsigned long sagaw;
550 int agaw = -1;
551
552 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700553 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800554 agaw >= 0; agaw--) {
555 if (test_bit(agaw, &sagaw))
556 break;
557 }
558
559 return agaw;
560}
561
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700562/*
563 * Calculate max SAGAW for each iommu.
564 */
565int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
566{
567 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
568}
569
570/*
571 * calculate agaw for each iommu.
572 * "SAGAW" may be different across iommus, use a default agaw, and
573 * get a supported less agaw for iommus that don't support the default agaw.
574 */
575int iommu_calculate_agaw(struct intel_iommu *iommu)
576{
577 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
578}
579
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700580/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800581static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
582{
583 int iommu_id;
584
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700585 /* si_domain and vm domain should not get here. */
Weidong Han1ce28fe2008-12-08 16:35:39 +0800586 BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700587 BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
Weidong Han1ce28fe2008-12-08 16:35:39 +0800588
Mike Travis1b198bb2012-03-05 15:05:16 -0800589 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800590 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
591 return NULL;
592
593 return g_iommus[iommu_id];
594}
595
Weidong Han8e6040972008-12-08 15:49:06 +0800596static void domain_update_iommu_coherency(struct dmar_domain *domain)
597{
598 int i;
599
Alex Williamson2e12bc22011-11-11 17:26:44 -0700600 i = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
601
602 domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0;
Weidong Han8e6040972008-12-08 15:49:06 +0800603
Mike Travis1b198bb2012-03-05 15:05:16 -0800604 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Weidong Han8e6040972008-12-08 15:49:06 +0800605 if (!ecap_coherent(g_iommus[i]->ecap)) {
606 domain->iommu_coherency = 0;
607 break;
608 }
Weidong Han8e6040972008-12-08 15:49:06 +0800609 }
610}
611
Sheng Yang58c610b2009-03-18 15:33:05 +0800612static void domain_update_iommu_snooping(struct dmar_domain *domain)
613{
614 int i;
615
616 domain->iommu_snooping = 1;
617
Mike Travis1b198bb2012-03-05 15:05:16 -0800618 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800619 if (!ecap_sc_support(g_iommus[i]->ecap)) {
620 domain->iommu_snooping = 0;
621 break;
622 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800623 }
624}
625
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100626static void domain_update_iommu_superpage(struct dmar_domain *domain)
627{
Allen Kay8140a952011-10-14 12:32:17 -0700628 struct dmar_drhd_unit *drhd;
629 struct intel_iommu *iommu = NULL;
630 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100631
632 if (!intel_iommu_superpage) {
633 domain->iommu_superpage = 0;
634 return;
635 }
636
Allen Kay8140a952011-10-14 12:32:17 -0700637 /* set iommu_superpage to the smallest common denominator */
Jiang Liu0e242612014-02-19 14:07:34 +0800638 rcu_read_lock();
Allen Kay8140a952011-10-14 12:32:17 -0700639 for_each_active_iommu(iommu, drhd) {
640 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100641 if (!mask) {
642 break;
643 }
644 }
Jiang Liu0e242612014-02-19 14:07:34 +0800645 rcu_read_unlock();
646
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100647 domain->iommu_superpage = fls(mask);
648}
649
Sheng Yang58c610b2009-03-18 15:33:05 +0800650/* Some capabilities may be different across iommus */
651static void domain_update_iommu_cap(struct dmar_domain *domain)
652{
653 domain_update_iommu_coherency(domain);
654 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100655 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800656}
657
David Woodhouse276dbf992009-04-04 01:45:37 +0100658static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800659{
660 struct dmar_drhd_unit *drhd = NULL;
Jiang Liub683b232014-02-19 14:07:32 +0800661 struct intel_iommu *iommu;
662 struct pci_dev *dev;
Weidong Hanc7151a82008-12-08 22:51:37 +0800663 int i;
664
Jiang Liu0e242612014-02-19 14:07:34 +0800665 rcu_read_lock();
Jiang Liub683b232014-02-19 14:07:32 +0800666 for_each_active_iommu(iommu, drhd) {
David Woodhouse276dbf992009-04-04 01:45:37 +0100667 if (segment != drhd->segment)
668 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800669
Jiang Liub683b232014-02-19 14:07:32 +0800670 for_each_active_dev_scope(drhd->devices,
671 drhd->devices_cnt, i, dev) {
672 if (dev->bus->number == bus && dev->devfn == devfn)
673 goto out;
674 if (dev->subordinate &&
675 dev->subordinate->number <= bus &&
676 dev->subordinate->busn_res.end >= bus)
677 goto out;
David Woodhouse924b6232009-04-04 00:39:25 +0100678 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800679
680 if (drhd->include_all)
Jiang Liub683b232014-02-19 14:07:32 +0800681 goto out;
Weidong Hanc7151a82008-12-08 22:51:37 +0800682 }
Jiang Liub683b232014-02-19 14:07:32 +0800683 iommu = NULL;
684out:
Jiang Liu0e242612014-02-19 14:07:34 +0800685 rcu_read_unlock();
Weidong Hanc7151a82008-12-08 22:51:37 +0800686
Jiang Liub683b232014-02-19 14:07:32 +0800687 return iommu;
Weidong Hanc7151a82008-12-08 22:51:37 +0800688}
689
Weidong Han5331fe62008-12-08 23:00:00 +0800690static void domain_flush_cache(struct dmar_domain *domain,
691 void *addr, int size)
692{
693 if (!domain->iommu_coherency)
694 clflush_cache_range(addr, size);
695}
696
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700697/* Gets context entry for a given bus and devfn */
698static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
699 u8 bus, u8 devfn)
700{
701 struct root_entry *root;
702 struct context_entry *context;
703 unsigned long phy_addr;
704 unsigned long flags;
705
706 spin_lock_irqsave(&iommu->lock, flags);
707 root = &iommu->root_entry[bus];
708 context = get_context_addr_from_root(root);
709 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700710 context = (struct context_entry *)
711 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700712 if (!context) {
713 spin_unlock_irqrestore(&iommu->lock, flags);
714 return NULL;
715 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700716 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700717 phy_addr = virt_to_phys((void *)context);
718 set_root_value(root, phy_addr);
719 set_root_present(root);
720 __iommu_flush_cache(iommu, root, sizeof(*root));
721 }
722 spin_unlock_irqrestore(&iommu->lock, flags);
723 return &context[devfn];
724}
725
726static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
727{
728 struct root_entry *root;
729 struct context_entry *context;
730 int ret;
731 unsigned long flags;
732
733 spin_lock_irqsave(&iommu->lock, flags);
734 root = &iommu->root_entry[bus];
735 context = get_context_addr_from_root(root);
736 if (!context) {
737 ret = 0;
738 goto out;
739 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000740 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700741out:
742 spin_unlock_irqrestore(&iommu->lock, flags);
743 return ret;
744}
745
746static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
747{
748 struct root_entry *root;
749 struct context_entry *context;
750 unsigned long flags;
751
752 spin_lock_irqsave(&iommu->lock, flags);
753 root = &iommu->root_entry[bus];
754 context = get_context_addr_from_root(root);
755 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000756 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700757 __iommu_flush_cache(iommu, &context[devfn], \
758 sizeof(*context));
759 }
760 spin_unlock_irqrestore(&iommu->lock, flags);
761}
762
763static void free_context_table(struct intel_iommu *iommu)
764{
765 struct root_entry *root;
766 int i;
767 unsigned long flags;
768 struct context_entry *context;
769
770 spin_lock_irqsave(&iommu->lock, flags);
771 if (!iommu->root_entry) {
772 goto out;
773 }
774 for (i = 0; i < ROOT_ENTRY_NR; i++) {
775 root = &iommu->root_entry[i];
776 context = get_context_addr_from_root(root);
777 if (context)
778 free_pgtable_page(context);
779 }
780 free_pgtable_page(iommu->root_entry);
781 iommu->root_entry = NULL;
782out:
783 spin_unlock_irqrestore(&iommu->lock, flags);
784}
785
David Woodhouseb026fd22009-06-28 10:37:25 +0100786static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
Allen Kay4399c8b2011-10-14 12:32:46 -0700787 unsigned long pfn, int target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700788{
David Woodhouseb026fd22009-06-28 10:37:25 +0100789 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700790 struct dma_pte *parent, *pte = NULL;
791 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700792 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700793
794 BUG_ON(!domain->pgd);
Julian Stecklinaf9423602013-10-09 10:03:52 +0200795
796 if (addr_width < BITS_PER_LONG && pfn >> addr_width)
797 /* Address beyond IOMMU's addressing capabilities. */
798 return NULL;
799
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700800 parent = domain->pgd;
801
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700802 while (level > 0) {
803 void *tmp_page;
804
David Woodhouseb026fd22009-06-28 10:37:25 +0100805 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700806 pte = &parent[offset];
Allen Kay4399c8b2011-10-14 12:32:46 -0700807 if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100808 break;
809 if (level == target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700810 break;
811
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000812 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100813 uint64_t pteval;
814
Suresh Siddha4c923d42009-10-02 11:01:24 -0700815 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700816
David Woodhouse206a73c12009-07-01 19:30:28 +0100817 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700818 return NULL;
David Woodhouse206a73c12009-07-01 19:30:28 +0100819
David Woodhousec85994e2009-07-01 19:21:24 +0100820 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400821 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 +0100822 if (cmpxchg64(&pte->val, 0ULL, pteval)) {
823 /* Someone else set it while we were thinking; use theirs. */
824 free_pgtable_page(tmp_page);
825 } else {
826 dma_pte_addr(pte);
827 domain_flush_cache(domain, pte, sizeof(*pte));
828 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700829 }
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000830 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700831 level--;
832 }
833
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700834 return pte;
835}
836
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100837
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700838/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100839static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
840 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100841 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700842{
843 struct dma_pte *parent, *pte = NULL;
844 int total = agaw_to_level(domain->agaw);
845 int offset;
846
847 parent = domain->pgd;
848 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100849 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700850 pte = &parent[offset];
851 if (level == total)
852 return pte;
853
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100854 if (!dma_pte_present(pte)) {
855 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700856 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100857 }
858
859 if (pte->val & DMA_PTE_LARGE_PAGE) {
860 *large_page = total;
861 return pte;
862 }
863
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000864 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700865 total--;
866 }
867 return NULL;
868}
869
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700870/* clear last level pte, a tlb flush should be followed */
Allen Kay292827c2011-10-14 12:31:54 -0700871static int dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf2009-06-27 22:09:11 +0100872 unsigned long start_pfn,
873 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700874{
David Woodhouse04b18e62009-06-27 19:15:01 +0100875 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100876 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100877 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700878
David Woodhouse04b18e62009-06-27 19:15:01 +0100879 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf2009-06-27 22:09:11 +0100880 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700881 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100882
David Woodhouse04b18e62009-06-27 19:15:01 +0100883 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700884 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100885 large_page = 1;
886 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100887 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100888 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100889 continue;
890 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100891 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100892 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100893 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100894 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100895 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
896
David Woodhouse310a5ab2009-06-28 18:52:20 +0100897 domain_flush_cache(domain, first_pte,
898 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700899
900 } while (start_pfn && start_pfn <= last_pfn);
Allen Kay292827c2011-10-14 12:31:54 -0700901
Jiang Liu5c645b32014-01-06 14:18:12 +0800902 return min_t(int, (large_page - 1) * 9, MAX_AGAW_PFN_WIDTH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700903}
904
Alex Williamson3269ee02013-06-15 10:27:19 -0600905static void dma_pte_free_level(struct dmar_domain *domain, int level,
906 struct dma_pte *pte, unsigned long pfn,
907 unsigned long start_pfn, unsigned long last_pfn)
908{
909 pfn = max(start_pfn, pfn);
910 pte = &pte[pfn_level_offset(pfn, level)];
911
912 do {
913 unsigned long level_pfn;
914 struct dma_pte *level_pte;
915
916 if (!dma_pte_present(pte) || dma_pte_superpage(pte))
917 goto next;
918
919 level_pfn = pfn & level_mask(level - 1);
920 level_pte = phys_to_virt(dma_pte_addr(pte));
921
922 if (level > 2)
923 dma_pte_free_level(domain, level - 1, level_pte,
924 level_pfn, start_pfn, last_pfn);
925
926 /* If range covers entire pagetable, free it */
927 if (!(start_pfn > level_pfn ||
Alex Williamson08336fd2014-01-21 15:48:18 -0800928 last_pfn < level_pfn + level_size(level) - 1)) {
Alex Williamson3269ee02013-06-15 10:27:19 -0600929 dma_clear_pte(pte);
930 domain_flush_cache(domain, pte, sizeof(*pte));
931 free_pgtable_page(level_pte);
932 }
933next:
934 pfn += level_size(level);
935 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
936}
937
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700938/* free page table pages. last level pte should already be cleared */
939static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100940 unsigned long start_pfn,
941 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700942{
David Woodhouse6660c632009-06-27 22:41:00 +0100943 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700944
David Woodhouse6660c632009-06-27 22:41:00 +0100945 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
946 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700947 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700948
David Woodhousef3a0a522009-06-30 03:40:07 +0100949 /* We don't need lock here; nobody else touches the iova range */
Alex Williamson3269ee02013-06-15 10:27:19 -0600950 dma_pte_free_level(domain, agaw_to_level(domain->agaw),
951 domain->pgd, 0, start_pfn, last_pfn);
David Woodhouse6660c632009-06-27 22:41:00 +0100952
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700953 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100954 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700955 free_pgtable_page(domain->pgd);
956 domain->pgd = NULL;
957 }
958}
959
960/* iommu handling */
961static int iommu_alloc_root_entry(struct intel_iommu *iommu)
962{
963 struct root_entry *root;
964 unsigned long flags;
965
Suresh Siddha4c923d42009-10-02 11:01:24 -0700966 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700967 if (!root)
968 return -ENOMEM;
969
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700970 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700971
972 spin_lock_irqsave(&iommu->lock, flags);
973 iommu->root_entry = root;
974 spin_unlock_irqrestore(&iommu->lock, flags);
975
976 return 0;
977}
978
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700979static void iommu_set_root_entry(struct intel_iommu *iommu)
980{
981 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +0100982 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700983 unsigned long flag;
984
985 addr = iommu->root_entry;
986
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200987 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700988 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
989
David Woodhousec416daa2009-05-10 20:30:58 +0100990 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700991
992 /* Make sure hardware complete it */
993 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +0100994 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700995
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +0200996 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700997}
998
999static void iommu_flush_write_buffer(struct intel_iommu *iommu)
1000{
1001 u32 val;
1002 unsigned long flag;
1003
David Woodhouse9af88142009-02-13 23:18:03 +00001004 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001005 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001006
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001007 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +01001008 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001009
1010 /* Make sure hardware complete it */
1011 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001012 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001013
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001014 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001015}
1016
1017/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001018static void __iommu_flush_context(struct intel_iommu *iommu,
1019 u16 did, u16 source_id, u8 function_mask,
1020 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001021{
1022 u64 val = 0;
1023 unsigned long flag;
1024
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001025 switch (type) {
1026 case DMA_CCMD_GLOBAL_INVL:
1027 val = DMA_CCMD_GLOBAL_INVL;
1028 break;
1029 case DMA_CCMD_DOMAIN_INVL:
1030 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1031 break;
1032 case DMA_CCMD_DEVICE_INVL:
1033 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1034 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1035 break;
1036 default:
1037 BUG();
1038 }
1039 val |= DMA_CCMD_ICC;
1040
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001041 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001042 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1043
1044 /* Make sure hardware complete it */
1045 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1046 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1047
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001048 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001049}
1050
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001051/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001052static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1053 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001054{
1055 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1056 u64 val = 0, val_iva = 0;
1057 unsigned long flag;
1058
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001059 switch (type) {
1060 case DMA_TLB_GLOBAL_FLUSH:
1061 /* global flush doesn't need set IVA_REG */
1062 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1063 break;
1064 case DMA_TLB_DSI_FLUSH:
1065 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1066 break;
1067 case DMA_TLB_PSI_FLUSH:
1068 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1069 /* Note: always flush non-leaf currently */
1070 val_iva = size_order | addr;
1071 break;
1072 default:
1073 BUG();
1074 }
1075 /* Note: set drain read/write */
1076#if 0
1077 /*
1078 * This is probably to be super secure.. Looks like we can
1079 * ignore it without any impact.
1080 */
1081 if (cap_read_drain(iommu->cap))
1082 val |= DMA_TLB_READ_DRAIN;
1083#endif
1084 if (cap_write_drain(iommu->cap))
1085 val |= DMA_TLB_WRITE_DRAIN;
1086
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001087 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001088 /* Note: Only uses first TLB reg currently */
1089 if (val_iva)
1090 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1091 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1092
1093 /* Make sure hardware complete it */
1094 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1095 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1096
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001097 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001098
1099 /* check IOTLB invalidation granularity */
1100 if (DMA_TLB_IAIG(val) == 0)
1101 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1102 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1103 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001104 (unsigned long long)DMA_TLB_IIRG(type),
1105 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001106}
1107
Yu Zhao93a23a72009-05-18 13:51:37 +08001108static struct device_domain_info *iommu_support_dev_iotlb(
1109 struct dmar_domain *domain, int segment, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001110{
Yu Zhao93a23a72009-05-18 13:51:37 +08001111 int found = 0;
1112 unsigned long flags;
1113 struct device_domain_info *info;
1114 struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn);
1115
1116 if (!ecap_dev_iotlb_support(iommu->ecap))
1117 return NULL;
1118
1119 if (!iommu->qi)
1120 return NULL;
1121
1122 spin_lock_irqsave(&device_domain_lock, flags);
1123 list_for_each_entry(info, &domain->devices, link)
1124 if (info->bus == bus && info->devfn == devfn) {
1125 found = 1;
1126 break;
1127 }
1128 spin_unlock_irqrestore(&device_domain_lock, flags);
1129
1130 if (!found || !info->dev)
1131 return NULL;
1132
1133 if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS))
1134 return NULL;
1135
1136 if (!dmar_find_matched_atsr_unit(info->dev))
1137 return NULL;
1138
1139 info->iommu = iommu;
1140
1141 return info;
1142}
1143
1144static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1145{
1146 if (!info)
1147 return;
1148
1149 pci_enable_ats(info->dev, VTD_PAGE_SHIFT);
1150}
1151
1152static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1153{
1154 if (!info->dev || !pci_ats_enabled(info->dev))
1155 return;
1156
1157 pci_disable_ats(info->dev);
1158}
1159
1160static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1161 u64 addr, unsigned mask)
1162{
1163 u16 sid, qdep;
1164 unsigned long flags;
1165 struct device_domain_info *info;
1166
1167 spin_lock_irqsave(&device_domain_lock, flags);
1168 list_for_each_entry(info, &domain->devices, link) {
1169 if (!info->dev || !pci_ats_enabled(info->dev))
1170 continue;
1171
1172 sid = info->bus << 8 | info->devfn;
1173 qdep = pci_ats_queue_depth(info->dev);
1174 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1175 }
1176 spin_unlock_irqrestore(&device_domain_lock, flags);
1177}
1178
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001179static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
Nadav Amit82653632010-04-01 13:24:40 +03001180 unsigned long pfn, unsigned int pages, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001181{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001182 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001183 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001184
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001185 BUG_ON(pages == 0);
1186
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001187 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001188 * Fallback to domain selective flush if no PSI support or the size is
1189 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001190 * PSI requires page size to be 2 ^ x, and the base address is naturally
1191 * aligned to the size
1192 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001193 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1194 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001195 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001196 else
1197 iommu->flush.flush_iotlb(iommu, did, addr, mask,
1198 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001199
1200 /*
Nadav Amit82653632010-04-01 13:24:40 +03001201 * In caching mode, changes of pages from non-present to present require
1202 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001203 */
Nadav Amit82653632010-04-01 13:24:40 +03001204 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001205 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001206}
1207
mark grossf8bab732008-02-08 04:18:38 -08001208static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1209{
1210 u32 pmen;
1211 unsigned long flags;
1212
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001213 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001214 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1215 pmen &= ~DMA_PMEN_EPM;
1216 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1217
1218 /* wait for the protected region status bit to clear */
1219 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1220 readl, !(pmen & DMA_PMEN_PRS), pmen);
1221
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001222 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001223}
1224
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001225static int iommu_enable_translation(struct intel_iommu *iommu)
1226{
1227 u32 sts;
1228 unsigned long flags;
1229
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001230 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001231 iommu->gcmd |= DMA_GCMD_TE;
1232 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001233
1234 /* Make sure hardware complete it */
1235 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001236 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001237
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001238 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001239 return 0;
1240}
1241
1242static int iommu_disable_translation(struct intel_iommu *iommu)
1243{
1244 u32 sts;
1245 unsigned long flag;
1246
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001247 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001248 iommu->gcmd &= ~DMA_GCMD_TE;
1249 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1250
1251 /* Make sure hardware complete it */
1252 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001253 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001254
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001255 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001256 return 0;
1257}
1258
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001259
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001260static int iommu_init_domains(struct intel_iommu *iommu)
1261{
1262 unsigned long ndomains;
1263 unsigned long nlongs;
1264
1265 ndomains = cap_ndoms(iommu->cap);
Jiang Liu852bdb02014-01-06 14:18:11 +08001266 pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
1267 iommu->seq_id, ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001268 nlongs = BITS_TO_LONGS(ndomains);
1269
Donald Dutile94a91b52009-08-20 16:51:34 -04001270 spin_lock_init(&iommu->lock);
1271
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001272 /* TBD: there might be 64K domains,
1273 * consider other allocation for future chip
1274 */
1275 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1276 if (!iommu->domain_ids) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001277 pr_err("IOMMU%d: allocating domain id array failed\n",
1278 iommu->seq_id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001279 return -ENOMEM;
1280 }
1281 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1282 GFP_KERNEL);
1283 if (!iommu->domains) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001284 pr_err("IOMMU%d: allocating domain array failed\n",
1285 iommu->seq_id);
1286 kfree(iommu->domain_ids);
1287 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001288 return -ENOMEM;
1289 }
1290
1291 /*
1292 * if Caching mode is set, then invalid translations are tagged
1293 * with domainid 0. Hence we need to pre-allocate it.
1294 */
1295 if (cap_caching_mode(iommu->cap))
1296 set_bit(0, iommu->domain_ids);
1297 return 0;
1298}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001299
Jiang Liua868e6b2014-01-06 14:18:20 +08001300static void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001301{
1302 struct dmar_domain *domain;
Jiang Liu5ced12a2014-01-06 14:18:22 +08001303 int i, count;
Weidong Hanc7151a82008-12-08 22:51:37 +08001304 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001305
Donald Dutile94a91b52009-08-20 16:51:34 -04001306 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001307 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Jiang Liua4eaa862014-02-19 14:07:30 +08001308 /*
1309 * Domain id 0 is reserved for invalid translation
1310 * if hardware supports caching mode.
1311 */
1312 if (cap_caching_mode(iommu->cap) && i == 0)
1313 continue;
1314
Donald Dutile94a91b52009-08-20 16:51:34 -04001315 domain = iommu->domains[i];
1316 clear_bit(i, iommu->domain_ids);
Weidong Hanc7151a82008-12-08 22:51:37 +08001317
Donald Dutile94a91b52009-08-20 16:51:34 -04001318 spin_lock_irqsave(&domain->iommu_lock, flags);
Jiang Liu5ced12a2014-01-06 14:18:22 +08001319 count = --domain->iommu_count;
1320 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001321 if (count == 0)
1322 domain_exit(domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001323 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001324 }
1325
1326 if (iommu->gcmd & DMA_GCMD_TE)
1327 iommu_disable_translation(iommu);
1328
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001329 kfree(iommu->domains);
1330 kfree(iommu->domain_ids);
Jiang Liua868e6b2014-01-06 14:18:20 +08001331 iommu->domains = NULL;
1332 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001333
Weidong Hand9630fe2008-12-08 11:06:32 +08001334 g_iommus[iommu->seq_id] = NULL;
1335
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001336 /* free context mapping */
1337 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001338}
1339
Jiang Liu92d03cc2014-02-19 14:07:28 +08001340static struct dmar_domain *alloc_domain(bool vm)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001341{
Jiang Liu92d03cc2014-02-19 14:07:28 +08001342 /* domain id for virtual machine, it won't be set in context */
1343 static atomic_t vm_domid = ATOMIC_INIT(0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001344 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001345
1346 domain = alloc_domain_mem();
1347 if (!domain)
1348 return NULL;
1349
Suresh Siddha4c923d42009-10-02 11:01:24 -07001350 domain->nid = -1;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001351 domain->iommu_count = 0;
Mike Travis1b198bb2012-03-05 15:05:16 -08001352 memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
Weidong Hand71a2f32008-12-07 21:13:41 +08001353 domain->flags = 0;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001354 spin_lock_init(&domain->iommu_lock);
1355 INIT_LIST_HEAD(&domain->devices);
1356 if (vm) {
1357 domain->id = atomic_inc_return(&vm_domid);
1358 domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
1359 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001360
1361 return domain;
1362}
1363
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001364static int iommu_attach_domain(struct dmar_domain *domain,
1365 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001366{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001367 int num;
1368 unsigned long ndomains;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001369 unsigned long flags;
1370
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001371 ndomains = cap_ndoms(iommu->cap);
Weidong Han8c11e792008-12-08 15:29:22 +08001372
1373 spin_lock_irqsave(&iommu->lock, flags);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001374
1375 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1376 if (num >= ndomains) {
1377 spin_unlock_irqrestore(&iommu->lock, flags);
1378 printk(KERN_ERR "IOMMU: no free domain ids\n");
1379 return -ENOMEM;
1380 }
1381
1382 domain->id = num;
Jiang Liu9ebd6822014-02-19 14:07:29 +08001383 domain->iommu_count++;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001384 set_bit(num, iommu->domain_ids);
Mike Travis1b198bb2012-03-05 15:05:16 -08001385 set_bit(iommu->seq_id, domain->iommu_bmp);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001386 iommu->domains[num] = domain;
1387 spin_unlock_irqrestore(&iommu->lock, flags);
1388
1389 return 0;
1390}
1391
1392static void iommu_detach_domain(struct dmar_domain *domain,
1393 struct intel_iommu *iommu)
1394{
1395 unsigned long flags;
1396 int num, ndomains;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001397
1398 spin_lock_irqsave(&iommu->lock, flags);
1399 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001400 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001401 if (iommu->domains[num] == domain) {
Jiang Liu92d03cc2014-02-19 14:07:28 +08001402 clear_bit(num, iommu->domain_ids);
1403 iommu->domains[num] = NULL;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001404 break;
1405 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001406 }
Weidong Han8c11e792008-12-08 15:29:22 +08001407 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001408}
1409
1410static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001411static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001412
Joseph Cihula51a63e62011-03-21 11:04:24 -07001413static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001414{
1415 struct pci_dev *pdev = NULL;
1416 struct iova *iova;
1417 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001418
David Millerf6611972008-02-06 01:36:23 -08001419 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001420
Mark Gross8a443df2008-03-04 14:59:31 -08001421 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1422 &reserved_rbtree_key);
1423
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001424 /* IOAPIC ranges shouldn't be accessed by DMA */
1425 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1426 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001427 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001428 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001429 return -ENODEV;
1430 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001431
1432 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1433 for_each_pci_dev(pdev) {
1434 struct resource *r;
1435
1436 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1437 r = &pdev->resource[i];
1438 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1439 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001440 iova = reserve_iova(&reserved_iova_list,
1441 IOVA_PFN(r->start),
1442 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001443 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001444 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001445 return -ENODEV;
1446 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001447 }
1448 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001449 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001450}
1451
1452static void domain_reserve_special_ranges(struct dmar_domain *domain)
1453{
1454 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1455}
1456
1457static inline int guestwidth_to_adjustwidth(int gaw)
1458{
1459 int agaw;
1460 int r = (gaw - 12) % 9;
1461
1462 if (r == 0)
1463 agaw = gaw;
1464 else
1465 agaw = gaw + 9 - r;
1466 if (agaw > 64)
1467 agaw = 64;
1468 return agaw;
1469}
1470
1471static int domain_init(struct dmar_domain *domain, int guest_width)
1472{
1473 struct intel_iommu *iommu;
1474 int adjust_width, agaw;
1475 unsigned long sagaw;
1476
David Millerf6611972008-02-06 01:36:23 -08001477 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001478 domain_reserve_special_ranges(domain);
1479
1480 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001481 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001482 if (guest_width > cap_mgaw(iommu->cap))
1483 guest_width = cap_mgaw(iommu->cap);
1484 domain->gaw = guest_width;
1485 adjust_width = guestwidth_to_adjustwidth(guest_width);
1486 agaw = width_to_agaw(adjust_width);
1487 sagaw = cap_sagaw(iommu->cap);
1488 if (!test_bit(agaw, &sagaw)) {
1489 /* hardware doesn't support it, choose a bigger one */
1490 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1491 agaw = find_next_bit(&sagaw, 5, agaw);
1492 if (agaw >= 5)
1493 return -ENODEV;
1494 }
1495 domain->agaw = agaw;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001496
Weidong Han8e6040972008-12-08 15:49:06 +08001497 if (ecap_coherent(iommu->ecap))
1498 domain->iommu_coherency = 1;
1499 else
1500 domain->iommu_coherency = 0;
1501
Sheng Yang58c610b2009-03-18 15:33:05 +08001502 if (ecap_sc_support(iommu->ecap))
1503 domain->iommu_snooping = 1;
1504 else
1505 domain->iommu_snooping = 0;
1506
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001507 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
Suresh Siddha4c923d42009-10-02 11:01:24 -07001508 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001509
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001510 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001511 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001512 if (!domain->pgd)
1513 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001514 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001515 return 0;
1516}
1517
1518static void domain_exit(struct dmar_domain *domain)
1519{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001520 struct dmar_drhd_unit *drhd;
1521 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001522
1523 /* Domain 0 is reserved, so dont process it */
1524 if (!domain)
1525 return;
1526
Alex Williamson7b668352011-05-24 12:02:41 +01001527 /* Flush any lazy unmaps that may reference this domain */
1528 if (!intel_iommu_strict)
1529 flush_unmaps_timeout(0);
1530
Jiang Liu92d03cc2014-02-19 14:07:28 +08001531 /* remove associated devices */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001532 domain_remove_dev_info(domain);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001533
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001534 /* destroy iovas */
1535 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001536
1537 /* clear ptes */
David Woodhouse595badf2009-06-27 22:09:11 +01001538 dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001539
1540 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01001541 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001542
Jiang Liu92d03cc2014-02-19 14:07:28 +08001543 /* clear attached or cached domains */
Jiang Liu0e242612014-02-19 14:07:34 +08001544 rcu_read_lock();
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001545 for_each_active_iommu(iommu, drhd)
Jiang Liu92d03cc2014-02-19 14:07:28 +08001546 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1547 test_bit(iommu->seq_id, domain->iommu_bmp))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001548 iommu_detach_domain(domain, iommu);
Jiang Liu0e242612014-02-19 14:07:34 +08001549 rcu_read_unlock();
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001550
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001551 free_domain_mem(domain);
1552}
1553
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001554static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
1555 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001556{
1557 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001558 unsigned long flags;
Weidong Han5331fe62008-12-08 23:00:00 +08001559 struct intel_iommu *iommu;
Weidong Hanea6606b2008-12-08 23:08:15 +08001560 struct dma_pte *pgd;
1561 unsigned long num;
1562 unsigned long ndomains;
1563 int id;
1564 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001565 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001566
1567 pr_debug("Set context mapping for %02x:%02x.%d\n",
1568 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001569
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001570 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001571 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1572 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001573
David Woodhouse276dbf992009-04-04 01:45:37 +01001574 iommu = device_to_iommu(segment, bus, devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001575 if (!iommu)
1576 return -ENODEV;
1577
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001578 context = device_to_context_entry(iommu, bus, devfn);
1579 if (!context)
1580 return -ENOMEM;
1581 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001582 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001583 spin_unlock_irqrestore(&iommu->lock, flags);
1584 return 0;
1585 }
1586
Weidong Hanea6606b2008-12-08 23:08:15 +08001587 id = domain->id;
1588 pgd = domain->pgd;
1589
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001590 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1591 domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001592 int found = 0;
1593
1594 /* find an available domain id for this device in iommu */
1595 ndomains = cap_ndoms(iommu->cap);
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001596 for_each_set_bit(num, iommu->domain_ids, ndomains) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001597 if (iommu->domains[num] == domain) {
1598 id = num;
1599 found = 1;
1600 break;
1601 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001602 }
1603
1604 if (found == 0) {
1605 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1606 if (num >= ndomains) {
1607 spin_unlock_irqrestore(&iommu->lock, flags);
1608 printk(KERN_ERR "IOMMU: no free domain ids\n");
1609 return -EFAULT;
1610 }
1611
1612 set_bit(num, iommu->domain_ids);
1613 iommu->domains[num] = domain;
1614 id = num;
1615 }
1616
1617 /* Skip top levels of page tables for
1618 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001619 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001620 */
Chris Wright1672af12009-12-02 12:06:34 -08001621 if (translation != CONTEXT_TT_PASS_THROUGH) {
1622 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1623 pgd = phys_to_virt(dma_pte_addr(pgd));
1624 if (!dma_pte_present(pgd)) {
1625 spin_unlock_irqrestore(&iommu->lock, flags);
1626 return -ENOMEM;
1627 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001628 }
1629 }
1630 }
1631
1632 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001633
Yu Zhao93a23a72009-05-18 13:51:37 +08001634 if (translation != CONTEXT_TT_PASS_THROUGH) {
1635 info = iommu_support_dev_iotlb(domain, segment, bus, devfn);
1636 translation = info ? CONTEXT_TT_DEV_IOTLB :
1637 CONTEXT_TT_MULTI_LEVEL;
1638 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001639 /*
1640 * In pass through mode, AW must be programmed to indicate the largest
1641 * AGAW value supported by hardware. And ASR is ignored by hardware.
1642 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001643 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001644 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001645 else {
1646 context_set_address_root(context, virt_to_phys(pgd));
1647 context_set_address_width(context, iommu->agaw);
1648 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001649
1650 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001651 context_set_fault_enable(context);
1652 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001653 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001654
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001655 /*
1656 * It's a non-present to present mapping. If hardware doesn't cache
1657 * non-present entry we only need to flush the write-buffer. If the
1658 * _does_ cache non-present entries, then it does so in the special
1659 * domain #0, which we have to flush:
1660 */
1661 if (cap_caching_mode(iommu->cap)) {
1662 iommu->flush.flush_context(iommu, 0,
1663 (((u16)bus) << 8) | devfn,
1664 DMA_CCMD_MASK_NOBIT,
1665 DMA_CCMD_DEVICE_INVL);
Nadav Amit82653632010-04-01 13:24:40 +03001666 iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001667 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001668 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001669 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001670 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001671 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001672
1673 spin_lock_irqsave(&domain->iommu_lock, flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08001674 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
Weidong Hanc7151a82008-12-08 22:51:37 +08001675 domain->iommu_count++;
Suresh Siddha4c923d42009-10-02 11:01:24 -07001676 if (domain->iommu_count == 1)
1677 domain->nid = iommu->node;
Sheng Yang58c610b2009-03-18 15:33:05 +08001678 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08001679 }
1680 spin_unlock_irqrestore(&domain->iommu_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001681 return 0;
1682}
1683
1684static int
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001685domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
1686 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001687{
1688 int ret;
1689 struct pci_dev *tmp, *parent;
1690
David Woodhouse276dbf992009-04-04 01:45:37 +01001691 ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001692 pdev->bus->number, pdev->devfn,
1693 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001694 if (ret)
1695 return ret;
1696
1697 /* dependent device mapping */
1698 tmp = pci_find_upstream_pcie_bridge(pdev);
1699 if (!tmp)
1700 return 0;
1701 /* Secondary interface's bus number and devfn 0 */
1702 parent = pdev->bus->self;
1703 while (parent != tmp) {
David Woodhouse276dbf992009-04-04 01:45:37 +01001704 ret = domain_context_mapping_one(domain,
1705 pci_domain_nr(parent->bus),
1706 parent->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001707 parent->devfn, translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001708 if (ret)
1709 return ret;
1710 parent = parent->bus->self;
1711 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05001712 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001713 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001714 pci_domain_nr(tmp->subordinate),
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001715 tmp->subordinate->number, 0,
1716 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001717 else /* this is a legacy PCI bridge */
1718 return domain_context_mapping_one(domain,
David Woodhouse276dbf992009-04-04 01:45:37 +01001719 pci_domain_nr(tmp->bus),
1720 tmp->bus->number,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001721 tmp->devfn,
1722 translation);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001723}
1724
Weidong Han5331fe62008-12-08 23:00:00 +08001725static int domain_context_mapped(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001726{
1727 int ret;
1728 struct pci_dev *tmp, *parent;
Weidong Han5331fe62008-12-08 23:00:00 +08001729 struct intel_iommu *iommu;
1730
David Woodhouse276dbf992009-04-04 01:45:37 +01001731 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
1732 pdev->devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001733 if (!iommu)
1734 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001735
David Woodhouse276dbf992009-04-04 01:45:37 +01001736 ret = device_context_mapped(iommu, pdev->bus->number, pdev->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001737 if (!ret)
1738 return ret;
1739 /* dependent device mapping */
1740 tmp = pci_find_upstream_pcie_bridge(pdev);
1741 if (!tmp)
1742 return ret;
1743 /* Secondary interface's bus number and devfn 0 */
1744 parent = pdev->bus->self;
1745 while (parent != tmp) {
Weidong Han8c11e792008-12-08 15:29:22 +08001746 ret = device_context_mapped(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01001747 parent->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001748 if (!ret)
1749 return ret;
1750 parent = parent->bus->self;
1751 }
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09001752 if (pci_is_pcie(tmp))
David Woodhouse276dbf992009-04-04 01:45:37 +01001753 return device_context_mapped(iommu, tmp->subordinate->number,
1754 0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001755 else
David Woodhouse276dbf992009-04-04 01:45:37 +01001756 return device_context_mapped(iommu, tmp->bus->number,
1757 tmp->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001758}
1759
Fenghua Yuf5329592009-08-04 15:09:37 -07001760/* Returns a number of VTD pages, but aligned to MM page size */
1761static inline unsigned long aligned_nrpages(unsigned long host_addr,
1762 size_t size)
1763{
1764 host_addr &= ~PAGE_MASK;
1765 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1766}
1767
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001768/* Return largest possible superpage level for a given mapping */
1769static inline int hardware_largepage_caps(struct dmar_domain *domain,
1770 unsigned long iov_pfn,
1771 unsigned long phy_pfn,
1772 unsigned long pages)
1773{
1774 int support, level = 1;
1775 unsigned long pfnmerge;
1776
1777 support = domain->iommu_superpage;
1778
1779 /* To use a large page, the virtual *and* physical addresses
1780 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1781 of them will mean we have to use smaller pages. So just
1782 merge them and check both at once. */
1783 pfnmerge = iov_pfn | phy_pfn;
1784
1785 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1786 pages >>= VTD_STRIDE_SHIFT;
1787 if (!pages)
1788 break;
1789 pfnmerge >>= VTD_STRIDE_SHIFT;
1790 level++;
1791 support--;
1792 }
1793 return level;
1794}
1795
David Woodhouse9051aa02009-06-29 12:30:54 +01001796static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1797 struct scatterlist *sg, unsigned long phys_pfn,
1798 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001799{
1800 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001801 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001802 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001803 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001804 unsigned int largepage_lvl = 0;
1805 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001806
1807 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1808
1809 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1810 return -EINVAL;
1811
1812 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1813
David Woodhouse9051aa02009-06-29 12:30:54 +01001814 if (sg)
1815 sg_res = 0;
1816 else {
1817 sg_res = nr_pages + 1;
1818 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1819 }
1820
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001821 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001822 uint64_t tmp;
1823
David Woodhousee1605492009-06-29 11:17:38 +01001824 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001825 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001826 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
1827 sg->dma_length = sg->length;
1828 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001829 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01001830 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001831
David Woodhousee1605492009-06-29 11:17:38 +01001832 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001833 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
1834
1835 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01001836 if (!pte)
1837 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001838 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001839 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001840 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001841 /* Ensure that old small page tables are removed to make room
1842 for superpage, if they exist. */
1843 dma_pte_clear_range(domain, iov_pfn,
1844 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1845 dma_pte_free_pagetable(domain, iov_pfn,
1846 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
1847 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001848 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00001849 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001850
David Woodhousee1605492009-06-29 11:17:38 +01001851 }
1852 /* We don't need lock here, nobody else
1853 * touches the iova range
1854 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01001855 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01001856 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01001857 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01001858 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
1859 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01001860 if (dumps) {
1861 dumps--;
1862 debug_dma_dump_mappings(NULL);
1863 }
1864 WARN_ON(1);
1865 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001866
1867 lvl_pages = lvl_to_nr_pages(largepage_lvl);
1868
1869 BUG_ON(nr_pages < lvl_pages);
1870 BUG_ON(sg_res < lvl_pages);
1871
1872 nr_pages -= lvl_pages;
1873 iov_pfn += lvl_pages;
1874 phys_pfn += lvl_pages;
1875 pteval += lvl_pages * VTD_PAGE_SIZE;
1876 sg_res -= lvl_pages;
1877
1878 /* If the next PTE would be the first in a new page, then we
1879 need to flush the cache on the entries we've just written.
1880 And then we'll need to recalculate 'pte', so clear it and
1881 let it get set again in the if (!pte) block above.
1882
1883 If we're done (!nr_pages) we need to flush the cache too.
1884
1885 Also if we've been setting superpages, we may need to
1886 recalculate 'pte' and switch back to smaller pages for the
1887 end of the mapping, if the trailing size is not enough to
1888 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01001889 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001890 if (!nr_pages || first_pte_in_page(pte) ||
1891 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01001892 domain_flush_cache(domain, first_pte,
1893 (void *)pte - (void *)first_pte);
1894 pte = NULL;
1895 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001896
1897 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01001898 sg = sg_next(sg);
1899 }
1900 return 0;
1901}
1902
David Woodhouse9051aa02009-06-29 12:30:54 +01001903static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1904 struct scatterlist *sg, unsigned long nr_pages,
1905 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001906{
David Woodhouse9051aa02009-06-29 12:30:54 +01001907 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
1908}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001909
David Woodhouse9051aa02009-06-29 12:30:54 +01001910static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1911 unsigned long phys_pfn, unsigned long nr_pages,
1912 int prot)
1913{
1914 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001915}
1916
Weidong Hanc7151a82008-12-08 22:51:37 +08001917static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001918{
Weidong Hanc7151a82008-12-08 22:51:37 +08001919 if (!iommu)
1920 return;
Weidong Han8c11e792008-12-08 15:29:22 +08001921
1922 clear_context_table(iommu, bus, devfn);
1923 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001924 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001925 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001926}
1927
David Woodhouse109b9b02012-05-25 17:43:02 +01001928static inline void unlink_domain_info(struct device_domain_info *info)
1929{
1930 assert_spin_locked(&device_domain_lock);
1931 list_del(&info->link);
1932 list_del(&info->global);
1933 if (info->dev)
1934 info->dev->dev.archdata.iommu = NULL;
1935}
1936
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001937static void domain_remove_dev_info(struct dmar_domain *domain)
1938{
1939 struct device_domain_info *info;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001940 unsigned long flags, flags2;
Weidong Hanc7151a82008-12-08 22:51:37 +08001941 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001942
1943 spin_lock_irqsave(&device_domain_lock, flags);
1944 while (!list_empty(&domain->devices)) {
1945 info = list_entry(domain->devices.next,
1946 struct device_domain_info, link);
David Woodhouse109b9b02012-05-25 17:43:02 +01001947 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001948 spin_unlock_irqrestore(&device_domain_lock, flags);
1949
Yu Zhao93a23a72009-05-18 13:51:37 +08001950 iommu_disable_dev_iotlb(info);
David Woodhouse276dbf992009-04-04 01:45:37 +01001951 iommu = device_to_iommu(info->segment, info->bus, info->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08001952 iommu_detach_dev(iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001953
Jiang Liu92d03cc2014-02-19 14:07:28 +08001954 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
1955 iommu_detach_dependent_devices(iommu, info->dev);
1956 /* clear this iommu in iommu_bmp, update iommu count
1957 * and capabilities
1958 */
1959 spin_lock_irqsave(&domain->iommu_lock, flags2);
1960 if (test_and_clear_bit(iommu->seq_id,
1961 domain->iommu_bmp)) {
1962 domain->iommu_count--;
1963 domain_update_iommu_cap(domain);
1964 }
1965 spin_unlock_irqrestore(&domain->iommu_lock, flags2);
1966 }
1967
1968 free_devinfo_mem(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001969 spin_lock_irqsave(&device_domain_lock, flags);
1970 }
1971 spin_unlock_irqrestore(&device_domain_lock, flags);
1972}
1973
1974/*
1975 * find_domain
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001976 * Note: we use struct pci_dev->dev.archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001977 */
Kay, Allen M38717942008-09-09 18:37:29 +03001978static struct dmar_domain *
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001979find_domain(struct pci_dev *pdev)
1980{
1981 struct device_domain_info *info;
1982
1983 /* No lock here, assumes no domain exit in normal case */
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07001984 info = pdev->dev.archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001985 if (info)
1986 return info->domain;
1987 return NULL;
1988}
1989
Jiang Liu745f2582014-02-19 14:07:26 +08001990static inline struct dmar_domain *
1991dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
1992{
1993 struct device_domain_info *info;
1994
1995 list_for_each_entry(info, &device_domain_list, global)
1996 if (info->segment == segment && info->bus == bus &&
1997 info->devfn == devfn)
1998 return info->domain;
1999
2000 return NULL;
2001}
2002
2003static int dmar_insert_dev_info(int segment, int bus, int devfn,
2004 struct pci_dev *dev, struct dmar_domain **domp)
2005{
2006 struct dmar_domain *found, *domain = *domp;
2007 struct device_domain_info *info;
2008 unsigned long flags;
2009
2010 info = alloc_devinfo_mem();
2011 if (!info)
2012 return -ENOMEM;
2013
2014 info->segment = segment;
2015 info->bus = bus;
2016 info->devfn = devfn;
2017 info->dev = dev;
2018 info->domain = domain;
2019 if (!dev)
2020 domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
2021
2022 spin_lock_irqsave(&device_domain_lock, flags);
2023 if (dev)
2024 found = find_domain(dev);
2025 else
2026 found = dmar_search_domain_by_dev_info(segment, bus, devfn);
2027 if (found) {
2028 spin_unlock_irqrestore(&device_domain_lock, flags);
2029 free_devinfo_mem(info);
2030 if (found != domain) {
2031 domain_exit(domain);
2032 *domp = found;
2033 }
2034 } else {
2035 list_add(&info->link, &domain->devices);
2036 list_add(&info->global, &device_domain_list);
2037 if (dev)
2038 dev->dev.archdata.iommu = info;
2039 spin_unlock_irqrestore(&device_domain_lock, flags);
2040 }
2041
2042 return 0;
2043}
2044
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002045/* domain is initialized */
2046static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
2047{
Jiang Liue85bb5d2014-02-19 14:07:27 +08002048 struct dmar_domain *domain, *free = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002049 struct intel_iommu *iommu;
2050 struct dmar_drhd_unit *drhd;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002051 struct pci_dev *dev_tmp;
2052 unsigned long flags;
2053 int bus = 0, devfn = 0;
David Woodhouse276dbf992009-04-04 01:45:37 +01002054 int segment;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002055
2056 domain = find_domain(pdev);
2057 if (domain)
2058 return domain;
2059
David Woodhouse276dbf992009-04-04 01:45:37 +01002060 segment = pci_domain_nr(pdev->bus);
2061
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002062 dev_tmp = pci_find_upstream_pcie_bridge(pdev);
2063 if (dev_tmp) {
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002064 if (pci_is_pcie(dev_tmp)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002065 bus = dev_tmp->subordinate->number;
2066 devfn = 0;
2067 } else {
2068 bus = dev_tmp->bus->number;
2069 devfn = dev_tmp->devfn;
2070 }
2071 spin_lock_irqsave(&device_domain_lock, flags);
Jiang Liu745f2582014-02-19 14:07:26 +08002072 domain = dmar_search_domain_by_dev_info(segment, bus, devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002073 spin_unlock_irqrestore(&device_domain_lock, flags);
2074 /* pcie-pci bridge already has a domain, uses it */
Jiang Liu745f2582014-02-19 14:07:26 +08002075 if (domain)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002076 goto found_domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002077 }
2078
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002079 drhd = dmar_find_matched_drhd_unit(pdev);
2080 if (!drhd) {
2081 printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
2082 pci_name(pdev));
2083 return NULL;
2084 }
2085 iommu = drhd->iommu;
2086
Jiang Liu745f2582014-02-19 14:07:26 +08002087 /* Allocate and intialize new domain for the device */
Jiang Liu92d03cc2014-02-19 14:07:28 +08002088 domain = alloc_domain(false);
Jiang Liu745f2582014-02-19 14:07:26 +08002089 if (!domain)
2090 goto error;
2091 if (iommu_attach_domain(domain, iommu)) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002092 free_domain_mem(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002093 goto error;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002094 }
Jiang Liue85bb5d2014-02-19 14:07:27 +08002095 free = domain;
2096 if (domain_init(domain, gaw))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002097 goto error;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002098
2099 /* register pcie-to-pci device */
2100 if (dev_tmp) {
Jiang Liue85bb5d2014-02-19 14:07:27 +08002101 if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002102 goto error;
Jiang Liue85bb5d2014-02-19 14:07:27 +08002103 else
2104 free = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002105 }
2106
2107found_domain:
Jiang Liu745f2582014-02-19 14:07:26 +08002108 if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
2109 pdev, &domain) == 0)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002110 return domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002111error:
Jiang Liue85bb5d2014-02-19 14:07:27 +08002112 if (free)
2113 domain_exit(free);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002114 /* recheck it here, maybe others set it */
2115 return find_domain(pdev);
2116}
2117
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002118static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002119#define IDENTMAP_ALL 1
2120#define IDENTMAP_GFX 2
2121#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002122
David Woodhouseb2132032009-06-26 18:50:28 +01002123static int iommu_domain_identity_map(struct dmar_domain *domain,
2124 unsigned long long start,
2125 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002126{
David Woodhousec5395d52009-06-28 16:35:56 +01002127 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2128 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002129
David Woodhousec5395d52009-06-28 16:35:56 +01002130 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2131 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002132 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002133 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002134 }
2135
David Woodhousec5395d52009-06-28 16:35:56 +01002136 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2137 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002138 /*
2139 * RMRR range might have overlap with physical memory range,
2140 * clear it first
2141 */
David Woodhousec5395d52009-06-28 16:35:56 +01002142 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002143
David Woodhousec5395d52009-06-28 16:35:56 +01002144 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2145 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002146 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002147}
2148
2149static int iommu_prepare_identity_map(struct pci_dev *pdev,
2150 unsigned long long start,
2151 unsigned long long end)
2152{
2153 struct dmar_domain *domain;
2154 int ret;
2155
David Woodhousec7ab48d2009-06-26 19:10:36 +01002156 domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002157 if (!domain)
2158 return -ENOMEM;
2159
David Woodhouse19943b02009-08-04 16:19:20 +01002160 /* For _hardware_ passthrough, don't bother. But for software
2161 passthrough, we do it anyway -- it may indicate a memory
2162 range which is reserved in E820, so which didn't get set
2163 up to start with in si_domain */
2164 if (domain == si_domain && hw_pass_through) {
2165 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
2166 pci_name(pdev), start, end);
2167 return 0;
2168 }
2169
2170 printk(KERN_INFO
2171 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
2172 pci_name(pdev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002173
David Woodhouse5595b522009-12-02 09:21:55 +00002174 if (end < start) {
2175 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2176 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2177 dmi_get_system_info(DMI_BIOS_VENDOR),
2178 dmi_get_system_info(DMI_BIOS_VERSION),
2179 dmi_get_system_info(DMI_PRODUCT_VERSION));
2180 ret = -EIO;
2181 goto error;
2182 }
2183
David Woodhouse2ff729f2009-08-26 14:25:41 +01002184 if (end >> agaw_to_width(domain->agaw)) {
2185 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2186 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2187 agaw_to_width(domain->agaw),
2188 dmi_get_system_info(DMI_BIOS_VENDOR),
2189 dmi_get_system_info(DMI_BIOS_VERSION),
2190 dmi_get_system_info(DMI_PRODUCT_VERSION));
2191 ret = -EIO;
2192 goto error;
2193 }
David Woodhouse19943b02009-08-04 16:19:20 +01002194
David Woodhouseb2132032009-06-26 18:50:28 +01002195 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002196 if (ret)
2197 goto error;
2198
2199 /* context entry init */
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002200 ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002201 if (ret)
2202 goto error;
2203
2204 return 0;
2205
2206 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002207 domain_exit(domain);
2208 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002209}
2210
2211static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
2212 struct pci_dev *pdev)
2213{
Keshavamurthy, Anil S358dd8a2007-10-21 16:41:59 -07002214 if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002215 return 0;
2216 return iommu_prepare_identity_map(pdev, rmrr->base_address,
David Woodhouse70e535d2011-05-31 00:22:52 +01002217 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002218}
2219
Suresh Siddhad3f13812011-08-23 17:05:25 -07002220#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002221static inline void iommu_prepare_isa(void)
2222{
2223 struct pci_dev *pdev;
2224 int ret;
2225
2226 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2227 if (!pdev)
2228 return;
2229
David Woodhousec7ab48d2009-06-26 19:10:36 +01002230 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse70e535d2011-05-31 00:22:52 +01002231 ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002232
2233 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002234 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2235 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002236
2237}
2238#else
2239static inline void iommu_prepare_isa(void)
2240{
2241 return;
2242}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002243#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002244
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002245static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002246
Matt Kraai071e1372009-08-23 22:30:22 -07002247static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002248{
2249 struct dmar_drhd_unit *drhd;
2250 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002251 int nid, ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002252
Jiang Liu92d03cc2014-02-19 14:07:28 +08002253 si_domain = alloc_domain(false);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002254 if (!si_domain)
2255 return -EFAULT;
2256
Jiang Liu92d03cc2014-02-19 14:07:28 +08002257 si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
2258
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002259 for_each_active_iommu(iommu, drhd) {
2260 ret = iommu_attach_domain(si_domain, iommu);
2261 if (ret) {
2262 domain_exit(si_domain);
2263 return -EFAULT;
2264 }
2265 }
2266
2267 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2268 domain_exit(si_domain);
2269 return -EFAULT;
2270 }
2271
Jiang Liu9544c002014-01-06 14:18:13 +08002272 pr_debug("IOMMU: identity mapping domain is domain %d\n",
2273 si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002274
David Woodhouse19943b02009-08-04 16:19:20 +01002275 if (hw)
2276 return 0;
2277
David Woodhousec7ab48d2009-06-26 19:10:36 +01002278 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002279 unsigned long start_pfn, end_pfn;
2280 int i;
2281
2282 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2283 ret = iommu_domain_identity_map(si_domain,
2284 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2285 if (ret)
2286 return ret;
2287 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002288 }
2289
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002290 return 0;
2291}
2292
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002293static int identity_mapping(struct pci_dev *pdev)
2294{
2295 struct device_domain_info *info;
2296
2297 if (likely(!iommu_identity_mapping))
2298 return 0;
2299
Mike Traviscb452a42011-05-28 13:15:03 -05002300 info = pdev->dev.archdata.iommu;
2301 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2302 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002303
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002304 return 0;
2305}
2306
2307static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002308 struct pci_dev *pdev,
2309 int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002310{
2311 struct device_domain_info *info;
2312 unsigned long flags;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002313 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002314
2315 info = alloc_devinfo_mem();
2316 if (!info)
2317 return -ENOMEM;
2318
2319 info->segment = pci_domain_nr(pdev->bus);
2320 info->bus = pdev->bus->number;
2321 info->devfn = pdev->devfn;
2322 info->dev = pdev;
2323 info->domain = domain;
2324
2325 spin_lock_irqsave(&device_domain_lock, flags);
2326 list_add(&info->link, &domain->devices);
2327 list_add(&info->global, &device_domain_list);
2328 pdev->dev.archdata.iommu = info;
2329 spin_unlock_irqrestore(&device_domain_lock, flags);
2330
David Woodhousee2ad23d2012-05-25 17:42:54 +01002331 ret = domain_context_mapping(domain, pdev, translation);
2332 if (ret) {
2333 spin_lock_irqsave(&device_domain_lock, flags);
David Woodhouse109b9b02012-05-25 17:43:02 +01002334 unlink_domain_info(info);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002335 spin_unlock_irqrestore(&device_domain_lock, flags);
2336 free_devinfo_mem(info);
2337 return ret;
2338 }
2339
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002340 return 0;
2341}
2342
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002343static bool device_has_rmrr(struct pci_dev *dev)
2344{
2345 struct dmar_rmrr_unit *rmrr;
Jiang Liub683b232014-02-19 14:07:32 +08002346 struct pci_dev *tmp;
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002347 int i;
2348
Jiang Liu0e242612014-02-19 14:07:34 +08002349 rcu_read_lock();
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002350 for_each_rmrr_units(rmrr) {
Jiang Liub683b232014-02-19 14:07:32 +08002351 /*
2352 * Return TRUE if this RMRR contains the device that
2353 * is passed in.
2354 */
2355 for_each_active_dev_scope(rmrr->devices,
2356 rmrr->devices_cnt, i, tmp)
2357 if (tmp == dev) {
Jiang Liu0e242612014-02-19 14:07:34 +08002358 rcu_read_unlock();
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002359 return true;
Jiang Liub683b232014-02-19 14:07:32 +08002360 }
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002361 }
Jiang Liu0e242612014-02-19 14:07:34 +08002362 rcu_read_unlock();
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002363 return false;
2364}
2365
David Woodhouse6941af22009-07-04 18:24:27 +01002366static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
2367{
Tom Mingarelliea2447f2012-11-20 19:43:17 +00002368
2369 /*
2370 * We want to prevent any device associated with an RMRR from
2371 * getting placed into the SI Domain. This is done because
2372 * problems exist when devices are moved in and out of domains
2373 * and their respective RMRR info is lost. We exempt USB devices
2374 * from this process due to their usage of RMRRs that are known
2375 * to not be needed after BIOS hand-off to OS.
2376 */
2377 if (device_has_rmrr(pdev) &&
2378 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2379 return 0;
2380
David Woodhousee0fc7e02009-09-30 09:12:17 -07002381 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2382 return 1;
2383
2384 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2385 return 1;
2386
2387 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2388 return 0;
David Woodhouse6941af22009-07-04 18:24:27 +01002389
David Woodhouse3dfc8132009-07-04 19:11:08 +01002390 /*
2391 * We want to start off with all devices in the 1:1 domain, and
2392 * take them out later if we find they can't access all of memory.
2393 *
2394 * However, we can't do this for PCI devices behind bridges,
2395 * because all PCI devices behind the same bridge will end up
2396 * with the same source-id on their transactions.
2397 *
2398 * Practically speaking, we can't change things around for these
2399 * devices at run-time, because we can't be sure there'll be no
2400 * DMA transactions in flight for any of their siblings.
2401 *
2402 * So PCI devices (unless they're on the root bus) as well as
2403 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2404 * the 1:1 domain, just in _case_ one of their siblings turns out
2405 * not to be able to map all of memory.
2406 */
Kenji Kaneshige5f4d91a2009-11-11 14:36:17 +09002407 if (!pci_is_pcie(pdev)) {
David Woodhouse3dfc8132009-07-04 19:11:08 +01002408 if (!pci_is_root_bus(pdev->bus))
2409 return 0;
2410 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2411 return 0;
Yijing Wang62f87c02012-07-24 17:20:03 +08002412 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
David Woodhouse3dfc8132009-07-04 19:11:08 +01002413 return 0;
2414
2415 /*
2416 * At boot time, we don't yet know if devices will be 64-bit capable.
2417 * Assume that they will -- if they turn out not to be, then we can
2418 * take them out of the 1:1 domain later.
2419 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002420 if (!startup) {
2421 /*
2422 * If the device's dma_mask is less than the system's memory
2423 * size then this is not a candidate for identity mapping.
2424 */
2425 u64 dma_mask = pdev->dma_mask;
2426
2427 if (pdev->dev.coherent_dma_mask &&
2428 pdev->dev.coherent_dma_mask < dma_mask)
2429 dma_mask = pdev->dev.coherent_dma_mask;
2430
2431 return dma_mask >= dma_get_required_mask(&pdev->dev);
2432 }
David Woodhouse6941af22009-07-04 18:24:27 +01002433
2434 return 1;
2435}
2436
Matt Kraai071e1372009-08-23 22:30:22 -07002437static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002438{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002439 struct pci_dev *pdev = NULL;
2440 int ret;
2441
David Woodhouse19943b02009-08-04 16:19:20 +01002442 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002443 if (ret)
2444 return -EFAULT;
2445
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002446 for_each_pci_dev(pdev) {
David Woodhouse6941af22009-07-04 18:24:27 +01002447 if (iommu_should_identity_map(pdev, 1)) {
David Woodhouse5fe60f42009-08-09 10:53:41 +01002448 ret = domain_add_dev_info(si_domain, pdev,
Mike Traviseae460b2012-03-05 15:05:16 -08002449 hw ? CONTEXT_TT_PASS_THROUGH :
2450 CONTEXT_TT_MULTI_LEVEL);
2451 if (ret) {
2452 /* device not associated with an iommu */
2453 if (ret == -ENODEV)
2454 continue;
David Woodhouse62edf5d2009-07-04 10:59:46 +01002455 return ret;
Mike Traviseae460b2012-03-05 15:05:16 -08002456 }
2457 pr_info("IOMMU: %s identity mapping for device %s\n",
2458 hw ? "hardware" : "software", pci_name(pdev));
David Woodhouse62edf5d2009-07-04 10:59:46 +01002459 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002460 }
2461
2462 return 0;
2463}
2464
Joseph Cihulab7792602011-05-03 00:08:37 -07002465static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002466{
2467 struct dmar_drhd_unit *drhd;
2468 struct dmar_rmrr_unit *rmrr;
2469 struct pci_dev *pdev;
2470 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002471 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002472
2473 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002474 * for each drhd
2475 * allocate root
2476 * initialize and program root entry to not present
2477 * endfor
2478 */
2479 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002480 /*
2481 * lock not needed as this is only incremented in the single
2482 * threaded kernel __init code path all other access are read
2483 * only
2484 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002485 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2486 g_num_of_iommus++;
2487 continue;
2488 }
2489 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2490 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002491 }
2492
Weidong Hand9630fe2008-12-08 11:06:32 +08002493 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2494 GFP_KERNEL);
2495 if (!g_iommus) {
2496 printk(KERN_ERR "Allocating global iommu array failed\n");
2497 ret = -ENOMEM;
2498 goto error;
2499 }
2500
mark gross80b20dd2008-04-18 13:53:58 -07002501 deferred_flush = kzalloc(g_num_of_iommus *
2502 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2503 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002504 ret = -ENOMEM;
Jiang Liu989d51f2014-02-19 14:07:21 +08002505 goto free_g_iommus;
mark gross5e0d2a62008-03-04 15:22:08 -08002506 }
2507
Jiang Liu7c919772014-01-06 14:18:18 +08002508 for_each_active_iommu(iommu, drhd) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002509 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002510
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002511 ret = iommu_init_domains(iommu);
2512 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002513 goto free_iommu;
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002514
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002515 /*
2516 * TBD:
2517 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002518 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002519 */
2520 ret = iommu_alloc_root_entry(iommu);
2521 if (ret) {
2522 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002523 goto free_iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002524 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002525 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002526 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002527 }
2528
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002529 /*
2530 * Start from the sane iommu hardware state.
2531 */
Jiang Liu7c919772014-01-06 14:18:18 +08002532 for_each_active_iommu(iommu, drhd) {
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002533 /*
2534 * If the queued invalidation is already initialized by us
2535 * (for example, while enabling interrupt-remapping) then
2536 * we got the things already rolling from a sane state.
2537 */
2538 if (iommu->qi)
2539 continue;
2540
2541 /*
2542 * Clear any previous faults.
2543 */
2544 dmar_fault(-1, iommu);
2545 /*
2546 * Disable queued invalidation if supported and already enabled
2547 * before OS handover.
2548 */
2549 dmar_disable_qi(iommu);
2550 }
2551
Jiang Liu7c919772014-01-06 14:18:18 +08002552 for_each_active_iommu(iommu, drhd) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002553 if (dmar_enable_qi(iommu)) {
2554 /*
2555 * Queued Invalidate not enabled, use Register Based
2556 * Invalidate
2557 */
2558 iommu->flush.flush_context = __iommu_flush_context;
2559 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002560 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002561 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002562 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002563 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002564 } else {
2565 iommu->flush.flush_context = qi_flush_context;
2566 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002567 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002568 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002569 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002570 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002571 }
2572 }
2573
David Woodhouse19943b02009-08-04 16:19:20 +01002574 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002575 iommu_identity_mapping |= IDENTMAP_ALL;
2576
Suresh Siddhad3f13812011-08-23 17:05:25 -07002577#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002578 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002579#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002580
2581 check_tylersburg_isoch();
2582
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002583 /*
2584 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002585 * identity mappings for rmrr, gfx, and isa and may fall back to static
2586 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002587 */
David Woodhouse19943b02009-08-04 16:19:20 +01002588 if (iommu_identity_mapping) {
2589 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2590 if (ret) {
2591 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002592 goto free_iommu;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002593 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002594 }
David Woodhouse19943b02009-08-04 16:19:20 +01002595 /*
2596 * For each rmrr
2597 * for each dev attached to rmrr
2598 * do
2599 * locate drhd for dev, alloc domain for dev
2600 * allocate free domain
2601 * allocate page table entries for rmrr
2602 * if context not allocated for bus
2603 * allocate and init context
2604 * set present in root table for this bus
2605 * init context with domain, translation etc
2606 * endfor
2607 * endfor
2608 */
2609 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2610 for_each_rmrr_units(rmrr) {
Jiang Liub683b232014-02-19 14:07:32 +08002611 /* some BIOS lists non-exist devices in DMAR table. */
2612 for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
2613 i, pdev) {
David Woodhouse19943b02009-08-04 16:19:20 +01002614 ret = iommu_prepare_rmrr_dev(rmrr, pdev);
2615 if (ret)
2616 printk(KERN_ERR
2617 "IOMMU: mapping reserved region failed\n");
2618 }
2619 }
2620
2621 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002622
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002623 /*
2624 * for each drhd
2625 * enable fault log
2626 * global invalidate context cache
2627 * global invalidate iotlb
2628 * enable translation
2629 */
Jiang Liu7c919772014-01-06 14:18:18 +08002630 for_each_iommu(iommu, drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002631 if (drhd->ignored) {
2632 /*
2633 * we always have to disable PMRs or DMA may fail on
2634 * this device
2635 */
2636 if (force_on)
Jiang Liu7c919772014-01-06 14:18:18 +08002637 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002638 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002639 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002640
2641 iommu_flush_write_buffer(iommu);
2642
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002643 ret = dmar_set_interrupt(iommu);
2644 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002645 goto free_iommu;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002646
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002647 iommu_set_root_entry(iommu);
2648
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002649 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002650 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
mark grossf8bab732008-02-08 04:18:38 -08002651
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002652 ret = iommu_enable_translation(iommu);
2653 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002654 goto free_iommu;
David Woodhouseb94996c2009-09-19 15:28:12 -07002655
2656 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002657 }
2658
2659 return 0;
Jiang Liu989d51f2014-02-19 14:07:21 +08002660
2661free_iommu:
Jiang Liu7c919772014-01-06 14:18:18 +08002662 for_each_active_iommu(iommu, drhd)
Jiang Liua868e6b2014-01-06 14:18:20 +08002663 free_dmar_iommu(iommu);
Jiang Liu9bdc5312014-01-06 14:18:27 +08002664 kfree(deferred_flush);
Jiang Liu989d51f2014-02-19 14:07:21 +08002665free_g_iommus:
Weidong Hand9630fe2008-12-08 11:06:32 +08002666 kfree(g_iommus);
Jiang Liu989d51f2014-02-19 14:07:21 +08002667error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002668 return ret;
2669}
2670
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002671/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002672static struct iova *intel_alloc_iova(struct device *dev,
2673 struct dmar_domain *domain,
2674 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002675{
2676 struct pci_dev *pdev = to_pci_dev(dev);
2677 struct iova *iova = NULL;
2678
David Woodhouse875764d2009-06-28 21:20:51 +01002679 /* Restrict dma_mask to the width that the iommu can handle */
2680 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2681
2682 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002683 /*
2684 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002685 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002686 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002687 */
David Woodhouse875764d2009-06-28 21:20:51 +01002688 iova = alloc_iova(&domain->iovad, nrpages,
2689 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2690 if (iova)
2691 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002692 }
David Woodhouse875764d2009-06-28 21:20:51 +01002693 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2694 if (unlikely(!iova)) {
2695 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
2696 nrpages, pci_name(pdev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002697 return NULL;
2698 }
2699
2700 return iova;
2701}
2702
David Woodhouse147202a2009-07-07 19:43:20 +01002703static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002704{
2705 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002706 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002707
2708 domain = get_domain_for_dev(pdev,
2709 DEFAULT_DOMAIN_ADDRESS_WIDTH);
2710 if (!domain) {
2711 printk(KERN_ERR
2712 "Allocating domain for %s failed", pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002713 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002714 }
2715
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002716 /* make sure context mapping is ok */
Weidong Han5331fe62008-12-08 23:00:00 +08002717 if (unlikely(!domain_context_mapped(pdev))) {
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002718 ret = domain_context_mapping(domain, pdev,
2719 CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002720 if (ret) {
2721 printk(KERN_ERR
2722 "Domain context map for %s failed",
2723 pci_name(pdev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002724 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002725 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002726 }
2727
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002728 return domain;
2729}
2730
David Woodhouse147202a2009-07-07 19:43:20 +01002731static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
2732{
2733 struct device_domain_info *info;
2734
2735 /* No lock here, assumes no domain exit in normal case */
2736 info = dev->dev.archdata.iommu;
2737 if (likely(info))
2738 return info->domain;
2739
2740 return __get_valid_domain_for_dev(dev);
2741}
2742
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002743static int iommu_dummy(struct pci_dev *pdev)
2744{
2745 return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
2746}
2747
2748/* Check if the pdev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002749static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002750{
David Woodhouse73676832009-07-04 14:08:36 +01002751 struct pci_dev *pdev;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002752 int found;
2753
Yijing Wangdbad0862013-12-05 19:43:42 +08002754 if (unlikely(!dev_is_pci(dev)))
David Woodhouse73676832009-07-04 14:08:36 +01002755 return 1;
2756
2757 pdev = to_pci_dev(dev);
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002758 if (iommu_dummy(pdev))
2759 return 1;
2760
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002761 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002762 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002763
2764 found = identity_mapping(pdev);
2765 if (found) {
David Woodhouse6941af22009-07-04 18:24:27 +01002766 if (iommu_should_identity_map(pdev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002767 return 1;
2768 else {
2769 /*
2770 * 32 bit DMA is removed from si_domain and fall back
2771 * to non-identity mapping.
2772 */
2773 domain_remove_one_dev_info(si_domain, pdev);
2774 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
2775 pci_name(pdev));
2776 return 0;
2777 }
2778 } else {
2779 /*
2780 * In case of a detached 64 bit DMA device from vm, the device
2781 * is put into si_domain for identity mapping.
2782 */
David Woodhouse6941af22009-07-04 18:24:27 +01002783 if (iommu_should_identity_map(pdev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002784 int ret;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002785 ret = domain_add_dev_info(si_domain, pdev,
2786 hw_pass_through ?
2787 CONTEXT_TT_PASS_THROUGH :
2788 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002789 if (!ret) {
2790 printk(KERN_INFO "64bit %s uses identity mapping\n",
2791 pci_name(pdev));
2792 return 1;
2793 }
2794 }
2795 }
2796
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002797 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002798}
2799
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002800static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
2801 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002802{
2803 struct pci_dev *pdev = to_pci_dev(hwdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002804 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002805 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002806 struct iova *iova;
2807 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002808 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08002809 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07002810 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002811
2812 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002813
David Woodhouse73676832009-07-04 14:08:36 +01002814 if (iommu_no_mapping(hwdev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002815 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002816
2817 domain = get_valid_domain_for_dev(pdev);
2818 if (!domain)
2819 return 0;
2820
Weidong Han8c11e792008-12-08 15:29:22 +08002821 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01002822 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002823
Mike Travisc681d0b2011-05-28 13:15:05 -05002824 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002825 if (!iova)
2826 goto error;
2827
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002828 /*
2829 * Check if DMAR supports zero-length reads on write only
2830 * mappings..
2831 */
2832 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08002833 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002834 prot |= DMA_PTE_READ;
2835 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
2836 prot |= DMA_PTE_WRITE;
2837 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002838 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002839 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02002840 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002841 * is not a big problem
2842 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01002843 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07002844 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002845 if (ret)
2846 goto error;
2847
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002848 /* it's a non-present to present mapping. Only flush if caching mode */
2849 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03002850 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002851 else
Weidong Han8c11e792008-12-08 15:29:22 +08002852 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002853
David Woodhouse03d6a242009-06-28 15:33:46 +01002854 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
2855 start_paddr += paddr & ~PAGE_MASK;
2856 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002857
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002858error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002859 if (iova)
2860 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00002861 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002862 pci_name(pdev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002863 return 0;
2864}
2865
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002866static dma_addr_t intel_map_page(struct device *dev, struct page *page,
2867 unsigned long offset, size_t size,
2868 enum dma_data_direction dir,
2869 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002870{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002871 return __intel_map_single(dev, page_to_phys(page) + offset, size,
2872 dir, to_pci_dev(dev)->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002873}
2874
mark gross5e0d2a62008-03-04 15:22:08 -08002875static void flush_unmaps(void)
2876{
mark gross80b20dd2008-04-18 13:53:58 -07002877 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08002878
mark gross5e0d2a62008-03-04 15:22:08 -08002879 timer_on = 0;
2880
2881 /* just flush them all */
2882 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08002883 struct intel_iommu *iommu = g_iommus[i];
2884 if (!iommu)
2885 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002886
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002887 if (!deferred_flush[i].next)
2888 continue;
2889
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002890 /* In caching mode, global flushes turn emulation expensive */
2891 if (!cap_caching_mode(iommu->cap))
2892 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08002893 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002894 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08002895 unsigned long mask;
2896 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002897 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08002898
Nadav Amit78d5f0f2010-04-08 23:00:41 +03002899 /* On real hardware multiple invalidations are expensive */
2900 if (cap_caching_mode(iommu->cap))
2901 iommu_flush_iotlb_psi(iommu, domain->id,
2902 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
2903 else {
2904 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
2905 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
2906 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
2907 }
Yu Zhao93a23a72009-05-18 13:51:37 +08002908 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
mark gross80b20dd2008-04-18 13:53:58 -07002909 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08002910 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002911 }
2912
mark gross5e0d2a62008-03-04 15:22:08 -08002913 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08002914}
2915
2916static void flush_unmaps_timeout(unsigned long data)
2917{
mark gross80b20dd2008-04-18 13:53:58 -07002918 unsigned long flags;
2919
2920 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002921 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07002922 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08002923}
2924
2925static void add_unmap(struct dmar_domain *dom, struct iova *iova)
2926{
2927 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07002928 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08002929 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08002930
2931 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07002932 if (list_size == HIGH_WATER_MARK)
2933 flush_unmaps();
2934
Weidong Han8c11e792008-12-08 15:29:22 +08002935 iommu = domain_get_iommu(dom);
2936 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07002937
mark gross80b20dd2008-04-18 13:53:58 -07002938 next = deferred_flush[iommu_id].next;
2939 deferred_flush[iommu_id].domain[next] = dom;
2940 deferred_flush[iommu_id].iova[next] = iova;
2941 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08002942
2943 if (!timer_on) {
2944 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
2945 timer_on = 1;
2946 }
2947 list_size++;
2948 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
2949}
2950
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09002951static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
2952 size_t size, enum dma_data_direction dir,
2953 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002954{
2955 struct pci_dev *pdev = to_pci_dev(dev);
2956 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01002957 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002958 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08002959 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002960
David Woodhouse73676832009-07-04 14:08:36 +01002961 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002962 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002963
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002964 domain = find_domain(pdev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002965 BUG_ON(!domain);
2966
Weidong Han8c11e792008-12-08 15:29:22 +08002967 iommu = domain_get_iommu(domain);
2968
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002969 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01002970 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
2971 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002972 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002973
David Woodhoused794dc92009-06-28 00:27:49 +01002974 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
2975 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002976
David Woodhoused794dc92009-06-28 00:27:49 +01002977 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
2978 pci_name(pdev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002979
2980 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01002981 dma_pte_clear_range(domain, start_pfn, last_pfn);
2982
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002983 /* free page tables */
David Woodhoused794dc92009-06-28 00:27:49 +01002984 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
2985
mark gross5e0d2a62008-03-04 15:22:08 -08002986 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01002987 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03002988 last_pfn - start_pfn + 1, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08002989 /* free iova */
2990 __free_iova(&domain->iovad, iova);
2991 } else {
2992 add_unmap(domain, iova);
2993 /*
2994 * queue up the release of the unmap to save the 1/6th of the
2995 * cpu used up by the iotlb flush operation...
2996 */
mark gross5e0d2a62008-03-04 15:22:08 -08002997 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002998}
2999
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003000static void *intel_alloc_coherent(struct device *hwdev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003001 dma_addr_t *dma_handle, gfp_t flags,
3002 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003003{
3004 void *vaddr;
3005 int order;
3006
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003007 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003008 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07003009
3010 if (!iommu_no_mapping(hwdev))
3011 flags &= ~(GFP_DMA | GFP_DMA32);
3012 else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
3013 if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
3014 flags |= GFP_DMA;
3015 else
3016 flags |= GFP_DMA32;
3017 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003018
3019 vaddr = (void *)__get_free_pages(flags, order);
3020 if (!vaddr)
3021 return NULL;
3022 memset(vaddr, 0, size);
3023
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003024 *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
3025 DMA_BIDIRECTIONAL,
3026 hwdev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003027 if (*dma_handle)
3028 return vaddr;
3029 free_pages((unsigned long)vaddr, order);
3030 return NULL;
3031}
3032
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003033static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003034 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003035{
3036 int order;
3037
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003038 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003039 order = get_order(size);
3040
David Woodhouse0db9b7a2009-07-14 02:01:57 +01003041 intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003042 free_pages((unsigned long)vaddr, order);
3043}
3044
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003045static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
3046 int nelems, enum dma_data_direction dir,
3047 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003048{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003049 struct pci_dev *pdev = to_pci_dev(hwdev);
3050 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003051 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003052 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003053 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003054
David Woodhouse73676832009-07-04 14:08:36 +01003055 if (iommu_no_mapping(hwdev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003056 return;
3057
3058 domain = find_domain(pdev);
Weidong Han8c11e792008-12-08 15:29:22 +08003059 BUG_ON(!domain);
3060
3061 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003062
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003063 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003064 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3065 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003066 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003067
David Woodhoused794dc92009-06-28 00:27:49 +01003068 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3069 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003070
3071 /* clear the whole page */
David Woodhoused794dc92009-06-28 00:27:49 +01003072 dma_pte_clear_range(domain, start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003073
David Woodhoused794dc92009-06-28 00:27:49 +01003074 /* free page tables */
3075 dma_pte_free_pagetable(domain, start_pfn, last_pfn);
3076
David Woodhouseacea0012009-07-14 01:55:11 +01003077 if (intel_iommu_strict) {
3078 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
Nadav Amit82653632010-04-01 13:24:40 +03003079 last_pfn - start_pfn + 1, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003080 /* free iova */
3081 __free_iova(&domain->iovad, iova);
3082 } else {
3083 add_unmap(domain, iova);
3084 /*
3085 * queue up the release of the unmap to save the 1/6th of the
3086 * cpu used up by the iotlb flush operation...
3087 */
3088 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003089}
3090
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003091static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003092 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003093{
3094 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003095 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003096
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003097 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003098 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003099 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003100 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003101 }
3102 return nelems;
3103}
3104
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003105static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
3106 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003107{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003108 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003109 struct pci_dev *pdev = to_pci_dev(hwdev);
3110 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003111 size_t size = 0;
3112 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003113 struct iova *iova = NULL;
3114 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003115 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003116 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003117 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003118
3119 BUG_ON(dir == DMA_NONE);
David Woodhouse73676832009-07-04 14:08:36 +01003120 if (iommu_no_mapping(hwdev))
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003121 return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003122
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003123 domain = get_valid_domain_for_dev(pdev);
3124 if (!domain)
3125 return 0;
3126
Weidong Han8c11e792008-12-08 15:29:22 +08003127 iommu = domain_get_iommu(domain);
3128
David Woodhouseb536d242009-06-28 14:49:31 +01003129 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003130 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003131
David Woodhouse5a5e02a2009-07-04 09:35:44 +01003132 iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
3133 pdev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003134 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003135 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003136 return 0;
3137 }
3138
3139 /*
3140 * Check if DMAR supports zero-length reads on write only
3141 * mappings..
3142 */
3143 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003144 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003145 prot |= DMA_PTE_READ;
3146 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3147 prot |= DMA_PTE_WRITE;
3148
David Woodhouseb536d242009-06-28 14:49:31 +01003149 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003150
Fenghua Yuf5329592009-08-04 15:09:37 -07003151 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003152 if (unlikely(ret)) {
3153 /* clear the page */
3154 dma_pte_clear_range(domain, start_vpfn,
3155 start_vpfn + size - 1);
3156 /* free page tables */
3157 dma_pte_free_pagetable(domain, start_vpfn,
3158 start_vpfn + size - 1);
3159 /* free iova */
3160 __free_iova(&domain->iovad, iova);
3161 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003162 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003163
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003164 /* it's a non-present to present mapping. Only flush if caching mode */
3165 if (cap_caching_mode(iommu->cap))
Nadav Amit82653632010-04-01 13:24:40 +03003166 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003167 else
Weidong Han8c11e792008-12-08 15:29:22 +08003168 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003169
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003170 return nelems;
3171}
3172
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003173static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3174{
3175 return !dma_addr;
3176}
3177
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003178struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003179 .alloc = intel_alloc_coherent,
3180 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003181 .map_sg = intel_map_sg,
3182 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003183 .map_page = intel_map_page,
3184 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003185 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003186};
3187
3188static inline int iommu_domain_cache_init(void)
3189{
3190 int ret = 0;
3191
3192 iommu_domain_cache = kmem_cache_create("iommu_domain",
3193 sizeof(struct dmar_domain),
3194 0,
3195 SLAB_HWCACHE_ALIGN,
3196
3197 NULL);
3198 if (!iommu_domain_cache) {
3199 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3200 ret = -ENOMEM;
3201 }
3202
3203 return ret;
3204}
3205
3206static inline int iommu_devinfo_cache_init(void)
3207{
3208 int ret = 0;
3209
3210 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3211 sizeof(struct device_domain_info),
3212 0,
3213 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003214 NULL);
3215 if (!iommu_devinfo_cache) {
3216 printk(KERN_ERR "Couldn't create devinfo cache\n");
3217 ret = -ENOMEM;
3218 }
3219
3220 return ret;
3221}
3222
3223static inline int iommu_iova_cache_init(void)
3224{
3225 int ret = 0;
3226
3227 iommu_iova_cache = kmem_cache_create("iommu_iova",
3228 sizeof(struct iova),
3229 0,
3230 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003231 NULL);
3232 if (!iommu_iova_cache) {
3233 printk(KERN_ERR "Couldn't create iova cache\n");
3234 ret = -ENOMEM;
3235 }
3236
3237 return ret;
3238}
3239
3240static int __init iommu_init_mempool(void)
3241{
3242 int ret;
3243 ret = iommu_iova_cache_init();
3244 if (ret)
3245 return ret;
3246
3247 ret = iommu_domain_cache_init();
3248 if (ret)
3249 goto domain_error;
3250
3251 ret = iommu_devinfo_cache_init();
3252 if (!ret)
3253 return ret;
3254
3255 kmem_cache_destroy(iommu_domain_cache);
3256domain_error:
3257 kmem_cache_destroy(iommu_iova_cache);
3258
3259 return -ENOMEM;
3260}
3261
3262static void __init iommu_exit_mempool(void)
3263{
3264 kmem_cache_destroy(iommu_devinfo_cache);
3265 kmem_cache_destroy(iommu_domain_cache);
3266 kmem_cache_destroy(iommu_iova_cache);
3267
3268}
3269
Dan Williams556ab452010-07-23 15:47:56 -07003270static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3271{
3272 struct dmar_drhd_unit *drhd;
3273 u32 vtbar;
3274 int rc;
3275
3276 /* We know that this device on this chipset has its own IOMMU.
3277 * If we find it under a different IOMMU, then the BIOS is lying
3278 * to us. Hope that the IOMMU for this device is actually
3279 * disabled, and it needs no translation...
3280 */
3281 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3282 if (rc) {
3283 /* "can't" happen */
3284 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3285 return;
3286 }
3287 vtbar &= 0xffff0000;
3288
3289 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3290 drhd = dmar_find_matched_drhd_unit(pdev);
3291 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3292 TAINT_FIRMWARE_WORKAROUND,
3293 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3294 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3295}
3296DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3297
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003298static void __init init_no_remapping_devices(void)
3299{
3300 struct dmar_drhd_unit *drhd;
Jiang Liub683b232014-02-19 14:07:32 +08003301 struct pci_dev *dev;
3302 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003303
3304 for_each_drhd_unit(drhd) {
3305 if (!drhd->include_all) {
Jiang Liub683b232014-02-19 14:07:32 +08003306 for_each_active_dev_scope(drhd->devices,
3307 drhd->devices_cnt, i, dev)
3308 break;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003309 /* ignore DMAR unit if no pci devices exist */
3310 if (i == drhd->devices_cnt)
3311 drhd->ignored = 1;
3312 }
3313 }
3314
Jiang Liu7c919772014-01-06 14:18:18 +08003315 for_each_active_drhd_unit(drhd) {
Jiang Liu7c919772014-01-06 14:18:18 +08003316 if (drhd->include_all)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003317 continue;
3318
Jiang Liub683b232014-02-19 14:07:32 +08003319 for_each_active_dev_scope(drhd->devices,
3320 drhd->devices_cnt, i, dev)
3321 if (!IS_GFX_DEVICE(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003322 break;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003323 if (i < drhd->devices_cnt)
3324 continue;
3325
David Woodhousec0771df2011-10-14 20:59:46 +01003326 /* This IOMMU has *only* gfx devices. Either bypass it or
3327 set the gfx_mapped flag, as appropriate */
3328 if (dmar_map_gfx) {
3329 intel_iommu_gfx_mapped = 1;
3330 } else {
3331 drhd->ignored = 1;
Jiang Liub683b232014-02-19 14:07:32 +08003332 for_each_active_dev_scope(drhd->devices,
3333 drhd->devices_cnt, i, dev)
3334 dev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003335 }
3336 }
3337}
3338
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003339#ifdef CONFIG_SUSPEND
3340static int init_iommu_hw(void)
3341{
3342 struct dmar_drhd_unit *drhd;
3343 struct intel_iommu *iommu = NULL;
3344
3345 for_each_active_iommu(iommu, drhd)
3346 if (iommu->qi)
3347 dmar_reenable_qi(iommu);
3348
Joseph Cihulab7792602011-05-03 00:08:37 -07003349 for_each_iommu(iommu, drhd) {
3350 if (drhd->ignored) {
3351 /*
3352 * we always have to disable PMRs or DMA may fail on
3353 * this device
3354 */
3355 if (force_on)
3356 iommu_disable_protect_mem_regions(iommu);
3357 continue;
3358 }
3359
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003360 iommu_flush_write_buffer(iommu);
3361
3362 iommu_set_root_entry(iommu);
3363
3364 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003365 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003366 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003367 DMA_TLB_GLOBAL_FLUSH);
Joseph Cihulab7792602011-05-03 00:08:37 -07003368 if (iommu_enable_translation(iommu))
3369 return 1;
David Woodhouseb94996c2009-09-19 15:28:12 -07003370 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003371 }
3372
3373 return 0;
3374}
3375
3376static void iommu_flush_all(void)
3377{
3378 struct dmar_drhd_unit *drhd;
3379 struct intel_iommu *iommu;
3380
3381 for_each_active_iommu(iommu, drhd) {
3382 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003383 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003384 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003385 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003386 }
3387}
3388
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003389static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003390{
3391 struct dmar_drhd_unit *drhd;
3392 struct intel_iommu *iommu = NULL;
3393 unsigned long flag;
3394
3395 for_each_active_iommu(iommu, drhd) {
3396 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3397 GFP_ATOMIC);
3398 if (!iommu->iommu_state)
3399 goto nomem;
3400 }
3401
3402 iommu_flush_all();
3403
3404 for_each_active_iommu(iommu, drhd) {
3405 iommu_disable_translation(iommu);
3406
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003407 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003408
3409 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3410 readl(iommu->reg + DMAR_FECTL_REG);
3411 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3412 readl(iommu->reg + DMAR_FEDATA_REG);
3413 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3414 readl(iommu->reg + DMAR_FEADDR_REG);
3415 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3416 readl(iommu->reg + DMAR_FEUADDR_REG);
3417
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003418 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003419 }
3420 return 0;
3421
3422nomem:
3423 for_each_active_iommu(iommu, drhd)
3424 kfree(iommu->iommu_state);
3425
3426 return -ENOMEM;
3427}
3428
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003429static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003430{
3431 struct dmar_drhd_unit *drhd;
3432 struct intel_iommu *iommu = NULL;
3433 unsigned long flag;
3434
3435 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003436 if (force_on)
3437 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3438 else
3439 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003440 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003441 }
3442
3443 for_each_active_iommu(iommu, drhd) {
3444
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003445 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003446
3447 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3448 iommu->reg + DMAR_FECTL_REG);
3449 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3450 iommu->reg + DMAR_FEDATA_REG);
3451 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3452 iommu->reg + DMAR_FEADDR_REG);
3453 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3454 iommu->reg + DMAR_FEUADDR_REG);
3455
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003456 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003457 }
3458
3459 for_each_active_iommu(iommu, drhd)
3460 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003461}
3462
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003463static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003464 .resume = iommu_resume,
3465 .suspend = iommu_suspend,
3466};
3467
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003468static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003469{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003470 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003471}
3472
3473#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003474static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003475#endif /* CONFIG_PM */
3476
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003477
3478int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3479{
3480 struct acpi_dmar_reserved_memory *rmrr;
3481 struct dmar_rmrr_unit *rmrru;
3482
3483 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3484 if (!rmrru)
3485 return -ENOMEM;
3486
3487 rmrru->hdr = header;
3488 rmrr = (struct acpi_dmar_reserved_memory *)header;
3489 rmrru->base_address = rmrr->base_address;
3490 rmrru->end_address = rmrr->end_address;
Jiang Liu2e455282014-02-19 14:07:36 +08003491 rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
3492 ((void *)rmrr) + rmrr->header.length,
3493 &rmrru->devices_cnt);
3494 if (rmrru->devices_cnt && rmrru->devices == NULL) {
3495 kfree(rmrru);
3496 return -ENOMEM;
3497 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003498
Jiang Liu2e455282014-02-19 14:07:36 +08003499 list_add(&rmrru->list, &dmar_rmrr_units);
3500
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003501 return 0;
3502}
3503
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003504int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3505{
3506 struct acpi_dmar_atsr *atsr;
3507 struct dmar_atsr_unit *atsru;
3508
3509 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3510 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3511 if (!atsru)
3512 return -ENOMEM;
3513
3514 atsru->hdr = hdr;
3515 atsru->include_all = atsr->flags & 0x1;
Jiang Liu2e455282014-02-19 14:07:36 +08003516 if (!atsru->include_all) {
3517 atsru->devices = dmar_alloc_dev_scope((void *)(atsr + 1),
3518 (void *)atsr + atsr->header.length,
3519 &atsru->devices_cnt);
3520 if (atsru->devices_cnt && atsru->devices == NULL) {
3521 kfree(atsru);
3522 return -ENOMEM;
3523 }
3524 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003525
Jiang Liu0e242612014-02-19 14:07:34 +08003526 list_add_rcu(&atsru->list, &dmar_atsr_units);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003527
3528 return 0;
3529}
3530
Jiang Liu9bdc5312014-01-06 14:18:27 +08003531static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
3532{
3533 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
3534 kfree(atsru);
3535}
3536
3537static void intel_iommu_free_dmars(void)
3538{
3539 struct dmar_rmrr_unit *rmrru, *rmrr_n;
3540 struct dmar_atsr_unit *atsru, *atsr_n;
3541
3542 list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
3543 list_del(&rmrru->list);
3544 dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
3545 kfree(rmrru);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003546 }
3547
Jiang Liu9bdc5312014-01-06 14:18:27 +08003548 list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
3549 list_del(&atsru->list);
3550 intel_iommu_free_atsr(atsru);
3551 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003552}
3553
3554int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3555{
Jiang Liub683b232014-02-19 14:07:32 +08003556 int i, ret = 1;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003557 struct pci_bus *bus;
Jiang Liub683b232014-02-19 14:07:32 +08003558 struct pci_dev *bridge = NULL, *tmp;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003559 struct acpi_dmar_atsr *atsr;
3560 struct dmar_atsr_unit *atsru;
3561
3562 dev = pci_physfn(dev);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003563 for (bus = dev->bus; bus; bus = bus->parent) {
Jiang Liub5f82dd2014-02-19 14:07:31 +08003564 bridge = bus->self;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003565 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003566 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003567 return 0;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003568 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003569 break;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003570 }
Jiang Liub5f82dd2014-02-19 14:07:31 +08003571 if (!bridge)
3572 return 0;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003573
Jiang Liu0e242612014-02-19 14:07:34 +08003574 rcu_read_lock();
Jiang Liub5f82dd2014-02-19 14:07:31 +08003575 list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
3576 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3577 if (atsr->segment != pci_domain_nr(dev->bus))
3578 continue;
3579
Jiang Liub683b232014-02-19 14:07:32 +08003580 for_each_dev_scope(atsru->devices, atsru->devices_cnt, i, tmp)
3581 if (tmp == bridge)
3582 goto out;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003583
3584 if (atsru->include_all)
Jiang Liub683b232014-02-19 14:07:32 +08003585 goto out;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003586 }
Jiang Liub683b232014-02-19 14:07:32 +08003587 ret = 0;
3588out:
Jiang Liu0e242612014-02-19 14:07:34 +08003589 rcu_read_unlock();
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003590
Jiang Liub683b232014-02-19 14:07:32 +08003591 return ret;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003592}
3593
Jiang Liu59ce0512014-02-19 14:07:35 +08003594int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
3595{
3596 int ret = 0;
3597 struct dmar_rmrr_unit *rmrru;
3598 struct dmar_atsr_unit *atsru;
3599 struct acpi_dmar_atsr *atsr;
3600 struct acpi_dmar_reserved_memory *rmrr;
3601
3602 if (!intel_iommu_enabled && system_state != SYSTEM_BOOTING)
3603 return 0;
3604
3605 list_for_each_entry(rmrru, &dmar_rmrr_units, list) {
3606 rmrr = container_of(rmrru->hdr,
3607 struct acpi_dmar_reserved_memory, header);
3608 if (info->event == BUS_NOTIFY_ADD_DEVICE) {
3609 ret = dmar_insert_dev_scope(info, (void *)(rmrr + 1),
3610 ((void *)rmrr) + rmrr->header.length,
3611 rmrr->segment, rmrru->devices,
3612 rmrru->devices_cnt);
3613 if (ret > 0)
3614 break;
3615 else if(ret < 0)
3616 return ret;
3617 } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
3618 if (dmar_remove_dev_scope(info, rmrr->segment,
3619 rmrru->devices, rmrru->devices_cnt))
3620 break;
3621 }
3622 }
3623
3624 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3625 if (atsru->include_all)
3626 continue;
3627
3628 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3629 if (info->event == BUS_NOTIFY_ADD_DEVICE) {
3630 ret = dmar_insert_dev_scope(info, (void *)(atsr + 1),
3631 (void *)atsr + atsr->header.length,
3632 atsr->segment, atsru->devices,
3633 atsru->devices_cnt);
3634 if (ret > 0)
3635 break;
3636 else if(ret < 0)
3637 return ret;
3638 } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
3639 if (dmar_remove_dev_scope(info, atsr->segment,
3640 atsru->devices, atsru->devices_cnt))
3641 break;
3642 }
3643 }
3644
3645 return 0;
3646}
3647
Fenghua Yu99dcade2009-11-11 07:23:06 -08003648/*
3649 * Here we only respond to action of unbound device from driver.
3650 *
3651 * Added device is not attached to its DMAR domain here yet. That will happen
3652 * when mapping the device to iova.
3653 */
3654static int device_notifier(struct notifier_block *nb,
3655 unsigned long action, void *data)
3656{
3657 struct device *dev = data;
3658 struct pci_dev *pdev = to_pci_dev(dev);
3659 struct dmar_domain *domain;
3660
Jiang Liu816997d2014-02-19 14:07:22 +08003661 if (iommu_dummy(pdev))
David Woodhouse44cd6132009-12-02 10:18:30 +00003662 return 0;
3663
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003664 if (action != BUS_NOTIFY_UNBOUND_DRIVER &&
3665 action != BUS_NOTIFY_DEL_DEVICE)
3666 return 0;
3667
Fenghua Yu99dcade2009-11-11 07:23:06 -08003668 domain = find_domain(pdev);
3669 if (!domain)
3670 return 0;
3671
Jiang Liu3a5670e2014-02-19 14:07:33 +08003672 down_read(&dmar_global_lock);
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003673 domain_remove_one_dev_info(domain, pdev);
3674 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3675 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
3676 list_empty(&domain->devices))
3677 domain_exit(domain);
Jiang Liu3a5670e2014-02-19 14:07:33 +08003678 up_read(&dmar_global_lock);
Alex Williamsona97590e2011-03-04 14:52:16 -07003679
Fenghua Yu99dcade2009-11-11 07:23:06 -08003680 return 0;
3681}
3682
3683static struct notifier_block device_nb = {
3684 .notifier_call = device_notifier,
3685};
3686
Jiang Liu75f05562014-02-19 14:07:37 +08003687static int intel_iommu_memory_notifier(struct notifier_block *nb,
3688 unsigned long val, void *v)
3689{
3690 struct memory_notify *mhp = v;
3691 unsigned long long start, end;
3692 unsigned long start_vpfn, last_vpfn;
3693
3694 switch (val) {
3695 case MEM_GOING_ONLINE:
3696 start = mhp->start_pfn << PAGE_SHIFT;
3697 end = ((mhp->start_pfn + mhp->nr_pages) << PAGE_SHIFT) - 1;
3698 if (iommu_domain_identity_map(si_domain, start, end)) {
3699 pr_warn("dmar: failed to build identity map for [%llx-%llx]\n",
3700 start, end);
3701 return NOTIFY_BAD;
3702 }
3703 break;
3704
3705 case MEM_OFFLINE:
3706 case MEM_CANCEL_ONLINE:
3707 start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
3708 last_vpfn = mm_to_dma_pfn(mhp->start_pfn + mhp->nr_pages - 1);
3709 while (start_vpfn <= last_vpfn) {
3710 struct iova *iova;
3711 struct dmar_drhd_unit *drhd;
3712 struct intel_iommu *iommu;
3713
3714 iova = find_iova(&si_domain->iovad, start_vpfn);
3715 if (iova == NULL) {
3716 pr_debug("dmar: failed get IOVA for PFN %lx\n",
3717 start_vpfn);
3718 break;
3719 }
3720
3721 iova = split_and_remove_iova(&si_domain->iovad, iova,
3722 start_vpfn, last_vpfn);
3723 if (iova == NULL) {
3724 pr_warn("dmar: failed to split IOVA PFN [%lx-%lx]\n",
3725 start_vpfn, last_vpfn);
3726 return NOTIFY_BAD;
3727 }
3728
3729 rcu_read_lock();
3730 for_each_active_iommu(iommu, drhd)
3731 iommu_flush_iotlb_psi(iommu, si_domain->id,
3732 iova->pfn_lo,
3733 iova->pfn_hi - iova->pfn_lo + 1, 0);
3734 rcu_read_unlock();
3735 dma_pte_clear_range(si_domain, iova->pfn_lo,
3736 iova->pfn_hi);
3737 dma_pte_free_pagetable(si_domain, iova->pfn_lo,
3738 iova->pfn_hi);
3739
3740 start_vpfn = iova->pfn_hi + 1;
3741 free_iova_mem(iova);
3742 }
3743 break;
3744 }
3745
3746 return NOTIFY_OK;
3747}
3748
3749static struct notifier_block intel_iommu_memory_nb = {
3750 .notifier_call = intel_iommu_memory_notifier,
3751 .priority = 0
3752};
3753
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003754int __init intel_iommu_init(void)
3755{
Jiang Liu9bdc5312014-01-06 14:18:27 +08003756 int ret = -ENODEV;
Takao Indoh3a93c842013-04-23 17:35:03 +09003757 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +08003758 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003759
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003760 /* VT-d is required for a TXT/tboot launch, so enforce that */
3761 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003762
Jiang Liu3a5670e2014-02-19 14:07:33 +08003763 if (iommu_init_mempool()) {
3764 if (force_on)
3765 panic("tboot: Failed to initialize iommu memory\n");
3766 return -ENOMEM;
3767 }
3768
3769 down_write(&dmar_global_lock);
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003770 if (dmar_table_init()) {
3771 if (force_on)
3772 panic("tboot: Failed to initialize DMAR table\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003773 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003774 }
3775
Takao Indoh3a93c842013-04-23 17:35:03 +09003776 /*
3777 * Disable translation if already enabled prior to OS handover.
3778 */
Jiang Liu7c919772014-01-06 14:18:18 +08003779 for_each_active_iommu(iommu, drhd)
Takao Indoh3a93c842013-04-23 17:35:03 +09003780 if (iommu->gcmd & DMA_GCMD_TE)
3781 iommu_disable_translation(iommu);
Takao Indoh3a93c842013-04-23 17:35:03 +09003782
Suresh Siddhac2c72862011-08-23 17:05:19 -07003783 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003784 if (force_on)
3785 panic("tboot: Failed to initialize DMAR device scope\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003786 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003787 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07003788
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003789 if (no_iommu || dmar_disabled)
Jiang Liu9bdc5312014-01-06 14:18:27 +08003790 goto out_free_dmar;
Suresh Siddha2ae21012008-07-10 11:16:43 -07003791
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003792 if (list_empty(&dmar_rmrr_units))
3793 printk(KERN_INFO "DMAR: No RMRR found\n");
3794
3795 if (list_empty(&dmar_atsr_units))
3796 printk(KERN_INFO "DMAR: No ATSR found\n");
3797
Joseph Cihula51a63e62011-03-21 11:04:24 -07003798 if (dmar_init_reserved_ranges()) {
3799 if (force_on)
3800 panic("tboot: Failed to reserve iommu ranges\n");
Jiang Liu3a5670e2014-02-19 14:07:33 +08003801 goto out_free_reserved_range;
Joseph Cihula51a63e62011-03-21 11:04:24 -07003802 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003803
3804 init_no_remapping_devices();
3805
Joseph Cihulab7792602011-05-03 00:08:37 -07003806 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003807 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07003808 if (force_on)
3809 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003810 printk(KERN_ERR "IOMMU: dmar init failed\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08003811 goto out_free_reserved_range;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003812 }
Jiang Liu3a5670e2014-02-19 14:07:33 +08003813 up_write(&dmar_global_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003814 printk(KERN_INFO
3815 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
3816
mark gross5e0d2a62008-03-04 15:22:08 -08003817 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09003818#ifdef CONFIG_SWIOTLB
3819 swiotlb = 0;
3820#endif
David Woodhouse19943b02009-08-04 16:19:20 +01003821 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07003822
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003823 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01003824
Joerg Roedel4236d97d2011-09-06 17:56:07 +02003825 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Fenghua Yu99dcade2009-11-11 07:23:06 -08003826 bus_register_notifier(&pci_bus_type, &device_nb);
Jiang Liu75f05562014-02-19 14:07:37 +08003827 if (si_domain && !hw_pass_through)
3828 register_memory_notifier(&intel_iommu_memory_nb);
Fenghua Yu99dcade2009-11-11 07:23:06 -08003829
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02003830 intel_iommu_enabled = 1;
3831
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003832 return 0;
Jiang Liu9bdc5312014-01-06 14:18:27 +08003833
3834out_free_reserved_range:
3835 put_iova_domain(&reserved_iova_list);
Jiang Liu9bdc5312014-01-06 14:18:27 +08003836out_free_dmar:
3837 intel_iommu_free_dmars();
Jiang Liu3a5670e2014-02-19 14:07:33 +08003838 up_write(&dmar_global_lock);
3839 iommu_exit_mempool();
Jiang Liu9bdc5312014-01-06 14:18:27 +08003840 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003841}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07003842
Han, Weidong3199aa62009-02-26 17:31:12 +08003843static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
3844 struct pci_dev *pdev)
3845{
3846 struct pci_dev *tmp, *parent;
3847
3848 if (!iommu || !pdev)
3849 return;
3850
3851 /* dependent device detach */
3852 tmp = pci_find_upstream_pcie_bridge(pdev);
3853 /* Secondary interface's bus number and devfn 0 */
3854 if (tmp) {
3855 parent = pdev->bus->self;
3856 while (parent != tmp) {
3857 iommu_detach_dev(iommu, parent->bus->number,
David Woodhouse276dbf992009-04-04 01:45:37 +01003858 parent->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003859 parent = parent->bus->self;
3860 }
Stefan Assmann45e829e2009-12-03 06:49:24 -05003861 if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */
Han, Weidong3199aa62009-02-26 17:31:12 +08003862 iommu_detach_dev(iommu,
3863 tmp->subordinate->number, 0);
3864 else /* this is a legacy PCI bridge */
David Woodhouse276dbf992009-04-04 01:45:37 +01003865 iommu_detach_dev(iommu, tmp->bus->number,
3866 tmp->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003867 }
3868}
3869
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003870static void domain_remove_one_dev_info(struct dmar_domain *domain,
Weidong Hanc7151a82008-12-08 22:51:37 +08003871 struct pci_dev *pdev)
3872{
Yijing Wangbca2b912013-10-31 17:26:04 +08003873 struct device_domain_info *info, *tmp;
Weidong Hanc7151a82008-12-08 22:51:37 +08003874 struct intel_iommu *iommu;
3875 unsigned long flags;
3876 int found = 0;
Weidong Hanc7151a82008-12-08 22:51:37 +08003877
David Woodhouse276dbf992009-04-04 01:45:37 +01003878 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
3879 pdev->devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08003880 if (!iommu)
3881 return;
3882
3883 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wangbca2b912013-10-31 17:26:04 +08003884 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
Mike Habeck8519dc42011-05-28 13:15:07 -05003885 if (info->segment == pci_domain_nr(pdev->bus) &&
3886 info->bus == pdev->bus->number &&
Weidong Hanc7151a82008-12-08 22:51:37 +08003887 info->devfn == pdev->devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01003888 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003889 spin_unlock_irqrestore(&device_domain_lock, flags);
3890
Yu Zhao93a23a72009-05-18 13:51:37 +08003891 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08003892 iommu_detach_dev(iommu, info->bus, info->devfn);
Han, Weidong3199aa62009-02-26 17:31:12 +08003893 iommu_detach_dependent_devices(iommu, pdev);
Weidong Hanc7151a82008-12-08 22:51:37 +08003894 free_devinfo_mem(info);
3895
3896 spin_lock_irqsave(&device_domain_lock, flags);
3897
3898 if (found)
3899 break;
3900 else
3901 continue;
3902 }
3903
3904 /* if there is no other devices under the same iommu
3905 * owned by this domain, clear this iommu in iommu_bmp
3906 * update iommu count and coherency
3907 */
David Woodhouse276dbf992009-04-04 01:45:37 +01003908 if (iommu == device_to_iommu(info->segment, info->bus,
3909 info->devfn))
Weidong Hanc7151a82008-12-08 22:51:37 +08003910 found = 1;
3911 }
3912
Roland Dreier3e7abe22011-07-20 06:22:21 -07003913 spin_unlock_irqrestore(&device_domain_lock, flags);
3914
Weidong Hanc7151a82008-12-08 22:51:37 +08003915 if (found == 0) {
3916 unsigned long tmp_flags;
3917 spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
Mike Travis1b198bb2012-03-05 15:05:16 -08003918 clear_bit(iommu->seq_id, domain->iommu_bmp);
Weidong Hanc7151a82008-12-08 22:51:37 +08003919 domain->iommu_count--;
Sheng Yang58c610b2009-03-18 15:33:05 +08003920 domain_update_iommu_cap(domain);
Weidong Hanc7151a82008-12-08 22:51:37 +08003921 spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
Alex Williamsona97590e2011-03-04 14:52:16 -07003922
Alex Williamson9b4554b2011-05-24 12:19:04 -04003923 if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
3924 !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
3925 spin_lock_irqsave(&iommu->lock, tmp_flags);
3926 clear_bit(domain->id, iommu->domain_ids);
3927 iommu->domains[domain->id] = NULL;
3928 spin_unlock_irqrestore(&iommu->lock, tmp_flags);
3929 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003930 }
Weidong Hanc7151a82008-12-08 22:51:37 +08003931}
3932
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003933static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08003934{
3935 int adjust_width;
3936
3937 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003938 domain_reserve_special_ranges(domain);
3939
3940 /* calculate AGAW */
3941 domain->gaw = guest_width;
3942 adjust_width = guestwidth_to_adjustwidth(guest_width);
3943 domain->agaw = width_to_agaw(adjust_width);
3944
Weidong Han5e98c4b2008-12-08 23:03:27 +08003945 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08003946 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01003947 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003948 domain->max_addr = 0;
Suresh Siddha4c923d42009-10-02 11:01:24 -07003949 domain->nid = -1;
Weidong Han5e98c4b2008-12-08 23:03:27 +08003950
3951 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07003952 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08003953 if (!domain->pgd)
3954 return -ENOMEM;
3955 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
3956 return 0;
3957}
3958
Joerg Roedel5d450802008-12-03 14:52:32 +01003959static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003960{
Joerg Roedel5d450802008-12-03 14:52:32 +01003961 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03003962
Jiang Liu92d03cc2014-02-19 14:07:28 +08003963 dmar_domain = alloc_domain(true);
Joerg Roedel5d450802008-12-03 14:52:32 +01003964 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03003965 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003966 "intel_iommu_domain_init: dmar_domain == NULL\n");
3967 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003968 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003969 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03003970 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01003971 "intel_iommu_domain_init() failed\n");
Jiang Liu92d03cc2014-02-19 14:07:28 +08003972 domain_exit(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003973 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03003974 }
Allen Kay8140a952011-10-14 12:32:17 -07003975 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01003976 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08003977
Joerg Roedel8a0e7152012-01-26 19:40:54 +01003978 domain->geometry.aperture_start = 0;
3979 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
3980 domain->geometry.force_aperture = true;
3981
Joerg Roedel5d450802008-12-03 14:52:32 +01003982 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03003983}
Kay, Allen M38717942008-09-09 18:37:29 +03003984
Joerg Roedel5d450802008-12-03 14:52:32 +01003985static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03003986{
Joerg Roedel5d450802008-12-03 14:52:32 +01003987 struct dmar_domain *dmar_domain = domain->priv;
3988
3989 domain->priv = NULL;
Jiang Liu92d03cc2014-02-19 14:07:28 +08003990 domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03003991}
Kay, Allen M38717942008-09-09 18:37:29 +03003992
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003993static int intel_iommu_attach_device(struct iommu_domain *domain,
3994 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03003995{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01003996 struct dmar_domain *dmar_domain = domain->priv;
3997 struct pci_dev *pdev = to_pci_dev(dev);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08003998 struct intel_iommu *iommu;
3999 int addr_width;
Kay, Allen M38717942008-09-09 18:37:29 +03004000
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004001 /* normally pdev is not mapped */
4002 if (unlikely(domain_context_mapped(pdev))) {
4003 struct dmar_domain *old_domain;
4004
4005 old_domain = find_domain(pdev);
4006 if (old_domain) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004007 if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
4008 dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
4009 domain_remove_one_dev_info(old_domain, pdev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004010 else
4011 domain_remove_dev_info(old_domain);
4012 }
4013 }
4014
David Woodhouse276dbf992009-04-04 01:45:37 +01004015 iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number,
4016 pdev->devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004017 if (!iommu)
4018 return -ENODEV;
4019
4020 /* check if this iommu agaw is sufficient for max mapped address */
4021 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01004022 if (addr_width > cap_mgaw(iommu->cap))
4023 addr_width = cap_mgaw(iommu->cap);
4024
4025 if (dmar_domain->max_addr > (1LL << addr_width)) {
4026 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004027 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01004028 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004029 return -EFAULT;
4030 }
Tom Lyona99c47a2010-05-17 08:20:45 +01004031 dmar_domain->gaw = addr_width;
4032
4033 /*
4034 * Knock out extra levels of page tables if necessary
4035 */
4036 while (iommu->agaw < dmar_domain->agaw) {
4037 struct dma_pte *pte;
4038
4039 pte = dmar_domain->pgd;
4040 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08004041 dmar_domain->pgd = (struct dma_pte *)
4042 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01004043 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01004044 }
4045 dmar_domain->agaw--;
4046 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004047
David Woodhouse5fe60f42009-08-09 10:53:41 +01004048 return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004049}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004050
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004051static void intel_iommu_detach_device(struct iommu_domain *domain,
4052 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004053{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004054 struct dmar_domain *dmar_domain = domain->priv;
4055 struct pci_dev *pdev = to_pci_dev(dev);
4056
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004057 domain_remove_one_dev_info(dmar_domain, pdev);
Kay, Allen M38717942008-09-09 18:37:29 +03004058}
Kay, Allen M38717942008-09-09 18:37:29 +03004059
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004060static int intel_iommu_map(struct iommu_domain *domain,
4061 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004062 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03004063{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004064 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004065 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004066 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004067 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004068
Joerg Roedeldde57a22008-12-03 15:04:09 +01004069 if (iommu_prot & IOMMU_READ)
4070 prot |= DMA_PTE_READ;
4071 if (iommu_prot & IOMMU_WRITE)
4072 prot |= DMA_PTE_WRITE;
Sheng Yang9cf066972009-03-18 15:33:07 +08004073 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4074 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004075
David Woodhouse163cc522009-06-28 00:51:17 +01004076 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004077 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004078 u64 end;
4079
4080 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01004081 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004082 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004083 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004084 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004085 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004086 return -EFAULT;
4087 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004088 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004089 }
David Woodhousead051222009-06-28 14:22:28 +01004090 /* Round up size to next multiple of PAGE_SIZE, if it and
4091 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004092 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004093 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4094 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004095 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004096}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004097
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004098static size_t intel_iommu_unmap(struct iommu_domain *domain,
4099 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004100{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004101 struct dmar_domain *dmar_domain = domain->priv;
Allen Kay292827c2011-10-14 12:31:54 -07004102 int order;
Sheng Yang4b99d352009-07-08 11:52:52 +01004103
Allen Kay292827c2011-10-14 12:31:54 -07004104 order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
David Woodhouse163cc522009-06-28 00:51:17 +01004105 (iova + size - 1) >> VTD_PAGE_SHIFT);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004106
David Woodhouse163cc522009-06-28 00:51:17 +01004107 if (dmar_domain->max_addr == iova + size)
4108 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004109
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004110 return PAGE_SIZE << order;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004111}
Kay, Allen M38717942008-09-09 18:37:29 +03004112
Joerg Roedeld14d6572008-12-03 15:06:57 +01004113static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
Varun Sethibb5547ac2013-03-29 01:23:58 +05304114 dma_addr_t iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004115{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004116 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004117 struct dma_pte *pte;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004118 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004119
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004120 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
Kay, Allen M38717942008-09-09 18:37:29 +03004121 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004122 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004123
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004124 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004125}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004126
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004127static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4128 unsigned long cap)
4129{
4130 struct dmar_domain *dmar_domain = domain->priv;
4131
4132 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4133 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004134 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004135 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004136
4137 return 0;
4138}
4139
Alex Williamson783f1572012-05-30 14:19:43 -06004140#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4141
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004142static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004143{
4144 struct pci_dev *pdev = to_pci_dev(dev);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004145 struct pci_dev *bridge, *dma_pdev = NULL;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004146 struct iommu_group *group;
4147 int ret;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004148
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004149 if (!device_to_iommu(pci_domain_nr(pdev->bus),
4150 pdev->bus->number, pdev->devfn))
Alex Williamson70ae6f02011-10-21 15:56:11 -04004151 return -ENODEV;
4152
4153 bridge = pci_find_upstream_pcie_bridge(pdev);
4154 if (bridge) {
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004155 if (pci_is_pcie(bridge))
4156 dma_pdev = pci_get_domain_bus_and_slot(
4157 pci_domain_nr(pdev->bus),
4158 bridge->subordinate->number, 0);
Alex Williamson3da4af0a2012-11-13 10:22:03 -07004159 if (!dma_pdev)
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004160 dma_pdev = pci_dev_get(bridge);
4161 } else
4162 dma_pdev = pci_dev_get(pdev);
4163
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004164 /* Account for quirked devices */
Alex Williamson783f1572012-05-30 14:19:43 -06004165 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4166
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004167 /*
4168 * If it's a multifunction device that does not support our
Alex Williamsonc14d2692013-05-30 12:39:18 -06004169 * required ACS flags, add to the same group as lowest numbered
4170 * function that also does not suport the required ACS flags.
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004171 */
Alex Williamson783f1572012-05-30 14:19:43 -06004172 if (dma_pdev->multifunction &&
Alex Williamsonc14d2692013-05-30 12:39:18 -06004173 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
4174 u8 i, slot = PCI_SLOT(dma_pdev->devfn);
4175
4176 for (i = 0; i < 8; i++) {
4177 struct pci_dev *tmp;
4178
4179 tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
4180 if (!tmp)
4181 continue;
4182
4183 if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
4184 swap_pci_ref(&dma_pdev, tmp);
4185 break;
4186 }
4187 pci_dev_put(tmp);
4188 }
4189 }
Alex Williamson783f1572012-05-30 14:19:43 -06004190
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004191 /*
4192 * Devices on the root bus go through the iommu. If that's not us,
4193 * find the next upstream device and test ACS up to the root bus.
4194 * Finding the next device may require skipping virtual buses.
4195 */
Alex Williamson783f1572012-05-30 14:19:43 -06004196 while (!pci_is_root_bus(dma_pdev->bus)) {
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004197 struct pci_bus *bus = dma_pdev->bus;
4198
4199 while (!bus->self) {
4200 if (!pci_is_root_bus(bus))
4201 bus = bus->parent;
4202 else
4203 goto root_bus;
4204 }
4205
4206 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
Alex Williamson783f1572012-05-30 14:19:43 -06004207 break;
4208
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004209 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
Alex Williamson70ae6f02011-10-21 15:56:11 -04004210 }
4211
Alex Williamsona4ff1fc2012-08-04 12:08:55 -06004212root_bus:
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004213 group = iommu_group_get(&dma_pdev->dev);
4214 pci_dev_put(dma_pdev);
4215 if (!group) {
4216 group = iommu_group_alloc();
4217 if (IS_ERR(group))
4218 return PTR_ERR(group);
4219 }
Alex Williamsonbcb71ab2011-10-21 15:56:24 -04004220
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004221 ret = iommu_group_add_device(group, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004222
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004223 iommu_group_put(group);
4224 return ret;
4225}
4226
4227static void intel_iommu_remove_device(struct device *dev)
4228{
4229 iommu_group_remove_device(dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004230}
4231
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004232static struct iommu_ops intel_iommu_ops = {
4233 .domain_init = intel_iommu_domain_init,
4234 .domain_destroy = intel_iommu_domain_destroy,
4235 .attach_dev = intel_iommu_attach_device,
4236 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004237 .map = intel_iommu_map,
4238 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004239 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004240 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004241 .add_device = intel_iommu_add_device,
4242 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004243 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004244};
David Woodhouse9af88142009-02-13 23:18:03 +00004245
Daniel Vetter94526182013-01-20 23:50:13 +01004246static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4247{
4248 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4249 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4250 dmar_map_gfx = 0;
4251}
4252
4253DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4254DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4255DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4256DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4257DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4258DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4259DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4260
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004261static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004262{
4263 /*
4264 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004265 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004266 */
4267 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4268 rwbf_quirk = 1;
4269}
4270
4271DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004272DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4273DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4274DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4275DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4276DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4277DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004278
Adam Jacksoneecfd572010-08-25 21:17:34 +01004279#define GGC 0x52
4280#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4281#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4282#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4283#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4284#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4285#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4286#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4287#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4288
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004289static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004290{
4291 unsigned short ggc;
4292
Adam Jacksoneecfd572010-08-25 21:17:34 +01004293 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004294 return;
4295
Adam Jacksoneecfd572010-08-25 21:17:34 +01004296 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004297 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4298 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004299 } else if (dmar_map_gfx) {
4300 /* we have to ensure the gfx device is idle before we flush */
4301 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4302 intel_iommu_strict = 1;
4303 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004304}
4305DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4306DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4307DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4308DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4309
David Woodhousee0fc7e02009-09-30 09:12:17 -07004310/* On Tylersburg chipsets, some BIOSes have been known to enable the
4311 ISOCH DMAR unit for the Azalia sound device, but not give it any
4312 TLB entries, which causes it to deadlock. Check for that. We do
4313 this in a function called from init_dmars(), instead of in a PCI
4314 quirk, because we don't want to print the obnoxious "BIOS broken"
4315 message if VT-d is actually disabled.
4316*/
4317static void __init check_tylersburg_isoch(void)
4318{
4319 struct pci_dev *pdev;
4320 uint32_t vtisochctrl;
4321
4322 /* If there's no Azalia in the system anyway, forget it. */
4323 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4324 if (!pdev)
4325 return;
4326 pci_dev_put(pdev);
4327
4328 /* System Management Registers. Might be hidden, in which case
4329 we can't do the sanity check. But that's OK, because the
4330 known-broken BIOSes _don't_ actually hide it, so far. */
4331 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4332 if (!pdev)
4333 return;
4334
4335 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4336 pci_dev_put(pdev);
4337 return;
4338 }
4339
4340 pci_dev_put(pdev);
4341
4342 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4343 if (vtisochctrl & 1)
4344 return;
4345
4346 /* Drop all bits other than the number of TLB entries */
4347 vtisochctrl &= 0x1c;
4348
4349 /* If we have the recommended number of TLB entries (16), fine. */
4350 if (vtisochctrl == 0x10)
4351 return;
4352
4353 /* Zero TLB entries? You get to ride the short bus to school. */
4354 if (!vtisochctrl) {
4355 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4356 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4357 dmi_get_system_info(DMI_BIOS_VENDOR),
4358 dmi_get_system_info(DMI_BIOS_VERSION),
4359 dmi_get_system_info(DMI_PRODUCT_VERSION));
4360 iommu_identity_mapping |= IDENTMAP_AZALIA;
4361 return;
4362 }
4363
4364 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4365 vtisochctrl);
4366}