blob: 0ba078bc0f32e70dd67a3226ac5faefcafcdeba3 [file] [log] [blame]
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001/*
David Woodhouseea8ea462014-03-05 17:09:32 +00002 * Copyright © 2006-2014 Intel Corporation.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003 *
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 *
David Woodhouseea8ea462014-03-05 17:09:32 +000013 * Authors: David Woodhouse <dwmw2@infradead.org>,
14 * Ashok Raj <ashok.raj@intel.com>,
15 * Shaohua Li <shaohua.li@intel.com>,
16 * Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>,
17 * Fenghua Yu <fenghua.yu@intel.com>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070018 */
19
20#include <linux/init.h>
21#include <linux/bitmap.h>
mark gross5e0d2a62008-03-04 15:22:08 -080022#include <linux/debugfs.h>
Paul Gortmaker54485c32011-10-29 10:26:25 -040023#include <linux/export.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070024#include <linux/slab.h>
25#include <linux/irq.h>
26#include <linux/interrupt.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070027#include <linux/spinlock.h>
28#include <linux/pci.h>
29#include <linux/dmar.h>
30#include <linux/dma-mapping.h>
31#include <linux/mempool.h>
Jiang Liu75f05562014-02-19 14:07:37 +080032#include <linux/memory.h>
mark gross5e0d2a62008-03-04 15:22:08 -080033#include <linux/timer.h>
Kay, Allen M38717942008-09-09 18:37:29 +030034#include <linux/iova.h>
Joerg Roedel5d450802008-12-03 14:52:32 +010035#include <linux/iommu.h>
Kay, Allen M38717942008-09-09 18:37:29 +030036#include <linux/intel-iommu.h>
Rafael J. Wysocki134fac32011-03-23 22:16:14 +010037#include <linux/syscore_ops.h>
Shane Wang69575d32009-09-01 18:25:07 -070038#include <linux/tboot.h>
Stephen Rothwelladb2fe02009-08-31 15:24:23 +100039#include <linux/dmi.h>
Joerg Roedel5cdede22011-04-04 15:55:18 +020040#include <linux/pci-ats.h>
Tejun Heo0ee332c2011-12-08 10:22:09 -080041#include <linux/memblock.h>
Akinobu Mita36746432014-06-04 16:06:51 -070042#include <linux/dma-contiguous.h>
Suresh Siddha8a8f4222012-03-30 11:47:08 -070043#include <asm/irq_remapping.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070044#include <asm/cacheflush.h>
FUJITA Tomonori46a7fa22008-07-11 10:23:42 +090045#include <asm/iommu.h>
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070046
Joerg Roedel078e1ee2012-09-26 12:44:43 +020047#include "irq_remapping.h"
48
Fenghua Yu5b6985c2008-10-16 18:02:32 -070049#define ROOT_SIZE VTD_PAGE_SIZE
50#define CONTEXT_SIZE VTD_PAGE_SIZE
51
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070052#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
53#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
David Woodhousee0fc7e02009-09-30 09:12:17 -070054#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070055
56#define IOAPIC_RANGE_START (0xfee00000)
57#define IOAPIC_RANGE_END (0xfeefffff)
58#define IOVA_START_ADDR (0x1000)
59
60#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
61
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070062#define MAX_AGAW_WIDTH 64
Jiang Liu5c645b32014-01-06 14:18:12 +080063#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -070064
David Woodhouse2ebe3152009-09-19 07:34:04 -070065#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
66#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
67
68/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
69 to match. That way, we can use 'unsigned long' for PFNs with impunity. */
70#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
71 __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
72#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -070073
Mark McLoughlinf27be032008-11-20 15:49:43 +000074#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
Yang Hongyang284901a2009-04-06 19:01:15 -070075#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
Yang Hongyang6a355282009-04-06 19:01:13 -070076#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
mark gross5e0d2a62008-03-04 15:22:08 -080077
Andrew Mortondf08cdc2010-09-22 13:05:11 -070078/* page table handling */
79#define LEVEL_STRIDE (9)
80#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
81
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +020082/*
83 * This bitmap is used to advertise the page sizes our hardware support
84 * to the IOMMU core, which will then use this information to split
85 * physically contiguous memory regions it is mapping into page sizes
86 * that we support.
87 *
88 * Traditionally the IOMMU core just handed us the mappings directly,
89 * after making sure the size is an order of a 4KiB page and that the
90 * mapping has natural alignment.
91 *
92 * To retain this behavior, we currently advertise that we support
93 * all page sizes that are an order of 4KiB.
94 *
95 * If at some point we'd like to utilize the IOMMU core's new behavior,
96 * we could change this to advertise the real page sizes we support.
97 */
98#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
99
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700100static inline int agaw_to_level(int agaw)
101{
102 return agaw + 2;
103}
104
105static inline int agaw_to_width(int agaw)
106{
Jiang Liu5c645b32014-01-06 14:18:12 +0800107 return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700108}
109
110static inline int width_to_agaw(int width)
111{
Jiang Liu5c645b32014-01-06 14:18:12 +0800112 return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
Andrew Mortondf08cdc2010-09-22 13:05:11 -0700113}
114
115static inline unsigned int level_to_offset_bits(int level)
116{
117 return (level - 1) * LEVEL_STRIDE;
118}
119
120static inline int pfn_level_offset(unsigned long pfn, int level)
121{
122 return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
123}
124
125static inline unsigned long level_mask(int level)
126{
127 return -1UL << level_to_offset_bits(level);
128}
129
130static inline unsigned long level_size(int level)
131{
132 return 1UL << level_to_offset_bits(level);
133}
134
135static inline unsigned long align_to_level(unsigned long pfn, int level)
136{
137 return (pfn + level_size(level) - 1) & level_mask(level);
138}
David Woodhousefd18de52009-05-10 23:57:41 +0100139
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100140static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
141{
Jiang Liu5c645b32014-01-06 14:18:12 +0800142 return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100143}
144
David Woodhousedd4e8312009-06-27 16:21:20 +0100145/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
146 are never going to work. */
147static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
148{
149 return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
150}
151
152static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
153{
154 return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
155}
156static inline unsigned long page_to_dma_pfn(struct page *pg)
157{
158 return mm_to_dma_pfn(page_to_pfn(pg));
159}
160static inline unsigned long virt_to_dma_pfn(void *p)
161{
162 return page_to_dma_pfn(virt_to_page(p));
163}
164
Weidong Hand9630fe2008-12-08 11:06:32 +0800165/* global iommu list, set NULL for ignored DMAR units */
166static struct intel_iommu **g_iommus;
167
David Woodhousee0fc7e02009-09-30 09:12:17 -0700168static void __init check_tylersburg_isoch(void);
David Woodhouse9af88142009-02-13 23:18:03 +0000169static int rwbf_quirk;
170
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000171/*
Joseph Cihulab7792602011-05-03 00:08:37 -0700172 * set to 1 to panic kernel if can't successfully enable VT-d
173 * (used when kernel is launched w/ TXT)
174 */
175static int force_on = 0;
176
177/*
Mark McLoughlin46b08e12008-11-20 15:49:44 +0000178 * 0: Present
179 * 1-11: Reserved
180 * 12-63: Context Ptr (12 - (haw-1))
181 * 64-127: Reserved
182 */
183struct root_entry {
184 u64 val;
185 u64 rsvd1;
186};
187#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
188static inline bool root_present(struct root_entry *root)
189{
190 return (root->val & 1);
191}
192static inline void set_root_present(struct root_entry *root)
193{
194 root->val |= 1;
195}
196static inline void set_root_value(struct root_entry *root, unsigned long value)
197{
198 root->val |= value & VTD_PAGE_MASK;
199}
200
201static inline struct context_entry *
202get_context_addr_from_root(struct root_entry *root)
203{
204 return (struct context_entry *)
205 (root_present(root)?phys_to_virt(
206 root->val & VTD_PAGE_MASK) :
207 NULL);
208}
209
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000210/*
211 * low 64 bits:
212 * 0: present
213 * 1: fault processing disable
214 * 2-3: translation type
215 * 12-63: address space root
216 * high 64 bits:
217 * 0-2: address width
218 * 3-6: aval
219 * 8-23: domain id
220 */
221struct context_entry {
222 u64 lo;
223 u64 hi;
224};
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000225
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000226static inline bool context_present(struct context_entry *context)
227{
228 return (context->lo & 1);
229}
230static inline void context_set_present(struct context_entry *context)
231{
232 context->lo |= 1;
233}
234
235static inline void context_set_fault_enable(struct context_entry *context)
236{
237 context->lo &= (((u64)-1) << 2) | 1;
238}
239
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000240static inline void context_set_translation_type(struct context_entry *context,
241 unsigned long value)
242{
243 context->lo &= (((u64)-1) << 4) | 3;
244 context->lo |= (value & 3) << 2;
245}
246
247static inline void context_set_address_root(struct context_entry *context,
248 unsigned long value)
249{
250 context->lo |= value & VTD_PAGE_MASK;
251}
252
253static inline void context_set_address_width(struct context_entry *context,
254 unsigned long value)
255{
256 context->hi |= value & 7;
257}
258
259static inline void context_set_domain_id(struct context_entry *context,
260 unsigned long value)
261{
262 context->hi |= (value & ((1 << 16) - 1)) << 8;
263}
264
265static inline void context_clear_entry(struct context_entry *context)
266{
267 context->lo = 0;
268 context->hi = 0;
269}
Mark McLoughlin7a8fc252008-11-20 15:49:45 +0000270
Mark McLoughlin622ba122008-11-20 15:49:46 +0000271/*
272 * 0: readable
273 * 1: writable
274 * 2-6: reserved
275 * 7: super page
Sheng Yang9cf06692009-03-18 15:33:07 +0800276 * 8-10: available
277 * 11: snoop behavior
Mark McLoughlin622ba122008-11-20 15:49:46 +0000278 * 12-63: Host physcial address
279 */
280struct dma_pte {
281 u64 val;
282};
Mark McLoughlin622ba122008-11-20 15:49:46 +0000283
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000284static inline void dma_clear_pte(struct dma_pte *pte)
285{
286 pte->val = 0;
287}
288
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000289static inline u64 dma_pte_addr(struct dma_pte *pte)
290{
David Woodhousec85994e2009-07-01 19:21:24 +0100291#ifdef CONFIG_64BIT
292 return pte->val & VTD_PAGE_MASK;
293#else
294 /* Must have a full atomic 64-bit read */
David Woodhouse1a8bd482010-08-10 01:38:53 +0100295 return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
David Woodhousec85994e2009-07-01 19:21:24 +0100296#endif
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000297}
298
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000299static inline bool dma_pte_present(struct dma_pte *pte)
300{
301 return (pte->val & 3) != 0;
302}
Mark McLoughlin622ba122008-11-20 15:49:46 +0000303
Allen Kay4399c8b2011-10-14 12:32:46 -0700304static inline bool dma_pte_superpage(struct dma_pte *pte)
305{
Joerg Roedelc3c75eb2014-07-04 11:19:10 +0200306 return (pte->val & DMA_PTE_LARGE_PAGE);
Allen Kay4399c8b2011-10-14 12:32:46 -0700307}
308
David Woodhouse75e6bf92009-07-02 11:21:16 +0100309static inline int first_pte_in_page(struct dma_pte *pte)
310{
311 return !((unsigned long)pte & ~VTD_PAGE_MASK);
312}
313
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700314/*
315 * This domain is a statically identity mapping domain.
316 * 1. This domain creats a static 1:1 mapping to all usable memory.
317 * 2. It maps to each iommu if successful.
318 * 3. Each iommu mapps to this domain if successful.
319 */
David Woodhouse19943b02009-08-04 16:19:20 +0100320static struct dmar_domain *si_domain;
321static int hw_pass_through = 1;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700322
Weidong Han1ce28fe2008-12-08 16:35:39 +0800323/* domain represents a virtual machine, more than one devices
324 * across iommus may be owned in one domain, e.g. kvm guest.
325 */
Jiang Liuab8dfe22014-07-11 14:19:27 +0800326#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 0)
Weidong Han1ce28fe2008-12-08 16:35:39 +0800327
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700328/* si_domain contains mulitple devices */
Jiang Liuab8dfe22014-07-11 14:19:27 +0800329#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 1)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700330
Mike Travis1b198bb2012-03-05 15:05:16 -0800331/* define the limit of IOMMUs supported in each domain */
332#ifdef CONFIG_X86
333# define IOMMU_UNITS_SUPPORTED MAX_IO_APICS
334#else
335# define IOMMU_UNITS_SUPPORTED 64
336#endif
337
Mark McLoughlin99126f72008-11-20 15:49:47 +0000338struct dmar_domain {
339 int id; /* domain id */
Suresh Siddha4c923d42009-10-02 11:01:24 -0700340 int nid; /* node id */
Mike Travis1b198bb2012-03-05 15:05:16 -0800341 DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
342 /* bitmap of iommus this domain uses*/
Mark McLoughlin99126f72008-11-20 15:49:47 +0000343
344 struct list_head devices; /* all devices' list */
345 struct iova_domain iovad; /* iova's that belong to this domain */
346
347 struct dma_pte *pgd; /* virtual address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000348 int gaw; /* max guest address width */
349
350 /* adjusted guest address width, 0 is level 2 30-bit */
351 int agaw;
352
Weidong Han3b5410e2008-12-08 09:17:15 +0800353 int flags; /* flags to find out type of domain */
Weidong Han8e6040972008-12-08 15:49:06 +0800354
355 int iommu_coherency;/* indicate coherency of iommu access */
Sheng Yang58c610b2009-03-18 15:33:05 +0800356 int iommu_snooping; /* indicate snooping control feature*/
Weidong Hanc7151a82008-12-08 22:51:37 +0800357 int iommu_count; /* reference count of iommu */
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100358 int iommu_superpage;/* Level of superpages supported:
359 0 == 4KiB (no superpages), 1 == 2MiB,
360 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
Weidong Hanc7151a82008-12-08 22:51:37 +0800361 spinlock_t iommu_lock; /* protect iommu set in domain */
Weidong Hanfe40f1e2008-12-08 23:10:23 +0800362 u64 max_addr; /* maximum mapped address */
Mark McLoughlin99126f72008-11-20 15:49:47 +0000363};
364
Mark McLoughlina647dacb2008-11-20 15:49:48 +0000365/* PCI domain-device relationship */
366struct device_domain_info {
367 struct list_head link; /* link to domain siblings */
368 struct list_head global; /* link to global list */
David Woodhouse276dbf992009-04-04 01:45:37 +0100369 u8 bus; /* PCI bus number */
Mark McLoughlina647dacb2008-11-20 15:49:48 +0000370 u8 devfn; /* PCI devfn number */
David Woodhouse0bcb3e22014-03-06 17:12:03 +0000371 struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
Yu Zhao93a23a72009-05-18 13:51:37 +0800372 struct intel_iommu *iommu; /* IOMMU used by this device */
Mark McLoughlina647dacb2008-11-20 15:49:48 +0000373 struct dmar_domain *domain; /* pointer to domain */
374};
375
Jiang Liub94e4112014-02-19 14:07:25 +0800376struct dmar_rmrr_unit {
377 struct list_head list; /* list of rmrr units */
378 struct acpi_dmar_header *hdr; /* ACPI header */
379 u64 base_address; /* reserved base address*/
380 u64 end_address; /* reserved end address */
David Woodhouse832bd852014-03-07 15:08:36 +0000381 struct dmar_dev_scope *devices; /* target devices */
Jiang Liub94e4112014-02-19 14:07:25 +0800382 int devices_cnt; /* target device count */
383};
384
385struct dmar_atsr_unit {
386 struct list_head list; /* list of ATSR units */
387 struct acpi_dmar_header *hdr; /* ACPI header */
David Woodhouse832bd852014-03-07 15:08:36 +0000388 struct dmar_dev_scope *devices; /* target devices */
Jiang Liub94e4112014-02-19 14:07:25 +0800389 int devices_cnt; /* target device count */
390 u8 include_all:1; /* include all ports */
391};
392
393static LIST_HEAD(dmar_atsr_units);
394static LIST_HEAD(dmar_rmrr_units);
395
396#define for_each_rmrr_units(rmrr) \
397 list_for_each_entry(rmrr, &dmar_rmrr_units, list)
398
mark gross5e0d2a62008-03-04 15:22:08 -0800399static void flush_unmaps_timeout(unsigned long data);
400
Jiang Liub707cb02014-01-06 14:18:26 +0800401static DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
mark gross5e0d2a62008-03-04 15:22:08 -0800402
mark gross80b20dd2008-04-18 13:53:58 -0700403#define HIGH_WATER_MARK 250
404struct deferred_flush_tables {
405 int next;
406 struct iova *iova[HIGH_WATER_MARK];
407 struct dmar_domain *domain[HIGH_WATER_MARK];
David Woodhouseea8ea462014-03-05 17:09:32 +0000408 struct page *freelist[HIGH_WATER_MARK];
mark gross80b20dd2008-04-18 13:53:58 -0700409};
410
411static struct deferred_flush_tables *deferred_flush;
412
mark gross5e0d2a62008-03-04 15:22:08 -0800413/* bitmap for indexing intel_iommus */
mark gross5e0d2a62008-03-04 15:22:08 -0800414static int g_num_of_iommus;
415
416static DEFINE_SPINLOCK(async_umap_flush_lock);
417static LIST_HEAD(unmaps_to_do);
418
419static int timer_on;
420static long list_size;
mark gross5e0d2a62008-03-04 15:22:08 -0800421
Jiang Liu92d03cc2014-02-19 14:07:28 +0800422static void domain_exit(struct dmar_domain *domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700423static void domain_remove_dev_info(struct dmar_domain *domain);
Jiang Liub94e4112014-02-19 14:07:25 +0800424static void domain_remove_one_dev_info(struct dmar_domain *domain,
David Woodhousebf9c9ed2014-03-09 16:19:13 -0700425 struct device *dev);
Jiang Liu92d03cc2014-02-19 14:07:28 +0800426static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
David Woodhouse0bcb3e22014-03-06 17:12:03 +0000427 struct device *dev);
Jiang Liu2a46ddf2014-07-11 14:19:30 +0800428static int domain_detach_iommu(struct dmar_domain *domain,
429 struct intel_iommu *iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700430
Suresh Siddhad3f13812011-08-23 17:05:25 -0700431#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800432int dmar_disabled = 0;
433#else
434int dmar_disabled = 1;
Suresh Siddhad3f13812011-08-23 17:05:25 -0700435#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800436
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -0200437int intel_iommu_enabled = 0;
438EXPORT_SYMBOL_GPL(intel_iommu_enabled);
439
David Woodhouse2d9e6672010-06-15 10:57:57 +0100440static int dmar_map_gfx = 1;
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700441static int dmar_forcedac;
mark gross5e0d2a62008-03-04 15:22:08 -0800442static int intel_iommu_strict;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100443static int intel_iommu_superpage = 1;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700444
David Woodhousec0771df2011-10-14 20:59:46 +0100445int intel_iommu_gfx_mapped;
446EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
447
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700448#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
449static DEFINE_SPINLOCK(device_domain_lock);
450static LIST_HEAD(device_domain_list);
451
Thierry Redingb22f6432014-06-27 09:03:12 +0200452static const struct iommu_ops intel_iommu_ops;
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +0100453
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700454static int __init intel_iommu_setup(char *str)
455{
456 if (!str)
457 return -EINVAL;
458 while (*str) {
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800459 if (!strncmp(str, "on", 2)) {
460 dmar_disabled = 0;
461 printk(KERN_INFO "Intel-IOMMU: enabled\n");
462 } else if (!strncmp(str, "off", 3)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700463 dmar_disabled = 1;
Kyle McMartin0cd5c3c2009-02-04 14:29:19 -0800464 printk(KERN_INFO "Intel-IOMMU: disabled\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700465 } else if (!strncmp(str, "igfx_off", 8)) {
466 dmar_map_gfx = 0;
467 printk(KERN_INFO
468 "Intel-IOMMU: disable GFX device mapping\n");
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700469 } else if (!strncmp(str, "forcedac", 8)) {
mark gross5e0d2a62008-03-04 15:22:08 -0800470 printk(KERN_INFO
Keshavamurthy, Anil S7d3b03c2007-10-21 16:41:53 -0700471 "Intel-IOMMU: Forcing DAC for PCI devices\n");
472 dmar_forcedac = 1;
mark gross5e0d2a62008-03-04 15:22:08 -0800473 } else if (!strncmp(str, "strict", 6)) {
474 printk(KERN_INFO
475 "Intel-IOMMU: disable batched IOTLB flush\n");
476 intel_iommu_strict = 1;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100477 } else if (!strncmp(str, "sp_off", 6)) {
478 printk(KERN_INFO
479 "Intel-IOMMU: disable supported super page\n");
480 intel_iommu_superpage = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700481 }
482
483 str += strcspn(str, ",");
484 while (*str == ',')
485 str++;
486 }
487 return 0;
488}
489__setup("intel_iommu=", intel_iommu_setup);
490
491static struct kmem_cache *iommu_domain_cache;
492static struct kmem_cache *iommu_devinfo_cache;
493static struct kmem_cache *iommu_iova_cache;
494
Suresh Siddha4c923d42009-10-02 11:01:24 -0700495static inline void *alloc_pgtable_page(int node)
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700496{
Suresh Siddha4c923d42009-10-02 11:01:24 -0700497 struct page *page;
498 void *vaddr = NULL;
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700499
Suresh Siddha4c923d42009-10-02 11:01:24 -0700500 page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
501 if (page)
502 vaddr = page_address(page);
Keshavamurthy, Anil Seb3fa7c2007-10-21 16:41:52 -0700503 return vaddr;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700504}
505
506static inline void free_pgtable_page(void *vaddr)
507{
508 free_page((unsigned long)vaddr);
509}
510
511static inline void *alloc_domain_mem(void)
512{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900513 return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700514}
515
Kay, Allen M38717942008-09-09 18:37:29 +0300516static void free_domain_mem(void *vaddr)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700517{
518 kmem_cache_free(iommu_domain_cache, vaddr);
519}
520
521static inline void * alloc_devinfo_mem(void)
522{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900523 return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700524}
525
526static inline void free_devinfo_mem(void *vaddr)
527{
528 kmem_cache_free(iommu_devinfo_cache, vaddr);
529}
530
531struct iova *alloc_iova_mem(void)
532{
KOSAKI Motohiro354bb652009-11-17 16:21:09 +0900533 return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700534}
535
536void free_iova_mem(struct iova *iova)
537{
538 kmem_cache_free(iommu_iova_cache, iova);
539}
540
Jiang Liuab8dfe22014-07-11 14:19:27 +0800541static inline int domain_type_is_vm(struct dmar_domain *domain)
542{
543 return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE;
544}
545
546static inline int domain_type_is_vm_or_si(struct dmar_domain *domain)
547{
548 return domain->flags & (DOMAIN_FLAG_VIRTUAL_MACHINE |
549 DOMAIN_FLAG_STATIC_IDENTITY);
550}
Weidong Han1b573682008-12-08 15:34:06 +0800551
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700552static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
Weidong Han1b573682008-12-08 15:34:06 +0800553{
554 unsigned long sagaw;
555 int agaw = -1;
556
557 sagaw = cap_sagaw(iommu->cap);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700558 for (agaw = width_to_agaw(max_gaw);
Weidong Han1b573682008-12-08 15:34:06 +0800559 agaw >= 0; agaw--) {
560 if (test_bit(agaw, &sagaw))
561 break;
562 }
563
564 return agaw;
565}
566
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -0700567/*
568 * Calculate max SAGAW for each iommu.
569 */
570int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
571{
572 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
573}
574
575/*
576 * calculate agaw for each iommu.
577 * "SAGAW" may be different across iommus, use a default agaw, and
578 * get a supported less agaw for iommus that don't support the default agaw.
579 */
580int iommu_calculate_agaw(struct intel_iommu *iommu)
581{
582 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
583}
584
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700585/* This functionin only returns single iommu in a domain */
Weidong Han8c11e792008-12-08 15:29:22 +0800586static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
587{
588 int iommu_id;
589
Fenghua Yu2c2e2c32009-06-19 13:47:29 -0700590 /* si_domain and vm domain should not get here. */
Jiang Liuab8dfe22014-07-11 14:19:27 +0800591 BUG_ON(domain_type_is_vm_or_si(domain));
Mike Travis1b198bb2012-03-05 15:05:16 -0800592 iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
Weidong Han8c11e792008-12-08 15:29:22 +0800593 if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
594 return NULL;
595
596 return g_iommus[iommu_id];
597}
598
Weidong Han8e6040972008-12-08 15:49:06 +0800599static void domain_update_iommu_coherency(struct dmar_domain *domain)
600{
David Woodhoused0501962014-03-11 17:10:29 -0700601 struct dmar_drhd_unit *drhd;
602 struct intel_iommu *iommu;
603 int i, found = 0;
Weidong Han8e6040972008-12-08 15:49:06 +0800604
David Woodhoused0501962014-03-11 17:10:29 -0700605 domain->iommu_coherency = 1;
Weidong Han8e6040972008-12-08 15:49:06 +0800606
Mike Travis1b198bb2012-03-05 15:05:16 -0800607 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
David Woodhoused0501962014-03-11 17:10:29 -0700608 found = 1;
Weidong Han8e6040972008-12-08 15:49:06 +0800609 if (!ecap_coherent(g_iommus[i]->ecap)) {
610 domain->iommu_coherency = 0;
611 break;
612 }
Weidong Han8e6040972008-12-08 15:49:06 +0800613 }
David Woodhoused0501962014-03-11 17:10:29 -0700614 if (found)
615 return;
616
617 /* No hardware attached; use lowest common denominator */
618 rcu_read_lock();
619 for_each_active_iommu(iommu, drhd) {
620 if (!ecap_coherent(iommu->ecap)) {
621 domain->iommu_coherency = 0;
622 break;
623 }
624 }
625 rcu_read_unlock();
Weidong Han8e6040972008-12-08 15:49:06 +0800626}
627
Sheng Yang58c610b2009-03-18 15:33:05 +0800628static void domain_update_iommu_snooping(struct dmar_domain *domain)
629{
630 int i;
631
632 domain->iommu_snooping = 1;
633
Mike Travis1b198bb2012-03-05 15:05:16 -0800634 for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
Sheng Yang58c610b2009-03-18 15:33:05 +0800635 if (!ecap_sc_support(g_iommus[i]->ecap)) {
636 domain->iommu_snooping = 0;
637 break;
638 }
Sheng Yang58c610b2009-03-18 15:33:05 +0800639 }
640}
641
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100642static void domain_update_iommu_superpage(struct dmar_domain *domain)
643{
Allen Kay8140a952011-10-14 12:32:17 -0700644 struct dmar_drhd_unit *drhd;
645 struct intel_iommu *iommu = NULL;
646 int mask = 0xf;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100647
648 if (!intel_iommu_superpage) {
649 domain->iommu_superpage = 0;
650 return;
651 }
652
Allen Kay8140a952011-10-14 12:32:17 -0700653 /* set iommu_superpage to the smallest common denominator */
Jiang Liu0e2426122014-02-19 14:07:34 +0800654 rcu_read_lock();
Allen Kay8140a952011-10-14 12:32:17 -0700655 for_each_active_iommu(iommu, drhd) {
656 mask &= cap_super_page_val(iommu->cap);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100657 if (!mask) {
658 break;
659 }
660 }
Jiang Liu0e2426122014-02-19 14:07:34 +0800661 rcu_read_unlock();
662
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100663 domain->iommu_superpage = fls(mask);
664}
665
Sheng Yang58c610b2009-03-18 15:33:05 +0800666/* Some capabilities may be different across iommus */
667static void domain_update_iommu_cap(struct dmar_domain *domain)
668{
669 domain_update_iommu_coherency(domain);
670 domain_update_iommu_snooping(domain);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100671 domain_update_iommu_superpage(domain);
Sheng Yang58c610b2009-03-18 15:33:05 +0800672}
673
David Woodhouse156baca2014-03-09 14:00:57 -0700674static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
Weidong Hanc7151a82008-12-08 22:51:37 +0800675{
676 struct dmar_drhd_unit *drhd = NULL;
Jiang Liub683b232014-02-19 14:07:32 +0800677 struct intel_iommu *iommu;
David Woodhouse156baca2014-03-09 14:00:57 -0700678 struct device *tmp;
679 struct pci_dev *ptmp, *pdev = NULL;
Yijing Wangaa4d0662014-05-26 20:14:06 +0800680 u16 segment = 0;
Weidong Hanc7151a82008-12-08 22:51:37 +0800681 int i;
682
David Woodhouse156baca2014-03-09 14:00:57 -0700683 if (dev_is_pci(dev)) {
684 pdev = to_pci_dev(dev);
685 segment = pci_domain_nr(pdev->bus);
686 } else if (ACPI_COMPANION(dev))
687 dev = &ACPI_COMPANION(dev)->dev;
688
Jiang Liu0e2426122014-02-19 14:07:34 +0800689 rcu_read_lock();
Jiang Liub683b232014-02-19 14:07:32 +0800690 for_each_active_iommu(iommu, drhd) {
David Woodhouse156baca2014-03-09 14:00:57 -0700691 if (pdev && segment != drhd->segment)
David Woodhouse276dbf992009-04-04 01:45:37 +0100692 continue;
Weidong Hanc7151a82008-12-08 22:51:37 +0800693
Jiang Liub683b232014-02-19 14:07:32 +0800694 for_each_active_dev_scope(drhd->devices,
David Woodhouse156baca2014-03-09 14:00:57 -0700695 drhd->devices_cnt, i, tmp) {
696 if (tmp == dev) {
697 *bus = drhd->devices[i].bus;
698 *devfn = drhd->devices[i].devfn;
699 goto out;
700 }
701
702 if (!pdev || !dev_is_pci(tmp))
David Woodhouse832bd852014-03-07 15:08:36 +0000703 continue;
David Woodhouse156baca2014-03-09 14:00:57 -0700704
705 ptmp = to_pci_dev(tmp);
706 if (ptmp->subordinate &&
707 ptmp->subordinate->number <= pdev->bus->number &&
708 ptmp->subordinate->busn_res.end >= pdev->bus->number)
709 goto got_pdev;
David Woodhouse924b6232009-04-04 00:39:25 +0100710 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800711
David Woodhouse156baca2014-03-09 14:00:57 -0700712 if (pdev && drhd->include_all) {
713 got_pdev:
714 *bus = pdev->bus->number;
715 *devfn = pdev->devfn;
Jiang Liub683b232014-02-19 14:07:32 +0800716 goto out;
David Woodhouse156baca2014-03-09 14:00:57 -0700717 }
Weidong Hanc7151a82008-12-08 22:51:37 +0800718 }
Jiang Liub683b232014-02-19 14:07:32 +0800719 iommu = NULL;
David Woodhouse156baca2014-03-09 14:00:57 -0700720 out:
Jiang Liu0e2426122014-02-19 14:07:34 +0800721 rcu_read_unlock();
Weidong Hanc7151a82008-12-08 22:51:37 +0800722
Jiang Liub683b232014-02-19 14:07:32 +0800723 return iommu;
Weidong Hanc7151a82008-12-08 22:51:37 +0800724}
725
Weidong Han5331fe62008-12-08 23:00:00 +0800726static void domain_flush_cache(struct dmar_domain *domain,
727 void *addr, int size)
728{
729 if (!domain->iommu_coherency)
730 clflush_cache_range(addr, size);
731}
732
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700733/* Gets context entry for a given bus and devfn */
734static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
735 u8 bus, u8 devfn)
736{
737 struct root_entry *root;
738 struct context_entry *context;
739 unsigned long phy_addr;
740 unsigned long flags;
741
742 spin_lock_irqsave(&iommu->lock, flags);
743 root = &iommu->root_entry[bus];
744 context = get_context_addr_from_root(root);
745 if (!context) {
Suresh Siddha4c923d42009-10-02 11:01:24 -0700746 context = (struct context_entry *)
747 alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700748 if (!context) {
749 spin_unlock_irqrestore(&iommu->lock, flags);
750 return NULL;
751 }
Fenghua Yu5b6985c2008-10-16 18:02:32 -0700752 __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700753 phy_addr = virt_to_phys((void *)context);
754 set_root_value(root, phy_addr);
755 set_root_present(root);
756 __iommu_flush_cache(iommu, root, sizeof(*root));
757 }
758 spin_unlock_irqrestore(&iommu->lock, flags);
759 return &context[devfn];
760}
761
762static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
763{
764 struct root_entry *root;
765 struct context_entry *context;
766 int ret;
767 unsigned long flags;
768
769 spin_lock_irqsave(&iommu->lock, flags);
770 root = &iommu->root_entry[bus];
771 context = get_context_addr_from_root(root);
772 if (!context) {
773 ret = 0;
774 goto out;
775 }
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000776 ret = context_present(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700777out:
778 spin_unlock_irqrestore(&iommu->lock, flags);
779 return ret;
780}
781
782static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
783{
784 struct root_entry *root;
785 struct context_entry *context;
786 unsigned long flags;
787
788 spin_lock_irqsave(&iommu->lock, flags);
789 root = &iommu->root_entry[bus];
790 context = get_context_addr_from_root(root);
791 if (context) {
Mark McLoughlinc07e7d22008-11-21 16:54:46 +0000792 context_clear_entry(&context[devfn]);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700793 __iommu_flush_cache(iommu, &context[devfn], \
794 sizeof(*context));
795 }
796 spin_unlock_irqrestore(&iommu->lock, flags);
797}
798
799static void free_context_table(struct intel_iommu *iommu)
800{
801 struct root_entry *root;
802 int i;
803 unsigned long flags;
804 struct context_entry *context;
805
806 spin_lock_irqsave(&iommu->lock, flags);
807 if (!iommu->root_entry) {
808 goto out;
809 }
810 for (i = 0; i < ROOT_ENTRY_NR; i++) {
811 root = &iommu->root_entry[i];
812 context = get_context_addr_from_root(root);
813 if (context)
814 free_pgtable_page(context);
815 }
816 free_pgtable_page(iommu->root_entry);
817 iommu->root_entry = NULL;
818out:
819 spin_unlock_irqrestore(&iommu->lock, flags);
820}
821
David Woodhouseb026fd22009-06-28 10:37:25 +0100822static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
David Woodhouse5cf0a762014-03-19 16:07:49 +0000823 unsigned long pfn, int *target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700824{
David Woodhouseb026fd22009-06-28 10:37:25 +0100825 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700826 struct dma_pte *parent, *pte = NULL;
827 int level = agaw_to_level(domain->agaw);
Allen Kay4399c8b2011-10-14 12:32:46 -0700828 int offset;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700829
830 BUG_ON(!domain->pgd);
Julian Stecklinaf9423602013-10-09 10:03:52 +0200831
832 if (addr_width < BITS_PER_LONG && pfn >> addr_width)
833 /* Address beyond IOMMU's addressing capabilities. */
834 return NULL;
835
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700836 parent = domain->pgd;
837
David Woodhouse5cf0a762014-03-19 16:07:49 +0000838 while (1) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700839 void *tmp_page;
840
David Woodhouseb026fd22009-06-28 10:37:25 +0100841 offset = pfn_level_offset(pfn, level);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700842 pte = &parent[offset];
David Woodhouse5cf0a762014-03-19 16:07:49 +0000843 if (!*target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100844 break;
David Woodhouse5cf0a762014-03-19 16:07:49 +0000845 if (level == *target_level)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700846 break;
847
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000848 if (!dma_pte_present(pte)) {
David Woodhousec85994e2009-07-01 19:21:24 +0100849 uint64_t pteval;
850
Suresh Siddha4c923d42009-10-02 11:01:24 -0700851 tmp_page = alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700852
David Woodhouse206a73c2009-07-01 19:30:28 +0100853 if (!tmp_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700854 return NULL;
David Woodhouse206a73c2009-07-01 19:30:28 +0100855
David Woodhousec85994e2009-07-01 19:21:24 +0100856 domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
Benjamin LaHaise64de5af2009-09-16 21:05:55 -0400857 pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
Yijing Wangeffad4b2014-05-26 20:13:47 +0800858 if (cmpxchg64(&pte->val, 0ULL, pteval))
David Woodhousec85994e2009-07-01 19:21:24 +0100859 /* Someone else set it while we were thinking; use theirs. */
860 free_pgtable_page(tmp_page);
Yijing Wangeffad4b2014-05-26 20:13:47 +0800861 else
David Woodhousec85994e2009-07-01 19:21:24 +0100862 domain_flush_cache(domain, pte, sizeof(*pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700863 }
David Woodhouse5cf0a762014-03-19 16:07:49 +0000864 if (level == 1)
865 break;
866
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000867 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700868 level--;
869 }
870
David Woodhouse5cf0a762014-03-19 16:07:49 +0000871 if (!*target_level)
872 *target_level = level;
873
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700874 return pte;
875}
876
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100877
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700878/* return address's pte at specific level */
David Woodhouse90dcfb52009-06-27 17:14:59 +0100879static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
880 unsigned long pfn,
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100881 int level, int *large_page)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700882{
883 struct dma_pte *parent, *pte = NULL;
884 int total = agaw_to_level(domain->agaw);
885 int offset;
886
887 parent = domain->pgd;
888 while (level <= total) {
David Woodhouse90dcfb52009-06-27 17:14:59 +0100889 offset = pfn_level_offset(pfn, total);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700890 pte = &parent[offset];
891 if (level == total)
892 return pte;
893
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100894 if (!dma_pte_present(pte)) {
895 *large_page = total;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700896 break;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100897 }
898
Yijing Wange16922a2014-05-20 20:37:51 +0800899 if (dma_pte_superpage(pte)) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100900 *large_page = total;
901 return pte;
902 }
903
Mark McLoughlin19c239c2008-11-21 16:56:53 +0000904 parent = phys_to_virt(dma_pte_addr(pte));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700905 total--;
906 }
907 return NULL;
908}
909
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700910/* clear last level pte, a tlb flush should be followed */
David Woodhouse5cf0a762014-03-19 16:07:49 +0000911static void dma_pte_clear_range(struct dmar_domain *domain,
David Woodhouse595badf52009-06-27 22:09:11 +0100912 unsigned long start_pfn,
913 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700914{
David Woodhouse04b18e62009-06-27 19:15:01 +0100915 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100916 unsigned int large_page = 1;
David Woodhouse310a5ab2009-06-28 18:52:20 +0100917 struct dma_pte *first_pte, *pte;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700918
David Woodhouse04b18e62009-06-27 19:15:01 +0100919 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
David Woodhouse595badf52009-06-27 22:09:11 +0100920 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700921 BUG_ON(start_pfn > last_pfn);
David Woodhouse66eae842009-06-27 19:00:32 +0100922
David Woodhouse04b18e62009-06-27 19:15:01 +0100923 /* we don't need lock here; nobody else touches the iova range */
David Woodhouse59c36282009-09-19 07:36:28 -0700924 do {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100925 large_page = 1;
926 first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100927 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100928 start_pfn = align_to_level(start_pfn + 1, large_page + 1);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100929 continue;
930 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100931 do {
David Woodhouse310a5ab2009-06-28 18:52:20 +0100932 dma_clear_pte(pte);
Youquan Song6dd9a7c2011-05-25 19:13:49 +0100933 start_pfn += lvl_to_nr_pages(large_page);
David Woodhouse310a5ab2009-06-28 18:52:20 +0100934 pte++;
David Woodhouse75e6bf92009-07-02 11:21:16 +0100935 } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
936
David Woodhouse310a5ab2009-06-28 18:52:20 +0100937 domain_flush_cache(domain, first_pte,
938 (void *)pte - (void *)first_pte);
David Woodhouse59c36282009-09-19 07:36:28 -0700939
940 } while (start_pfn && start_pfn <= last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700941}
942
Alex Williamson3269ee02013-06-15 10:27:19 -0600943static void dma_pte_free_level(struct dmar_domain *domain, int level,
944 struct dma_pte *pte, unsigned long pfn,
945 unsigned long start_pfn, unsigned long last_pfn)
946{
947 pfn = max(start_pfn, pfn);
948 pte = &pte[pfn_level_offset(pfn, level)];
949
950 do {
951 unsigned long level_pfn;
952 struct dma_pte *level_pte;
953
954 if (!dma_pte_present(pte) || dma_pte_superpage(pte))
955 goto next;
956
957 level_pfn = pfn & level_mask(level - 1);
958 level_pte = phys_to_virt(dma_pte_addr(pte));
959
960 if (level > 2)
961 dma_pte_free_level(domain, level - 1, level_pte,
962 level_pfn, start_pfn, last_pfn);
963
964 /* If range covers entire pagetable, free it */
965 if (!(start_pfn > level_pfn ||
Alex Williamson08336fd2014-01-21 15:48:18 -0800966 last_pfn < level_pfn + level_size(level) - 1)) {
Alex Williamson3269ee02013-06-15 10:27:19 -0600967 dma_clear_pte(pte);
968 domain_flush_cache(domain, pte, sizeof(*pte));
969 free_pgtable_page(level_pte);
970 }
971next:
972 pfn += level_size(level);
973 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
974}
975
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700976/* free page table pages. last level pte should already be cleared */
977static void dma_pte_free_pagetable(struct dmar_domain *domain,
David Woodhoused794dc92009-06-28 00:27:49 +0100978 unsigned long start_pfn,
979 unsigned long last_pfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700980{
David Woodhouse6660c632009-06-27 22:41:00 +0100981 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700982
David Woodhouse6660c632009-06-27 22:41:00 +0100983 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
984 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
David Woodhouse59c36282009-09-19 07:36:28 -0700985 BUG_ON(start_pfn > last_pfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700986
David Woodhousef3a0a522009-06-30 03:40:07 +0100987 /* We don't need lock here; nobody else touches the iova range */
Alex Williamson3269ee02013-06-15 10:27:19 -0600988 dma_pte_free_level(domain, agaw_to_level(domain->agaw),
989 domain->pgd, 0, start_pfn, last_pfn);
David Woodhouse6660c632009-06-27 22:41:00 +0100990
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700991 /* free pgd */
David Woodhoused794dc92009-06-28 00:27:49 +0100992 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -0700993 free_pgtable_page(domain->pgd);
994 domain->pgd = NULL;
995 }
996}
997
David Woodhouseea8ea462014-03-05 17:09:32 +0000998/* When a page at a given level is being unlinked from its parent, we don't
999 need to *modify* it at all. All we need to do is make a list of all the
1000 pages which can be freed just as soon as we've flushed the IOTLB and we
1001 know the hardware page-walk will no longer touch them.
1002 The 'pte' argument is the *parent* PTE, pointing to the page that is to
1003 be freed. */
1004static struct page *dma_pte_list_pagetables(struct dmar_domain *domain,
1005 int level, struct dma_pte *pte,
1006 struct page *freelist)
1007{
1008 struct page *pg;
1009
1010 pg = pfn_to_page(dma_pte_addr(pte) >> PAGE_SHIFT);
1011 pg->freelist = freelist;
1012 freelist = pg;
1013
1014 if (level == 1)
1015 return freelist;
1016
Jiang Liuadeb2592014-04-09 10:20:39 +08001017 pte = page_address(pg);
1018 do {
David Woodhouseea8ea462014-03-05 17:09:32 +00001019 if (dma_pte_present(pte) && !dma_pte_superpage(pte))
1020 freelist = dma_pte_list_pagetables(domain, level - 1,
1021 pte, freelist);
Jiang Liuadeb2592014-04-09 10:20:39 +08001022 pte++;
1023 } while (!first_pte_in_page(pte));
David Woodhouseea8ea462014-03-05 17:09:32 +00001024
1025 return freelist;
1026}
1027
1028static struct page *dma_pte_clear_level(struct dmar_domain *domain, int level,
1029 struct dma_pte *pte, unsigned long pfn,
1030 unsigned long start_pfn,
1031 unsigned long last_pfn,
1032 struct page *freelist)
1033{
1034 struct dma_pte *first_pte = NULL, *last_pte = NULL;
1035
1036 pfn = max(start_pfn, pfn);
1037 pte = &pte[pfn_level_offset(pfn, level)];
1038
1039 do {
1040 unsigned long level_pfn;
1041
1042 if (!dma_pte_present(pte))
1043 goto next;
1044
1045 level_pfn = pfn & level_mask(level);
1046
1047 /* If range covers entire pagetable, free it */
1048 if (start_pfn <= level_pfn &&
1049 last_pfn >= level_pfn + level_size(level) - 1) {
1050 /* These suborbinate page tables are going away entirely. Don't
1051 bother to clear them; we're just going to *free* them. */
1052 if (level > 1 && !dma_pte_superpage(pte))
1053 freelist = dma_pte_list_pagetables(domain, level - 1, pte, freelist);
1054
1055 dma_clear_pte(pte);
1056 if (!first_pte)
1057 first_pte = pte;
1058 last_pte = pte;
1059 } else if (level > 1) {
1060 /* Recurse down into a level that isn't *entirely* obsolete */
1061 freelist = dma_pte_clear_level(domain, level - 1,
1062 phys_to_virt(dma_pte_addr(pte)),
1063 level_pfn, start_pfn, last_pfn,
1064 freelist);
1065 }
1066next:
1067 pfn += level_size(level);
1068 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
1069
1070 if (first_pte)
1071 domain_flush_cache(domain, first_pte,
1072 (void *)++last_pte - (void *)first_pte);
1073
1074 return freelist;
1075}
1076
1077/* We can't just free the pages because the IOMMU may still be walking
1078 the page tables, and may have cached the intermediate levels. The
1079 pages can only be freed after the IOTLB flush has been done. */
1080struct page *domain_unmap(struct dmar_domain *domain,
1081 unsigned long start_pfn,
1082 unsigned long last_pfn)
1083{
1084 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
1085 struct page *freelist = NULL;
1086
1087 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
1088 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
1089 BUG_ON(start_pfn > last_pfn);
1090
1091 /* we don't need lock here; nobody else touches the iova range */
1092 freelist = dma_pte_clear_level(domain, agaw_to_level(domain->agaw),
1093 domain->pgd, 0, start_pfn, last_pfn, NULL);
1094
1095 /* free pgd */
1096 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
1097 struct page *pgd_page = virt_to_page(domain->pgd);
1098 pgd_page->freelist = freelist;
1099 freelist = pgd_page;
1100
1101 domain->pgd = NULL;
1102 }
1103
1104 return freelist;
1105}
1106
1107void dma_free_pagelist(struct page *freelist)
1108{
1109 struct page *pg;
1110
1111 while ((pg = freelist)) {
1112 freelist = pg->freelist;
1113 free_pgtable_page(page_address(pg));
1114 }
1115}
1116
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001117/* iommu handling */
1118static int iommu_alloc_root_entry(struct intel_iommu *iommu)
1119{
1120 struct root_entry *root;
1121 unsigned long flags;
1122
Suresh Siddha4c923d42009-10-02 11:01:24 -07001123 root = (struct root_entry *)alloc_pgtable_page(iommu->node);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001124 if (!root)
1125 return -ENOMEM;
1126
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001127 __iommu_flush_cache(iommu, root, ROOT_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001128
1129 spin_lock_irqsave(&iommu->lock, flags);
1130 iommu->root_entry = root;
1131 spin_unlock_irqrestore(&iommu->lock, flags);
1132
1133 return 0;
1134}
1135
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001136static void iommu_set_root_entry(struct intel_iommu *iommu)
1137{
1138 void *addr;
David Woodhousec416daa2009-05-10 20:30:58 +01001139 u32 sts;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001140 unsigned long flag;
1141
1142 addr = iommu->root_entry;
1143
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001144 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001145 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
1146
David Woodhousec416daa2009-05-10 20:30:58 +01001147 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001148
1149 /* Make sure hardware complete it */
1150 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001151 readl, (sts & DMA_GSTS_RTPS), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001152
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001153 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001154}
1155
1156static void iommu_flush_write_buffer(struct intel_iommu *iommu)
1157{
1158 u32 val;
1159 unsigned long flag;
1160
David Woodhouse9af88142009-02-13 23:18:03 +00001161 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001162 return;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001163
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001164 raw_spin_lock_irqsave(&iommu->register_lock, flag);
David Woodhouse462b60f2009-05-10 20:18:18 +01001165 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001166
1167 /* Make sure hardware complete it */
1168 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001169 readl, (!(val & DMA_GSTS_WBFS)), val);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001170
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001171 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001172}
1173
1174/* return value determine if we need a write buffer flush */
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001175static void __iommu_flush_context(struct intel_iommu *iommu,
1176 u16 did, u16 source_id, u8 function_mask,
1177 u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001178{
1179 u64 val = 0;
1180 unsigned long flag;
1181
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001182 switch (type) {
1183 case DMA_CCMD_GLOBAL_INVL:
1184 val = DMA_CCMD_GLOBAL_INVL;
1185 break;
1186 case DMA_CCMD_DOMAIN_INVL:
1187 val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
1188 break;
1189 case DMA_CCMD_DEVICE_INVL:
1190 val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
1191 | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
1192 break;
1193 default:
1194 BUG();
1195 }
1196 val |= DMA_CCMD_ICC;
1197
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001198 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001199 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
1200
1201 /* Make sure hardware complete it */
1202 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
1203 dmar_readq, (!(val & DMA_CCMD_ICC)), val);
1204
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001205 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001206}
1207
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001208/* return value determine if we need a write buffer flush */
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001209static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
1210 u64 addr, unsigned int size_order, u64 type)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001211{
1212 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
1213 u64 val = 0, val_iva = 0;
1214 unsigned long flag;
1215
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001216 switch (type) {
1217 case DMA_TLB_GLOBAL_FLUSH:
1218 /* global flush doesn't need set IVA_REG */
1219 val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
1220 break;
1221 case DMA_TLB_DSI_FLUSH:
1222 val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
1223 break;
1224 case DMA_TLB_PSI_FLUSH:
1225 val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
David Woodhouseea8ea462014-03-05 17:09:32 +00001226 /* IH bit is passed in as part of address */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001227 val_iva = size_order | addr;
1228 break;
1229 default:
1230 BUG();
1231 }
1232 /* Note: set drain read/write */
1233#if 0
1234 /*
1235 * This is probably to be super secure.. Looks like we can
1236 * ignore it without any impact.
1237 */
1238 if (cap_read_drain(iommu->cap))
1239 val |= DMA_TLB_READ_DRAIN;
1240#endif
1241 if (cap_write_drain(iommu->cap))
1242 val |= DMA_TLB_WRITE_DRAIN;
1243
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001244 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001245 /* Note: Only uses first TLB reg currently */
1246 if (val_iva)
1247 dmar_writeq(iommu->reg + tlb_offset, val_iva);
1248 dmar_writeq(iommu->reg + tlb_offset + 8, val);
1249
1250 /* Make sure hardware complete it */
1251 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
1252 dmar_readq, (!(val & DMA_TLB_IVT)), val);
1253
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001254 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001255
1256 /* check IOTLB invalidation granularity */
1257 if (DMA_TLB_IAIG(val) == 0)
1258 printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
1259 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
1260 pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001261 (unsigned long long)DMA_TLB_IIRG(type),
1262 (unsigned long long)DMA_TLB_IAIG(val));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001263}
1264
David Woodhouse64ae8922014-03-09 12:52:30 -07001265static struct device_domain_info *
1266iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu,
1267 u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001268{
Yu Zhao93a23a72009-05-18 13:51:37 +08001269 int found = 0;
1270 unsigned long flags;
1271 struct device_domain_info *info;
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001272 struct pci_dev *pdev;
Yu Zhao93a23a72009-05-18 13:51:37 +08001273
1274 if (!ecap_dev_iotlb_support(iommu->ecap))
1275 return NULL;
1276
1277 if (!iommu->qi)
1278 return NULL;
1279
1280 spin_lock_irqsave(&device_domain_lock, flags);
1281 list_for_each_entry(info, &domain->devices, link)
Jiang Liuc3b497c2014-07-11 14:19:25 +08001282 if (info->iommu == iommu && info->bus == bus &&
1283 info->devfn == devfn) {
Yu Zhao93a23a72009-05-18 13:51:37 +08001284 found = 1;
1285 break;
1286 }
1287 spin_unlock_irqrestore(&device_domain_lock, flags);
1288
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001289 if (!found || !info->dev || !dev_is_pci(info->dev))
Yu Zhao93a23a72009-05-18 13:51:37 +08001290 return NULL;
1291
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001292 pdev = to_pci_dev(info->dev);
1293
1294 if (!pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ATS))
Yu Zhao93a23a72009-05-18 13:51:37 +08001295 return NULL;
1296
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001297 if (!dmar_find_matched_atsr_unit(pdev))
Yu Zhao93a23a72009-05-18 13:51:37 +08001298 return NULL;
1299
Yu Zhao93a23a72009-05-18 13:51:37 +08001300 return info;
1301}
1302
1303static void iommu_enable_dev_iotlb(struct device_domain_info *info)
1304{
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001305 if (!info || !dev_is_pci(info->dev))
Yu Zhao93a23a72009-05-18 13:51:37 +08001306 return;
1307
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001308 pci_enable_ats(to_pci_dev(info->dev), VTD_PAGE_SHIFT);
Yu Zhao93a23a72009-05-18 13:51:37 +08001309}
1310
1311static void iommu_disable_dev_iotlb(struct device_domain_info *info)
1312{
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001313 if (!info->dev || !dev_is_pci(info->dev) ||
1314 !pci_ats_enabled(to_pci_dev(info->dev)))
Yu Zhao93a23a72009-05-18 13:51:37 +08001315 return;
1316
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001317 pci_disable_ats(to_pci_dev(info->dev));
Yu Zhao93a23a72009-05-18 13:51:37 +08001318}
1319
1320static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
1321 u64 addr, unsigned mask)
1322{
1323 u16 sid, qdep;
1324 unsigned long flags;
1325 struct device_domain_info *info;
1326
1327 spin_lock_irqsave(&device_domain_lock, flags);
1328 list_for_each_entry(info, &domain->devices, link) {
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001329 struct pci_dev *pdev;
1330 if (!info->dev || !dev_is_pci(info->dev))
1331 continue;
1332
1333 pdev = to_pci_dev(info->dev);
1334 if (!pci_ats_enabled(pdev))
Yu Zhao93a23a72009-05-18 13:51:37 +08001335 continue;
1336
1337 sid = info->bus << 8 | info->devfn;
David Woodhouse0bcb3e22014-03-06 17:12:03 +00001338 qdep = pci_ats_queue_depth(pdev);
Yu Zhao93a23a72009-05-18 13:51:37 +08001339 qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
1340 }
1341 spin_unlock_irqrestore(&device_domain_lock, flags);
1342}
1343
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001344static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
David Woodhouseea8ea462014-03-05 17:09:32 +00001345 unsigned long pfn, unsigned int pages, int ih, int map)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001346{
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001347 unsigned int mask = ilog2(__roundup_pow_of_two(pages));
David Woodhouse03d6a242009-06-28 15:33:46 +01001348 uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001349
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001350 BUG_ON(pages == 0);
1351
David Woodhouseea8ea462014-03-05 17:09:32 +00001352 if (ih)
1353 ih = 1 << 6;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001354 /*
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001355 * Fallback to domain selective flush if no PSI support or the size is
1356 * too big.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001357 * PSI requires page size to be 2 ^ x, and the base address is naturally
1358 * aligned to the size
1359 */
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001360 if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1361 iommu->flush.flush_iotlb(iommu, did, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01001362 DMA_TLB_DSI_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001363 else
David Woodhouseea8ea462014-03-05 17:09:32 +00001364 iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
Yu Zhao9dd2fe82009-05-18 13:51:36 +08001365 DMA_TLB_PSI_FLUSH);
Yu Zhaobf92df32009-06-29 11:31:45 +08001366
1367 /*
Nadav Amit82653632010-04-01 13:24:40 +03001368 * In caching mode, changes of pages from non-present to present require
1369 * flush. However, device IOTLB doesn't need to be flushed in this case.
Yu Zhaobf92df32009-06-29 11:31:45 +08001370 */
Nadav Amit82653632010-04-01 13:24:40 +03001371 if (!cap_caching_mode(iommu->cap) || !map)
Yu Zhao93a23a72009-05-18 13:51:37 +08001372 iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001373}
1374
mark grossf8bab732008-02-08 04:18:38 -08001375static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
1376{
1377 u32 pmen;
1378 unsigned long flags;
1379
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001380 raw_spin_lock_irqsave(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001381 pmen = readl(iommu->reg + DMAR_PMEN_REG);
1382 pmen &= ~DMA_PMEN_EPM;
1383 writel(pmen, iommu->reg + DMAR_PMEN_REG);
1384
1385 /* wait for the protected region status bit to clear */
1386 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
1387 readl, !(pmen & DMA_PMEN_PRS), pmen);
1388
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001389 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
mark grossf8bab732008-02-08 04:18:38 -08001390}
1391
Jiang Liu2a41cce2014-07-11 14:19:33 +08001392static void iommu_enable_translation(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001393{
1394 u32 sts;
1395 unsigned long flags;
1396
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001397 raw_spin_lock_irqsave(&iommu->register_lock, flags);
David Woodhousec416daa2009-05-10 20:30:58 +01001398 iommu->gcmd |= DMA_GCMD_TE;
1399 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001400
1401 /* Make sure hardware complete it */
1402 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001403 readl, (sts & DMA_GSTS_TES), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001404
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001405 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001406}
1407
Jiang Liu2a41cce2014-07-11 14:19:33 +08001408static void iommu_disable_translation(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001409{
1410 u32 sts;
1411 unsigned long flag;
1412
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001413 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001414 iommu->gcmd &= ~DMA_GCMD_TE;
1415 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
1416
1417 /* Make sure hardware complete it */
1418 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
David Woodhousec416daa2009-05-10 20:30:58 +01001419 readl, (!(sts & DMA_GSTS_TES)), sts);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001420
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02001421 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001422}
1423
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07001424
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001425static int iommu_init_domains(struct intel_iommu *iommu)
1426{
1427 unsigned long ndomains;
1428 unsigned long nlongs;
1429
1430 ndomains = cap_ndoms(iommu->cap);
Jiang Liu852bdb02014-01-06 14:18:11 +08001431 pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
1432 iommu->seq_id, ndomains);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001433 nlongs = BITS_TO_LONGS(ndomains);
1434
Donald Dutile94a91b502009-08-20 16:51:34 -04001435 spin_lock_init(&iommu->lock);
1436
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001437 /* TBD: there might be 64K domains,
1438 * consider other allocation for future chip
1439 */
1440 iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
1441 if (!iommu->domain_ids) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001442 pr_err("IOMMU%d: allocating domain id array failed\n",
1443 iommu->seq_id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001444 return -ENOMEM;
1445 }
1446 iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1447 GFP_KERNEL);
1448 if (!iommu->domains) {
Jiang Liu852bdb02014-01-06 14:18:11 +08001449 pr_err("IOMMU%d: allocating domain array failed\n",
1450 iommu->seq_id);
1451 kfree(iommu->domain_ids);
1452 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001453 return -ENOMEM;
1454 }
1455
1456 /*
1457 * if Caching mode is set, then invalid translations are tagged
1458 * with domainid 0. Hence we need to pre-allocate it.
1459 */
1460 if (cap_caching_mode(iommu->cap))
1461 set_bit(0, iommu->domain_ids);
1462 return 0;
1463}
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001464
Jiang Liua868e6b2014-01-06 14:18:20 +08001465static void free_dmar_iommu(struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001466{
1467 struct dmar_domain *domain;
Jiang Liu2a46ddf2014-07-11 14:19:30 +08001468 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001469
Donald Dutile94a91b502009-08-20 16:51:34 -04001470 if ((iommu->domains) && (iommu->domain_ids)) {
Akinobu Mitaa45946a2010-03-11 14:04:08 -08001471 for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
Jiang Liua4eaa862014-02-19 14:07:30 +08001472 /*
1473 * Domain id 0 is reserved for invalid translation
1474 * if hardware supports caching mode.
1475 */
1476 if (cap_caching_mode(iommu->cap) && i == 0)
1477 continue;
1478
Donald Dutile94a91b502009-08-20 16:51:34 -04001479 domain = iommu->domains[i];
1480 clear_bit(i, iommu->domain_ids);
Jiang Liu129ad282014-07-11 14:19:31 +08001481 if (domain_detach_iommu(domain, iommu) == 0 &&
1482 !domain_type_is_vm(domain))
Jiang Liu92d03cc2014-02-19 14:07:28 +08001483 domain_exit(domain);
Weidong Han5e98c4b2008-12-08 23:03:27 +08001484 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001485 }
1486
1487 if (iommu->gcmd & DMA_GCMD_TE)
1488 iommu_disable_translation(iommu);
1489
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001490 kfree(iommu->domains);
1491 kfree(iommu->domain_ids);
Jiang Liua868e6b2014-01-06 14:18:20 +08001492 iommu->domains = NULL;
1493 iommu->domain_ids = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001494
Weidong Hand9630fe2008-12-08 11:06:32 +08001495 g_iommus[iommu->seq_id] = NULL;
1496
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001497 /* free context mapping */
1498 free_context_table(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001499}
1500
Jiang Liuab8dfe22014-07-11 14:19:27 +08001501static struct dmar_domain *alloc_domain(int flags)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001502{
Jiang Liu92d03cc2014-02-19 14:07:28 +08001503 /* domain id for virtual machine, it won't be set in context */
1504 static atomic_t vm_domid = ATOMIC_INIT(0);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001505 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001506
1507 domain = alloc_domain_mem();
1508 if (!domain)
1509 return NULL;
1510
Jiang Liuab8dfe22014-07-11 14:19:27 +08001511 memset(domain, 0, sizeof(*domain));
Suresh Siddha4c923d42009-10-02 11:01:24 -07001512 domain->nid = -1;
Jiang Liuab8dfe22014-07-11 14:19:27 +08001513 domain->flags = flags;
Jiang Liu92d03cc2014-02-19 14:07:28 +08001514 spin_lock_init(&domain->iommu_lock);
1515 INIT_LIST_HEAD(&domain->devices);
Jiang Liuab8dfe22014-07-11 14:19:27 +08001516 if (flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
Jiang Liu92d03cc2014-02-19 14:07:28 +08001517 domain->id = atomic_inc_return(&vm_domid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001518
1519 return domain;
1520}
1521
Jiang Liufb170fb2014-07-11 14:19:28 +08001522static int __iommu_attach_domain(struct dmar_domain *domain,
1523 struct intel_iommu *iommu)
1524{
1525 int num;
1526 unsigned long ndomains;
1527
1528 ndomains = cap_ndoms(iommu->cap);
1529 num = find_first_zero_bit(iommu->domain_ids, ndomains);
1530 if (num < ndomains) {
1531 set_bit(num, iommu->domain_ids);
1532 iommu->domains[num] = domain;
1533 } else {
1534 num = -ENOSPC;
1535 }
1536
1537 return num;
1538}
1539
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001540static int iommu_attach_domain(struct dmar_domain *domain,
1541 struct intel_iommu *iommu)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001542{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001543 int num;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001544 unsigned long flags;
1545
Weidong Han8c11e792008-12-08 15:29:22 +08001546 spin_lock_irqsave(&iommu->lock, flags);
Jiang Liufb170fb2014-07-11 14:19:28 +08001547 num = __iommu_attach_domain(domain, iommu);
Jiang Liu44bde612014-07-11 14:19:29 +08001548 spin_unlock_irqrestore(&iommu->lock, flags);
Jiang Liufb170fb2014-07-11 14:19:28 +08001549 if (num < 0)
1550 pr_err("IOMMU: no free domain ids\n");
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001551
Jiang Liufb170fb2014-07-11 14:19:28 +08001552 return num;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001553}
1554
Jiang Liu44bde612014-07-11 14:19:29 +08001555static int iommu_attach_vm_domain(struct dmar_domain *domain,
1556 struct intel_iommu *iommu)
1557{
1558 int num;
1559 unsigned long ndomains;
1560
1561 ndomains = cap_ndoms(iommu->cap);
1562 for_each_set_bit(num, iommu->domain_ids, ndomains)
1563 if (iommu->domains[num] == domain)
1564 return num;
1565
1566 return __iommu_attach_domain(domain, iommu);
1567}
1568
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001569static void iommu_detach_domain(struct dmar_domain *domain,
1570 struct intel_iommu *iommu)
1571{
1572 unsigned long flags;
1573 int num, ndomains;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001574
1575 spin_lock_irqsave(&iommu->lock, flags);
Jiang Liufb170fb2014-07-11 14:19:28 +08001576 if (domain_type_is_vm_or_si(domain)) {
1577 ndomains = cap_ndoms(iommu->cap);
1578 for_each_set_bit(num, iommu->domain_ids, ndomains) {
1579 if (iommu->domains[num] == domain) {
1580 clear_bit(num, iommu->domain_ids);
1581 iommu->domains[num] = NULL;
1582 break;
1583 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001584 }
Jiang Liufb170fb2014-07-11 14:19:28 +08001585 } else {
1586 clear_bit(domain->id, iommu->domain_ids);
1587 iommu->domains[domain->id] = NULL;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001588 }
Weidong Han8c11e792008-12-08 15:29:22 +08001589 spin_unlock_irqrestore(&iommu->lock, flags);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001590}
1591
Jiang Liufb170fb2014-07-11 14:19:28 +08001592static void domain_attach_iommu(struct dmar_domain *domain,
1593 struct intel_iommu *iommu)
1594{
1595 unsigned long flags;
1596
1597 spin_lock_irqsave(&domain->iommu_lock, flags);
1598 if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
1599 domain->iommu_count++;
1600 if (domain->iommu_count == 1)
1601 domain->nid = iommu->node;
1602 domain_update_iommu_cap(domain);
1603 }
1604 spin_unlock_irqrestore(&domain->iommu_lock, flags);
1605}
1606
1607static int domain_detach_iommu(struct dmar_domain *domain,
1608 struct intel_iommu *iommu)
1609{
1610 unsigned long flags;
1611 int count = INT_MAX;
1612
1613 spin_lock_irqsave(&domain->iommu_lock, flags);
1614 if (test_and_clear_bit(iommu->seq_id, domain->iommu_bmp)) {
1615 count = --domain->iommu_count;
1616 domain_update_iommu_cap(domain);
1617 }
1618 spin_unlock_irqrestore(&domain->iommu_lock, flags);
1619
1620 return count;
1621}
1622
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001623static struct iova_domain reserved_iova_list;
Mark Gross8a443df2008-03-04 14:59:31 -08001624static struct lock_class_key reserved_rbtree_key;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001625
Joseph Cihula51a63e62011-03-21 11:04:24 -07001626static int dmar_init_reserved_ranges(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001627{
1628 struct pci_dev *pdev = NULL;
1629 struct iova *iova;
1630 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001631
David Millerf6611972008-02-06 01:36:23 -08001632 init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001633
Mark Gross8a443df2008-03-04 14:59:31 -08001634 lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
1635 &reserved_rbtree_key);
1636
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001637 /* IOAPIC ranges shouldn't be accessed by DMA */
1638 iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
1639 IOVA_PFN(IOAPIC_RANGE_END));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001640 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001641 printk(KERN_ERR "Reserve IOAPIC range failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001642 return -ENODEV;
1643 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001644
1645 /* Reserve all PCI MMIO to avoid peer-to-peer access */
1646 for_each_pci_dev(pdev) {
1647 struct resource *r;
1648
1649 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1650 r = &pdev->resource[i];
1651 if (!r->flags || !(r->flags & IORESOURCE_MEM))
1652 continue;
David Woodhouse1a4a4552009-06-28 16:00:42 +01001653 iova = reserve_iova(&reserved_iova_list,
1654 IOVA_PFN(r->start),
1655 IOVA_PFN(r->end));
Joseph Cihula51a63e62011-03-21 11:04:24 -07001656 if (!iova) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001657 printk(KERN_ERR "Reserve iova failed\n");
Joseph Cihula51a63e62011-03-21 11:04:24 -07001658 return -ENODEV;
1659 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001660 }
1661 }
Joseph Cihula51a63e62011-03-21 11:04:24 -07001662 return 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001663}
1664
1665static void domain_reserve_special_ranges(struct dmar_domain *domain)
1666{
1667 copy_reserved_iova(&reserved_iova_list, &domain->iovad);
1668}
1669
1670static inline int guestwidth_to_adjustwidth(int gaw)
1671{
1672 int agaw;
1673 int r = (gaw - 12) % 9;
1674
1675 if (r == 0)
1676 agaw = gaw;
1677 else
1678 agaw = gaw + 9 - r;
1679 if (agaw > 64)
1680 agaw = 64;
1681 return agaw;
1682}
1683
1684static int domain_init(struct dmar_domain *domain, int guest_width)
1685{
1686 struct intel_iommu *iommu;
1687 int adjust_width, agaw;
1688 unsigned long sagaw;
1689
David Millerf6611972008-02-06 01:36:23 -08001690 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001691 domain_reserve_special_ranges(domain);
1692
1693 /* calculate AGAW */
Weidong Han8c11e792008-12-08 15:29:22 +08001694 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001695 if (guest_width > cap_mgaw(iommu->cap))
1696 guest_width = cap_mgaw(iommu->cap);
1697 domain->gaw = guest_width;
1698 adjust_width = guestwidth_to_adjustwidth(guest_width);
1699 agaw = width_to_agaw(adjust_width);
1700 sagaw = cap_sagaw(iommu->cap);
1701 if (!test_bit(agaw, &sagaw)) {
1702 /* hardware doesn't support it, choose a bigger one */
1703 pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
1704 agaw = find_next_bit(&sagaw, 5, agaw);
1705 if (agaw >= 5)
1706 return -ENODEV;
1707 }
1708 domain->agaw = agaw;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001709
Weidong Han8e6040972008-12-08 15:49:06 +08001710 if (ecap_coherent(iommu->ecap))
1711 domain->iommu_coherency = 1;
1712 else
1713 domain->iommu_coherency = 0;
1714
Sheng Yang58c610b2009-03-18 15:33:05 +08001715 if (ecap_sc_support(iommu->ecap))
1716 domain->iommu_snooping = 1;
1717 else
1718 domain->iommu_snooping = 0;
1719
David Woodhouse214e39a2014-03-19 10:38:49 +00001720 if (intel_iommu_superpage)
1721 domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
1722 else
1723 domain->iommu_superpage = 0;
1724
Suresh Siddha4c923d42009-10-02 11:01:24 -07001725 domain->nid = iommu->node;
Weidong Hanc7151a82008-12-08 22:51:37 +08001726
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001727 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07001728 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001729 if (!domain->pgd)
1730 return -ENOMEM;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07001731 __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001732 return 0;
1733}
1734
1735static void domain_exit(struct dmar_domain *domain)
1736{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001737 struct dmar_drhd_unit *drhd;
1738 struct intel_iommu *iommu;
David Woodhouseea8ea462014-03-05 17:09:32 +00001739 struct page *freelist = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001740
1741 /* Domain 0 is reserved, so dont process it */
1742 if (!domain)
1743 return;
1744
Alex Williamson7b668352011-05-24 12:02:41 +01001745 /* Flush any lazy unmaps that may reference this domain */
1746 if (!intel_iommu_strict)
1747 flush_unmaps_timeout(0);
1748
Jiang Liu92d03cc2014-02-19 14:07:28 +08001749 /* remove associated devices */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001750 domain_remove_dev_info(domain);
Jiang Liu92d03cc2014-02-19 14:07:28 +08001751
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001752 /* destroy iovas */
1753 put_iova_domain(&domain->iovad);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001754
David Woodhouseea8ea462014-03-05 17:09:32 +00001755 freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001756
Jiang Liu92d03cc2014-02-19 14:07:28 +08001757 /* clear attached or cached domains */
Jiang Liu0e2426122014-02-19 14:07:34 +08001758 rcu_read_lock();
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001759 for_each_active_iommu(iommu, drhd)
Jiang Liufb170fb2014-07-11 14:19:28 +08001760 iommu_detach_domain(domain, iommu);
Jiang Liu0e2426122014-02-19 14:07:34 +08001761 rcu_read_unlock();
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07001762
David Woodhouseea8ea462014-03-05 17:09:32 +00001763 dma_free_pagelist(freelist);
1764
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001765 free_domain_mem(domain);
1766}
1767
David Woodhouse64ae8922014-03-09 12:52:30 -07001768static int domain_context_mapping_one(struct dmar_domain *domain,
1769 struct intel_iommu *iommu,
1770 u8 bus, u8 devfn, int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001771{
1772 struct context_entry *context;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001773 unsigned long flags;
Weidong Hanea6606b2008-12-08 23:08:15 +08001774 struct dma_pte *pgd;
Weidong Hanea6606b2008-12-08 23:08:15 +08001775 int id;
1776 int agaw;
Yu Zhao93a23a72009-05-18 13:51:37 +08001777 struct device_domain_info *info = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001778
1779 pr_debug("Set context mapping for %02x:%02x.%d\n",
1780 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001781
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001782 BUG_ON(!domain->pgd);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001783 BUG_ON(translation != CONTEXT_TT_PASS_THROUGH &&
1784 translation != CONTEXT_TT_MULTI_LEVEL);
Weidong Han5331fe62008-12-08 23:00:00 +08001785
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001786 context = device_to_context_entry(iommu, bus, devfn);
1787 if (!context)
1788 return -ENOMEM;
1789 spin_lock_irqsave(&iommu->lock, flags);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001790 if (context_present(context)) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001791 spin_unlock_irqrestore(&iommu->lock, flags);
1792 return 0;
1793 }
1794
Weidong Hanea6606b2008-12-08 23:08:15 +08001795 id = domain->id;
1796 pgd = domain->pgd;
1797
Jiang Liuab8dfe22014-07-11 14:19:27 +08001798 if (domain_type_is_vm_or_si(domain)) {
Jiang Liu44bde612014-07-11 14:19:29 +08001799 if (domain_type_is_vm(domain)) {
1800 id = iommu_attach_vm_domain(domain, iommu);
Jiang Liufb170fb2014-07-11 14:19:28 +08001801 if (id < 0) {
Weidong Hanea6606b2008-12-08 23:08:15 +08001802 spin_unlock_irqrestore(&iommu->lock, flags);
Jiang Liufb170fb2014-07-11 14:19:28 +08001803 pr_err("IOMMU: no free domain ids\n");
Weidong Hanea6606b2008-12-08 23:08:15 +08001804 return -EFAULT;
1805 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001806 }
1807
1808 /* Skip top levels of page tables for
1809 * iommu which has less agaw than default.
Chris Wright1672af12009-12-02 12:06:34 -08001810 * Unnecessary for PT mode.
Weidong Hanea6606b2008-12-08 23:08:15 +08001811 */
Chris Wright1672af12009-12-02 12:06:34 -08001812 if (translation != CONTEXT_TT_PASS_THROUGH) {
1813 for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) {
1814 pgd = phys_to_virt(dma_pte_addr(pgd));
1815 if (!dma_pte_present(pgd)) {
1816 spin_unlock_irqrestore(&iommu->lock, flags);
1817 return -ENOMEM;
1818 }
Weidong Hanea6606b2008-12-08 23:08:15 +08001819 }
1820 }
1821 }
1822
1823 context_set_domain_id(context, id);
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001824
Yu Zhao93a23a72009-05-18 13:51:37 +08001825 if (translation != CONTEXT_TT_PASS_THROUGH) {
David Woodhouse64ae8922014-03-09 12:52:30 -07001826 info = iommu_support_dev_iotlb(domain, iommu, bus, devfn);
Yu Zhao93a23a72009-05-18 13:51:37 +08001827 translation = info ? CONTEXT_TT_DEV_IOTLB :
1828 CONTEXT_TT_MULTI_LEVEL;
1829 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001830 /*
1831 * In pass through mode, AW must be programmed to indicate the largest
1832 * AGAW value supported by hardware. And ASR is ignored by hardware.
1833 */
Yu Zhao93a23a72009-05-18 13:51:37 +08001834 if (unlikely(translation == CONTEXT_TT_PASS_THROUGH))
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001835 context_set_address_width(context, iommu->msagaw);
Yu Zhao93a23a72009-05-18 13:51:37 +08001836 else {
1837 context_set_address_root(context, virt_to_phys(pgd));
1838 context_set_address_width(context, iommu->agaw);
1839 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001840
1841 context_set_translation_type(context, translation);
Mark McLoughlinc07e7d22008-11-21 16:54:46 +00001842 context_set_fault_enable(context);
1843 context_set_present(context);
Weidong Han5331fe62008-12-08 23:00:00 +08001844 domain_flush_cache(domain, context, sizeof(*context));
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001845
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001846 /*
1847 * It's a non-present to present mapping. If hardware doesn't cache
1848 * non-present entry we only need to flush the write-buffer. If the
1849 * _does_ cache non-present entries, then it does so in the special
1850 * domain #0, which we have to flush:
1851 */
1852 if (cap_caching_mode(iommu->cap)) {
1853 iommu->flush.flush_context(iommu, 0,
1854 (((u16)bus) << 8) | devfn,
1855 DMA_CCMD_MASK_NOBIT,
1856 DMA_CCMD_DEVICE_INVL);
Jiang Liu18fd7792014-07-11 14:19:26 +08001857 iommu->flush.flush_iotlb(iommu, id, 0, 0, DMA_TLB_DSI_FLUSH);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001858 } else {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001859 iommu_flush_write_buffer(iommu);
David Woodhouse4c25a2c2009-05-10 17:16:06 +01001860 }
Yu Zhao93a23a72009-05-18 13:51:37 +08001861 iommu_enable_dev_iotlb(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001862 spin_unlock_irqrestore(&iommu->lock, flags);
Weidong Hanc7151a82008-12-08 22:51:37 +08001863
Jiang Liufb170fb2014-07-11 14:19:28 +08001864 domain_attach_iommu(domain, iommu);
1865
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001866 return 0;
1867}
1868
Alex Williamson579305f2014-07-03 09:51:43 -06001869struct domain_context_mapping_data {
1870 struct dmar_domain *domain;
1871 struct intel_iommu *iommu;
1872 int translation;
1873};
1874
1875static int domain_context_mapping_cb(struct pci_dev *pdev,
1876 u16 alias, void *opaque)
1877{
1878 struct domain_context_mapping_data *data = opaque;
1879
1880 return domain_context_mapping_one(data->domain, data->iommu,
1881 PCI_BUS_NUM(alias), alias & 0xff,
1882 data->translation);
1883}
1884
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001885static int
David Woodhousee1f167f2014-03-09 15:24:46 -07001886domain_context_mapping(struct dmar_domain *domain, struct device *dev,
1887 int translation)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001888{
David Woodhouse64ae8922014-03-09 12:52:30 -07001889 struct intel_iommu *iommu;
David Woodhouse156baca2014-03-09 14:00:57 -07001890 u8 bus, devfn;
Alex Williamson579305f2014-07-03 09:51:43 -06001891 struct domain_context_mapping_data data;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001892
David Woodhousee1f167f2014-03-09 15:24:46 -07001893 iommu = device_to_iommu(dev, &bus, &devfn);
David Woodhouse64ae8922014-03-09 12:52:30 -07001894 if (!iommu)
1895 return -ENODEV;
1896
Alex Williamson579305f2014-07-03 09:51:43 -06001897 if (!dev_is_pci(dev))
1898 return domain_context_mapping_one(domain, iommu, bus, devfn,
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07001899 translation);
Alex Williamson579305f2014-07-03 09:51:43 -06001900
1901 data.domain = domain;
1902 data.iommu = iommu;
1903 data.translation = translation;
1904
1905 return pci_for_each_dma_alias(to_pci_dev(dev),
1906 &domain_context_mapping_cb, &data);
1907}
1908
1909static int domain_context_mapped_cb(struct pci_dev *pdev,
1910 u16 alias, void *opaque)
1911{
1912 struct intel_iommu *iommu = opaque;
1913
1914 return !device_context_mapped(iommu, PCI_BUS_NUM(alias), alias & 0xff);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001915}
1916
David Woodhousee1f167f2014-03-09 15:24:46 -07001917static int domain_context_mapped(struct device *dev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001918{
Weidong Han5331fe62008-12-08 23:00:00 +08001919 struct intel_iommu *iommu;
David Woodhouse156baca2014-03-09 14:00:57 -07001920 u8 bus, devfn;
Weidong Han5331fe62008-12-08 23:00:00 +08001921
David Woodhousee1f167f2014-03-09 15:24:46 -07001922 iommu = device_to_iommu(dev, &bus, &devfn);
Weidong Han5331fe62008-12-08 23:00:00 +08001923 if (!iommu)
1924 return -ENODEV;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001925
Alex Williamson579305f2014-07-03 09:51:43 -06001926 if (!dev_is_pci(dev))
1927 return device_context_mapped(iommu, bus, devfn);
David Woodhousee1f167f2014-03-09 15:24:46 -07001928
Alex Williamson579305f2014-07-03 09:51:43 -06001929 return !pci_for_each_dma_alias(to_pci_dev(dev),
1930 domain_context_mapped_cb, iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07001931}
1932
Fenghua Yuf5329592009-08-04 15:09:37 -07001933/* Returns a number of VTD pages, but aligned to MM page size */
1934static inline unsigned long aligned_nrpages(unsigned long host_addr,
1935 size_t size)
1936{
1937 host_addr &= ~PAGE_MASK;
1938 return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
1939}
1940
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001941/* Return largest possible superpage level for a given mapping */
1942static inline int hardware_largepage_caps(struct dmar_domain *domain,
1943 unsigned long iov_pfn,
1944 unsigned long phy_pfn,
1945 unsigned long pages)
1946{
1947 int support, level = 1;
1948 unsigned long pfnmerge;
1949
1950 support = domain->iommu_superpage;
1951
1952 /* To use a large page, the virtual *and* physical addresses
1953 must be aligned to 2MiB/1GiB/etc. Lower bits set in either
1954 of them will mean we have to use smaller pages. So just
1955 merge them and check both at once. */
1956 pfnmerge = iov_pfn | phy_pfn;
1957
1958 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
1959 pages >>= VTD_STRIDE_SHIFT;
1960 if (!pages)
1961 break;
1962 pfnmerge >>= VTD_STRIDE_SHIFT;
1963 level++;
1964 support--;
1965 }
1966 return level;
1967}
1968
David Woodhouse9051aa02009-06-29 12:30:54 +01001969static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
1970 struct scatterlist *sg, unsigned long phys_pfn,
1971 unsigned long nr_pages, int prot)
David Woodhousee1605492009-06-29 11:17:38 +01001972{
1973 struct dma_pte *first_pte = NULL, *pte = NULL;
David Woodhouse9051aa02009-06-29 12:30:54 +01001974 phys_addr_t uninitialized_var(pteval);
David Woodhousee1605492009-06-29 11:17:38 +01001975 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
David Woodhouse9051aa02009-06-29 12:30:54 +01001976 unsigned long sg_res;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001977 unsigned int largepage_lvl = 0;
1978 unsigned long lvl_pages = 0;
David Woodhousee1605492009-06-29 11:17:38 +01001979
1980 BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
1981
1982 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
1983 return -EINVAL;
1984
1985 prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
1986
David Woodhouse9051aa02009-06-29 12:30:54 +01001987 if (sg)
1988 sg_res = 0;
1989 else {
1990 sg_res = nr_pages + 1;
1991 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
1992 }
1993
Youquan Song6dd9a7c2011-05-25 19:13:49 +01001994 while (nr_pages > 0) {
David Woodhousec85994e2009-07-01 19:21:24 +01001995 uint64_t tmp;
1996
David Woodhousee1605492009-06-29 11:17:38 +01001997 if (!sg_res) {
Fenghua Yuf5329592009-08-04 15:09:37 -07001998 sg_res = aligned_nrpages(sg->offset, sg->length);
David Woodhousee1605492009-06-29 11:17:38 +01001999 sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
2000 sg->dma_length = sg->length;
2001 pteval = page_to_phys(sg_page(sg)) | prot;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002002 phys_pfn = pteval >> VTD_PAGE_SHIFT;
David Woodhousee1605492009-06-29 11:17:38 +01002003 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002004
David Woodhousee1605492009-06-29 11:17:38 +01002005 if (!pte) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002006 largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
2007
David Woodhouse5cf0a762014-03-19 16:07:49 +00002008 first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, &largepage_lvl);
David Woodhousee1605492009-06-29 11:17:38 +01002009 if (!pte)
2010 return -ENOMEM;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002011 /* It is large page*/
Woodhouse, David6491d4d2012-12-19 13:25:35 +00002012 if (largepage_lvl > 1) {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002013 pteval |= DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00002014 /* Ensure that old small page tables are removed to make room
2015 for superpage, if they exist. */
2016 dma_pte_clear_range(domain, iov_pfn,
2017 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
2018 dma_pte_free_pagetable(domain, iov_pfn,
2019 iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
2020 } else {
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002021 pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
Woodhouse, David6491d4d2012-12-19 13:25:35 +00002022 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002023
David Woodhousee1605492009-06-29 11:17:38 +01002024 }
2025 /* We don't need lock here, nobody else
2026 * touches the iova range
2027 */
David Woodhouse7766a3f2009-07-01 20:27:03 +01002028 tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
David Woodhousec85994e2009-07-01 19:21:24 +01002029 if (tmp) {
David Woodhouse1bf20f02009-06-29 22:06:43 +01002030 static int dumps = 5;
David Woodhousec85994e2009-07-01 19:21:24 +01002031 printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
2032 iov_pfn, tmp, (unsigned long long)pteval);
David Woodhouse1bf20f02009-06-29 22:06:43 +01002033 if (dumps) {
2034 dumps--;
2035 debug_dma_dump_mappings(NULL);
2036 }
2037 WARN_ON(1);
2038 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002039
2040 lvl_pages = lvl_to_nr_pages(largepage_lvl);
2041
2042 BUG_ON(nr_pages < lvl_pages);
2043 BUG_ON(sg_res < lvl_pages);
2044
2045 nr_pages -= lvl_pages;
2046 iov_pfn += lvl_pages;
2047 phys_pfn += lvl_pages;
2048 pteval += lvl_pages * VTD_PAGE_SIZE;
2049 sg_res -= lvl_pages;
2050
2051 /* If the next PTE would be the first in a new page, then we
2052 need to flush the cache on the entries we've just written.
2053 And then we'll need to recalculate 'pte', so clear it and
2054 let it get set again in the if (!pte) block above.
2055
2056 If we're done (!nr_pages) we need to flush the cache too.
2057
2058 Also if we've been setting superpages, we may need to
2059 recalculate 'pte' and switch back to smaller pages for the
2060 end of the mapping, if the trailing size is not enough to
2061 use another superpage (i.e. sg_res < lvl_pages). */
David Woodhousee1605492009-06-29 11:17:38 +01002062 pte++;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002063 if (!nr_pages || first_pte_in_page(pte) ||
2064 (largepage_lvl > 1 && sg_res < lvl_pages)) {
David Woodhousee1605492009-06-29 11:17:38 +01002065 domain_flush_cache(domain, first_pte,
2066 (void *)pte - (void *)first_pte);
2067 pte = NULL;
2068 }
Youquan Song6dd9a7c2011-05-25 19:13:49 +01002069
2070 if (!sg_res && nr_pages)
David Woodhousee1605492009-06-29 11:17:38 +01002071 sg = sg_next(sg);
2072 }
2073 return 0;
2074}
2075
David Woodhouse9051aa02009-06-29 12:30:54 +01002076static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
2077 struct scatterlist *sg, unsigned long nr_pages,
2078 int prot)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002079{
David Woodhouse9051aa02009-06-29 12:30:54 +01002080 return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
2081}
Fenghua Yu5b6985c2008-10-16 18:02:32 -07002082
David Woodhouse9051aa02009-06-29 12:30:54 +01002083static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
2084 unsigned long phys_pfn, unsigned long nr_pages,
2085 int prot)
2086{
2087 return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002088}
2089
Weidong Hanc7151a82008-12-08 22:51:37 +08002090static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002091{
Weidong Hanc7151a82008-12-08 22:51:37 +08002092 if (!iommu)
2093 return;
Weidong Han8c11e792008-12-08 15:29:22 +08002094
2095 clear_context_table(iommu, bus, devfn);
2096 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002097 DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002098 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002099}
2100
David Woodhouse109b9b02012-05-25 17:43:02 +01002101static inline void unlink_domain_info(struct device_domain_info *info)
2102{
2103 assert_spin_locked(&device_domain_lock);
2104 list_del(&info->link);
2105 list_del(&info->global);
2106 if (info->dev)
David Woodhouse0bcb3e22014-03-06 17:12:03 +00002107 info->dev->archdata.iommu = NULL;
David Woodhouse109b9b02012-05-25 17:43:02 +01002108}
2109
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002110static void domain_remove_dev_info(struct dmar_domain *domain)
2111{
Yijing Wang3a74ca02014-05-20 20:37:47 +08002112 struct device_domain_info *info, *tmp;
Jiang Liufb170fb2014-07-11 14:19:28 +08002113 unsigned long flags;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002114
2115 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wang3a74ca02014-05-20 20:37:47 +08002116 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
David Woodhouse109b9b02012-05-25 17:43:02 +01002117 unlink_domain_info(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002118 spin_unlock_irqrestore(&device_domain_lock, flags);
2119
Yu Zhao93a23a72009-05-18 13:51:37 +08002120 iommu_disable_dev_iotlb(info);
David Woodhouse7c7faa12014-03-09 13:33:06 -07002121 iommu_detach_dev(info->iommu, info->bus, info->devfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002122
Jiang Liuab8dfe22014-07-11 14:19:27 +08002123 if (domain_type_is_vm(domain)) {
David Woodhouse7c7faa12014-03-09 13:33:06 -07002124 iommu_detach_dependent_devices(info->iommu, info->dev);
Jiang Liufb170fb2014-07-11 14:19:28 +08002125 domain_detach_iommu(domain, info->iommu);
Jiang Liu92d03cc2014-02-19 14:07:28 +08002126 }
2127
2128 free_devinfo_mem(info);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002129 spin_lock_irqsave(&device_domain_lock, flags);
2130 }
2131 spin_unlock_irqrestore(&device_domain_lock, flags);
2132}
2133
2134/*
2135 * find_domain
David Woodhouse1525a292014-03-06 16:19:30 +00002136 * Note: we use struct device->archdata.iommu stores the info
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002137 */
David Woodhouse1525a292014-03-06 16:19:30 +00002138static struct dmar_domain *find_domain(struct device *dev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002139{
2140 struct device_domain_info *info;
2141
2142 /* No lock here, assumes no domain exit in normal case */
David Woodhouse1525a292014-03-06 16:19:30 +00002143 info = dev->archdata.iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002144 if (info)
2145 return info->domain;
2146 return NULL;
2147}
2148
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002149static inline struct device_domain_info *
Jiang Liu745f2582014-02-19 14:07:26 +08002150dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
2151{
2152 struct device_domain_info *info;
2153
2154 list_for_each_entry(info, &device_domain_list, global)
David Woodhouse41e80dca2014-03-09 13:55:54 -07002155 if (info->iommu->segment == segment && info->bus == bus &&
Jiang Liu745f2582014-02-19 14:07:26 +08002156 info->devfn == devfn)
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002157 return info;
Jiang Liu745f2582014-02-19 14:07:26 +08002158
2159 return NULL;
2160}
2161
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002162static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu,
David Woodhouse41e80dca2014-03-09 13:55:54 -07002163 int bus, int devfn,
David Woodhouseb718cd32014-03-09 13:11:33 -07002164 struct device *dev,
2165 struct dmar_domain *domain)
Jiang Liu745f2582014-02-19 14:07:26 +08002166{
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002167 struct dmar_domain *found = NULL;
Jiang Liu745f2582014-02-19 14:07:26 +08002168 struct device_domain_info *info;
2169 unsigned long flags;
2170
2171 info = alloc_devinfo_mem();
2172 if (!info)
David Woodhouseb718cd32014-03-09 13:11:33 -07002173 return NULL;
Jiang Liu745f2582014-02-19 14:07:26 +08002174
Jiang Liu745f2582014-02-19 14:07:26 +08002175 info->bus = bus;
2176 info->devfn = devfn;
2177 info->dev = dev;
2178 info->domain = domain;
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002179 info->iommu = iommu;
Jiang Liu745f2582014-02-19 14:07:26 +08002180
2181 spin_lock_irqsave(&device_domain_lock, flags);
2182 if (dev)
David Woodhouse0bcb3e22014-03-06 17:12:03 +00002183 found = find_domain(dev);
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002184 else {
2185 struct device_domain_info *info2;
David Woodhouse41e80dca2014-03-09 13:55:54 -07002186 info2 = dmar_search_domain_by_dev_info(iommu->segment, bus, devfn);
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002187 if (info2)
2188 found = info2->domain;
2189 }
Jiang Liu745f2582014-02-19 14:07:26 +08002190 if (found) {
2191 spin_unlock_irqrestore(&device_domain_lock, flags);
2192 free_devinfo_mem(info);
David Woodhouseb718cd32014-03-09 13:11:33 -07002193 /* Caller must free the original domain */
2194 return found;
Jiang Liu745f2582014-02-19 14:07:26 +08002195 }
2196
David Woodhouseb718cd32014-03-09 13:11:33 -07002197 list_add(&info->link, &domain->devices);
2198 list_add(&info->global, &device_domain_list);
2199 if (dev)
2200 dev->archdata.iommu = info;
2201 spin_unlock_irqrestore(&device_domain_lock, flags);
2202
2203 return domain;
Jiang Liu745f2582014-02-19 14:07:26 +08002204}
2205
Alex Williamson579305f2014-07-03 09:51:43 -06002206static int get_last_alias(struct pci_dev *pdev, u16 alias, void *opaque)
2207{
2208 *(u16 *)opaque = alias;
2209 return 0;
2210}
2211
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002212/* domain is initialized */
David Woodhouse146922e2014-03-09 15:44:17 -07002213static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002214{
Alex Williamson579305f2014-07-03 09:51:43 -06002215 struct dmar_domain *domain, *tmp;
2216 struct intel_iommu *iommu;
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002217 struct device_domain_info *info;
Alex Williamson579305f2014-07-03 09:51:43 -06002218 u16 dma_alias;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002219 unsigned long flags;
Yijing Wangaa4d0662014-05-26 20:14:06 +08002220 u8 bus, devfn;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002221
David Woodhouse146922e2014-03-09 15:44:17 -07002222 domain = find_domain(dev);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002223 if (domain)
2224 return domain;
2225
David Woodhouse146922e2014-03-09 15:44:17 -07002226 iommu = device_to_iommu(dev, &bus, &devfn);
2227 if (!iommu)
Alex Williamson579305f2014-07-03 09:51:43 -06002228 return NULL;
2229
2230 if (dev_is_pci(dev)) {
2231 struct pci_dev *pdev = to_pci_dev(dev);
2232
2233 pci_for_each_dma_alias(pdev, get_last_alias, &dma_alias);
2234
2235 spin_lock_irqsave(&device_domain_lock, flags);
2236 info = dmar_search_domain_by_dev_info(pci_domain_nr(pdev->bus),
2237 PCI_BUS_NUM(dma_alias),
2238 dma_alias & 0xff);
2239 if (info) {
2240 iommu = info->iommu;
2241 domain = info->domain;
2242 }
2243 spin_unlock_irqrestore(&device_domain_lock, flags);
2244
2245 /* DMA alias already has a domain, uses it */
2246 if (info)
2247 goto found_domain;
2248 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002249
David Woodhouse146922e2014-03-09 15:44:17 -07002250 /* Allocate and initialize new domain for the device */
Jiang Liuab8dfe22014-07-11 14:19:27 +08002251 domain = alloc_domain(0);
Jiang Liu745f2582014-02-19 14:07:26 +08002252 if (!domain)
Alex Williamson579305f2014-07-03 09:51:43 -06002253 return NULL;
Jiang Liu44bde612014-07-11 14:19:29 +08002254 domain->id = iommu_attach_domain(domain, iommu);
2255 if (domain->id < 0) {
Alex Williamson2fe9723d2011-03-04 14:52:30 -07002256 free_domain_mem(domain);
Alex Williamson579305f2014-07-03 09:51:43 -06002257 return NULL;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002258 }
Jiang Liufb170fb2014-07-11 14:19:28 +08002259 domain_attach_iommu(domain, iommu);
Alex Williamson579305f2014-07-03 09:51:43 -06002260 if (domain_init(domain, gaw)) {
2261 domain_exit(domain);
2262 return NULL;
2263 }
2264
2265 /* register PCI DMA alias device */
2266 if (dev_is_pci(dev)) {
2267 tmp = dmar_insert_dev_info(iommu, PCI_BUS_NUM(dma_alias),
2268 dma_alias & 0xff, NULL, domain);
2269
2270 if (!tmp || tmp != domain) {
2271 domain_exit(domain);
2272 domain = tmp;
2273 }
2274
David Woodhouseb718cd32014-03-09 13:11:33 -07002275 if (!domain)
Alex Williamson579305f2014-07-03 09:51:43 -06002276 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002277 }
2278
2279found_domain:
Alex Williamson579305f2014-07-03 09:51:43 -06002280 tmp = dmar_insert_dev_info(iommu, bus, devfn, dev, domain);
2281
2282 if (!tmp || tmp != domain) {
2283 domain_exit(domain);
2284 domain = tmp;
2285 }
David Woodhouseb718cd32014-03-09 13:11:33 -07002286
2287 return domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002288}
2289
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002290static int iommu_identity_mapping;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002291#define IDENTMAP_ALL 1
2292#define IDENTMAP_GFX 2
2293#define IDENTMAP_AZALIA 4
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002294
David Woodhouseb2132032009-06-26 18:50:28 +01002295static int iommu_domain_identity_map(struct dmar_domain *domain,
2296 unsigned long long start,
2297 unsigned long long end)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002298{
David Woodhousec5395d52009-06-28 16:35:56 +01002299 unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
2300 unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002301
David Woodhousec5395d52009-06-28 16:35:56 +01002302 if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
2303 dma_to_mm_pfn(last_vpfn))) {
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002304 printk(KERN_ERR "IOMMU: reserve iova failed\n");
David Woodhouseb2132032009-06-26 18:50:28 +01002305 return -ENOMEM;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002306 }
2307
David Woodhousec5395d52009-06-28 16:35:56 +01002308 pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
2309 start, end, domain->id);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002310 /*
2311 * RMRR range might have overlap with physical memory range,
2312 * clear it first
2313 */
David Woodhousec5395d52009-06-28 16:35:56 +01002314 dma_pte_clear_range(domain, first_vpfn, last_vpfn);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002315
David Woodhousec5395d52009-06-28 16:35:56 +01002316 return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
2317 last_vpfn - first_vpfn + 1,
David Woodhouse61df7442009-06-28 11:55:58 +01002318 DMA_PTE_READ|DMA_PTE_WRITE);
David Woodhouseb2132032009-06-26 18:50:28 +01002319}
2320
David Woodhouse0b9d9752014-03-09 15:48:15 -07002321static int iommu_prepare_identity_map(struct device *dev,
David Woodhouseb2132032009-06-26 18:50:28 +01002322 unsigned long long start,
2323 unsigned long long end)
2324{
2325 struct dmar_domain *domain;
2326 int ret;
2327
David Woodhouse0b9d9752014-03-09 15:48:15 -07002328 domain = get_domain_for_dev(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
David Woodhouseb2132032009-06-26 18:50:28 +01002329 if (!domain)
2330 return -ENOMEM;
2331
David Woodhouse19943b02009-08-04 16:19:20 +01002332 /* For _hardware_ passthrough, don't bother. But for software
2333 passthrough, we do it anyway -- it may indicate a memory
2334 range which is reserved in E820, so which didn't get set
2335 up to start with in si_domain */
2336 if (domain == si_domain && hw_pass_through) {
2337 printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
David Woodhouse0b9d9752014-03-09 15:48:15 -07002338 dev_name(dev), start, end);
David Woodhouse19943b02009-08-04 16:19:20 +01002339 return 0;
2340 }
2341
2342 printk(KERN_INFO
2343 "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
David Woodhouse0b9d9752014-03-09 15:48:15 -07002344 dev_name(dev), start, end);
David Woodhouse2ff729f2009-08-26 14:25:41 +01002345
David Woodhouse5595b522009-12-02 09:21:55 +00002346 if (end < start) {
2347 WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
2348 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2349 dmi_get_system_info(DMI_BIOS_VENDOR),
2350 dmi_get_system_info(DMI_BIOS_VERSION),
2351 dmi_get_system_info(DMI_PRODUCT_VERSION));
2352 ret = -EIO;
2353 goto error;
2354 }
2355
David Woodhouse2ff729f2009-08-26 14:25:41 +01002356 if (end >> agaw_to_width(domain->agaw)) {
2357 WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
2358 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
2359 agaw_to_width(domain->agaw),
2360 dmi_get_system_info(DMI_BIOS_VENDOR),
2361 dmi_get_system_info(DMI_BIOS_VERSION),
2362 dmi_get_system_info(DMI_PRODUCT_VERSION));
2363 ret = -EIO;
2364 goto error;
2365 }
David Woodhouse19943b02009-08-04 16:19:20 +01002366
David Woodhouseb2132032009-06-26 18:50:28 +01002367 ret = iommu_domain_identity_map(domain, start, end);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002368 if (ret)
2369 goto error;
2370
2371 /* context entry init */
David Woodhouse0b9d9752014-03-09 15:48:15 -07002372 ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
David Woodhouseb2132032009-06-26 18:50:28 +01002373 if (ret)
2374 goto error;
2375
2376 return 0;
2377
2378 error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002379 domain_exit(domain);
2380 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002381}
2382
2383static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
David Woodhouse0b9d9752014-03-09 15:48:15 -07002384 struct device *dev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002385{
David Woodhouse0b9d9752014-03-09 15:48:15 -07002386 if (dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002387 return 0;
David Woodhouse0b9d9752014-03-09 15:48:15 -07002388 return iommu_prepare_identity_map(dev, rmrr->base_address,
2389 rmrr->end_address);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002390}
2391
Suresh Siddhad3f13812011-08-23 17:05:25 -07002392#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002393static inline void iommu_prepare_isa(void)
2394{
2395 struct pci_dev *pdev;
2396 int ret;
2397
2398 pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
2399 if (!pdev)
2400 return;
2401
David Woodhousec7ab48d2009-06-26 19:10:36 +01002402 printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
David Woodhouse0b9d9752014-03-09 15:48:15 -07002403 ret = iommu_prepare_identity_map(&pdev->dev, 0, 16*1024*1024 - 1);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002404
2405 if (ret)
David Woodhousec7ab48d2009-06-26 19:10:36 +01002406 printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
2407 "floppy might not work\n");
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002408
Yijing Wang9b27e822014-05-20 20:37:52 +08002409 pci_dev_put(pdev);
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002410}
2411#else
2412static inline void iommu_prepare_isa(void)
2413{
2414 return;
2415}
Suresh Siddhad3f13812011-08-23 17:05:25 -07002416#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002417
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002418static int md_domain_init(struct dmar_domain *domain, int guest_width);
David Woodhousec7ab48d2009-06-26 19:10:36 +01002419
Matt Kraai071e1372009-08-23 22:30:22 -07002420static int __init si_domain_init(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002421{
2422 struct dmar_drhd_unit *drhd;
2423 struct intel_iommu *iommu;
David Woodhousec7ab48d2009-06-26 19:10:36 +01002424 int nid, ret = 0;
Jiang Liu44bde612014-07-11 14:19:29 +08002425 bool first = true;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002426
Jiang Liuab8dfe22014-07-11 14:19:27 +08002427 si_domain = alloc_domain(DOMAIN_FLAG_STATIC_IDENTITY);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002428 if (!si_domain)
2429 return -EFAULT;
2430
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002431 for_each_active_iommu(iommu, drhd) {
2432 ret = iommu_attach_domain(si_domain, iommu);
Jiang Liufb170fb2014-07-11 14:19:28 +08002433 if (ret < 0) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002434 domain_exit(si_domain);
2435 return -EFAULT;
Jiang Liu44bde612014-07-11 14:19:29 +08002436 } else if (first) {
2437 si_domain->id = ret;
2438 first = false;
2439 } else if (si_domain->id != ret) {
2440 domain_exit(si_domain);
2441 return -EFAULT;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002442 }
Jiang Liufb170fb2014-07-11 14:19:28 +08002443 domain_attach_iommu(si_domain, iommu);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002444 }
2445
2446 if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
2447 domain_exit(si_domain);
2448 return -EFAULT;
2449 }
2450
Jiang Liu9544c002014-01-06 14:18:13 +08002451 pr_debug("IOMMU: identity mapping domain is domain %d\n",
2452 si_domain->id);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002453
David Woodhouse19943b02009-08-04 16:19:20 +01002454 if (hw)
2455 return 0;
2456
David Woodhousec7ab48d2009-06-26 19:10:36 +01002457 for_each_online_node(nid) {
Tejun Heod4bbf7e2011-11-28 09:46:22 -08002458 unsigned long start_pfn, end_pfn;
2459 int i;
2460
2461 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
2462 ret = iommu_domain_identity_map(si_domain,
2463 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
2464 if (ret)
2465 return ret;
2466 }
David Woodhousec7ab48d2009-06-26 19:10:36 +01002467 }
2468
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002469 return 0;
2470}
2471
David Woodhouse9b226622014-03-09 14:03:28 -07002472static int identity_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002473{
2474 struct device_domain_info *info;
2475
2476 if (likely(!iommu_identity_mapping))
2477 return 0;
2478
David Woodhouse9b226622014-03-09 14:03:28 -07002479 info = dev->archdata.iommu;
Mike Traviscb452a42011-05-28 13:15:03 -05002480 if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
2481 return (info->domain == si_domain);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002482
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002483 return 0;
2484}
2485
2486static int domain_add_dev_info(struct dmar_domain *domain,
David Woodhouse5913c9b2014-03-09 16:27:31 -07002487 struct device *dev, int translation)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002488{
David Woodhouse0ac72662014-03-09 13:19:22 -07002489 struct dmar_domain *ndomain;
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002490 struct intel_iommu *iommu;
David Woodhouse156baca2014-03-09 14:00:57 -07002491 u8 bus, devfn;
David Woodhouse5fe60f42009-08-09 10:53:41 +01002492 int ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002493
David Woodhouse5913c9b2014-03-09 16:27:31 -07002494 iommu = device_to_iommu(dev, &bus, &devfn);
David Woodhouse5a8f40e2014-03-09 13:31:18 -07002495 if (!iommu)
2496 return -ENODEV;
2497
David Woodhouse5913c9b2014-03-09 16:27:31 -07002498 ndomain = dmar_insert_dev_info(iommu, bus, devfn, dev, domain);
David Woodhouse0ac72662014-03-09 13:19:22 -07002499 if (ndomain != domain)
2500 return -EBUSY;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002501
David Woodhouse5913c9b2014-03-09 16:27:31 -07002502 ret = domain_context_mapping(domain, dev, translation);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002503 if (ret) {
David Woodhouse5913c9b2014-03-09 16:27:31 -07002504 domain_remove_one_dev_info(domain, dev);
David Woodhousee2ad23d2012-05-25 17:42:54 +01002505 return ret;
2506 }
2507
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002508 return 0;
2509}
2510
David Woodhouse0b9d9752014-03-09 15:48:15 -07002511static bool device_has_rmrr(struct device *dev)
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002512{
2513 struct dmar_rmrr_unit *rmrr;
David Woodhouse832bd852014-03-07 15:08:36 +00002514 struct device *tmp;
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002515 int i;
2516
Jiang Liu0e2426122014-02-19 14:07:34 +08002517 rcu_read_lock();
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002518 for_each_rmrr_units(rmrr) {
Jiang Liub683b232014-02-19 14:07:32 +08002519 /*
2520 * Return TRUE if this RMRR contains the device that
2521 * is passed in.
2522 */
2523 for_each_active_dev_scope(rmrr->devices,
2524 rmrr->devices_cnt, i, tmp)
David Woodhouse0b9d9752014-03-09 15:48:15 -07002525 if (tmp == dev) {
Jiang Liu0e2426122014-02-19 14:07:34 +08002526 rcu_read_unlock();
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002527 return true;
Jiang Liub683b232014-02-19 14:07:32 +08002528 }
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002529 }
Jiang Liu0e2426122014-02-19 14:07:34 +08002530 rcu_read_unlock();
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002531 return false;
2532}
2533
David Woodhouse3bdb2592014-03-09 16:03:08 -07002534static int iommu_should_identity_map(struct device *dev, int startup)
David Woodhouse6941af22009-07-04 18:24:27 +01002535{
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002536
David Woodhouse3bdb2592014-03-09 16:03:08 -07002537 if (dev_is_pci(dev)) {
2538 struct pci_dev *pdev = to_pci_dev(dev);
Tom Mingarelliea2447f72012-11-20 19:43:17 +00002539
David Woodhouse3bdb2592014-03-09 16:03:08 -07002540 /*
2541 * We want to prevent any device associated with an RMRR from
2542 * getting placed into the SI Domain. This is done because
2543 * problems exist when devices are moved in and out of domains
2544 * and their respective RMRR info is lost. We exempt USB devices
2545 * from this process due to their usage of RMRRs that are known
2546 * to not be needed after BIOS hand-off to OS.
2547 */
2548 if (device_has_rmrr(dev) &&
2549 (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
2550 return 0;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002551
David Woodhouse3bdb2592014-03-09 16:03:08 -07002552 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
2553 return 1;
David Woodhousee0fc7e02009-09-30 09:12:17 -07002554
David Woodhouse3bdb2592014-03-09 16:03:08 -07002555 if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
2556 return 1;
2557
2558 if (!(iommu_identity_mapping & IDENTMAP_ALL))
2559 return 0;
2560
2561 /*
2562 * We want to start off with all devices in the 1:1 domain, and
2563 * take them out later if we find they can't access all of memory.
2564 *
2565 * However, we can't do this for PCI devices behind bridges,
2566 * because all PCI devices behind the same bridge will end up
2567 * with the same source-id on their transactions.
2568 *
2569 * Practically speaking, we can't change things around for these
2570 * devices at run-time, because we can't be sure there'll be no
2571 * DMA transactions in flight for any of their siblings.
2572 *
2573 * So PCI devices (unless they're on the root bus) as well as
2574 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
2575 * the 1:1 domain, just in _case_ one of their siblings turns out
2576 * not to be able to map all of memory.
2577 */
2578 if (!pci_is_pcie(pdev)) {
2579 if (!pci_is_root_bus(pdev->bus))
2580 return 0;
2581 if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
2582 return 0;
2583 } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
2584 return 0;
2585 } else {
2586 if (device_has_rmrr(dev))
2587 return 0;
2588 }
David Woodhouse6941af22009-07-04 18:24:27 +01002589
David Woodhouse3dfc8132009-07-04 19:11:08 +01002590 /*
David Woodhouse3dfc8132009-07-04 19:11:08 +01002591 * At boot time, we don't yet know if devices will be 64-bit capable.
David Woodhouse3bdb2592014-03-09 16:03:08 -07002592 * Assume that they will — if they turn out not to be, then we can
David Woodhouse3dfc8132009-07-04 19:11:08 +01002593 * take them out of the 1:1 domain later.
2594 */
Chris Wright8fcc5372011-05-28 13:15:02 -05002595 if (!startup) {
2596 /*
2597 * If the device's dma_mask is less than the system's memory
2598 * size then this is not a candidate for identity mapping.
2599 */
David Woodhouse3bdb2592014-03-09 16:03:08 -07002600 u64 dma_mask = *dev->dma_mask;
Chris Wright8fcc5372011-05-28 13:15:02 -05002601
David Woodhouse3bdb2592014-03-09 16:03:08 -07002602 if (dev->coherent_dma_mask &&
2603 dev->coherent_dma_mask < dma_mask)
2604 dma_mask = dev->coherent_dma_mask;
Chris Wright8fcc5372011-05-28 13:15:02 -05002605
David Woodhouse3bdb2592014-03-09 16:03:08 -07002606 return dma_mask >= dma_get_required_mask(dev);
Chris Wright8fcc5372011-05-28 13:15:02 -05002607 }
David Woodhouse6941af22009-07-04 18:24:27 +01002608
2609 return 1;
2610}
2611
David Woodhousecf04eee2014-03-21 16:49:04 +00002612static int __init dev_prepare_static_identity_mapping(struct device *dev, int hw)
2613{
2614 int ret;
2615
2616 if (!iommu_should_identity_map(dev, 1))
2617 return 0;
2618
2619 ret = domain_add_dev_info(si_domain, dev,
2620 hw ? CONTEXT_TT_PASS_THROUGH :
2621 CONTEXT_TT_MULTI_LEVEL);
2622 if (!ret)
2623 pr_info("IOMMU: %s identity mapping for device %s\n",
2624 hw ? "hardware" : "software", dev_name(dev));
2625 else if (ret == -ENODEV)
2626 /* device not associated with an iommu */
2627 ret = 0;
2628
2629 return ret;
2630}
2631
2632
Matt Kraai071e1372009-08-23 22:30:22 -07002633static int __init iommu_prepare_static_identity_mapping(int hw)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002634{
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002635 struct pci_dev *pdev = NULL;
David Woodhousecf04eee2014-03-21 16:49:04 +00002636 struct dmar_drhd_unit *drhd;
2637 struct intel_iommu *iommu;
2638 struct device *dev;
2639 int i;
2640 int ret = 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002641
David Woodhouse19943b02009-08-04 16:19:20 +01002642 ret = si_domain_init(hw);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002643 if (ret)
2644 return -EFAULT;
2645
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002646 for_each_pci_dev(pdev) {
David Woodhousecf04eee2014-03-21 16:49:04 +00002647 ret = dev_prepare_static_identity_mapping(&pdev->dev, hw);
2648 if (ret)
2649 return ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002650 }
2651
David Woodhousecf04eee2014-03-21 16:49:04 +00002652 for_each_active_iommu(iommu, drhd)
2653 for_each_active_dev_scope(drhd->devices, drhd->devices_cnt, i, dev) {
2654 struct acpi_device_physical_node *pn;
2655 struct acpi_device *adev;
2656
2657 if (dev->bus != &acpi_bus_type)
2658 continue;
2659
2660 adev= to_acpi_device(dev);
2661 mutex_lock(&adev->physical_node_lock);
2662 list_for_each_entry(pn, &adev->physical_node_list, node) {
2663 ret = dev_prepare_static_identity_mapping(pn->dev, hw);
2664 if (ret)
2665 break;
2666 }
2667 mutex_unlock(&adev->physical_node_lock);
2668 if (ret)
2669 return ret;
2670 }
2671
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002672 return 0;
2673}
2674
Joseph Cihulab7792602011-05-03 00:08:37 -07002675static int __init init_dmars(void)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002676{
2677 struct dmar_drhd_unit *drhd;
2678 struct dmar_rmrr_unit *rmrr;
David Woodhouse832bd852014-03-07 15:08:36 +00002679 struct device *dev;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002680 struct intel_iommu *iommu;
Suresh Siddha9d783ba2009-03-16 17:04:55 -07002681 int i, ret;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002682
2683 /*
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002684 * for each drhd
2685 * allocate root
2686 * initialize and program root entry to not present
2687 * endfor
2688 */
2689 for_each_drhd_unit(drhd) {
mark gross5e0d2a62008-03-04 15:22:08 -08002690 /*
2691 * lock not needed as this is only incremented in the single
2692 * threaded kernel __init code path all other access are read
2693 * only
2694 */
Mike Travis1b198bb2012-03-05 15:05:16 -08002695 if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
2696 g_num_of_iommus++;
2697 continue;
2698 }
2699 printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
2700 IOMMU_UNITS_SUPPORTED);
mark gross5e0d2a62008-03-04 15:22:08 -08002701 }
2702
Weidong Hand9630fe2008-12-08 11:06:32 +08002703 g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
2704 GFP_KERNEL);
2705 if (!g_iommus) {
2706 printk(KERN_ERR "Allocating global iommu array failed\n");
2707 ret = -ENOMEM;
2708 goto error;
2709 }
2710
mark gross80b20dd2008-04-18 13:53:58 -07002711 deferred_flush = kzalloc(g_num_of_iommus *
2712 sizeof(struct deferred_flush_tables), GFP_KERNEL);
2713 if (!deferred_flush) {
mark gross5e0d2a62008-03-04 15:22:08 -08002714 ret = -ENOMEM;
Jiang Liu989d51f2014-02-19 14:07:21 +08002715 goto free_g_iommus;
mark gross5e0d2a62008-03-04 15:22:08 -08002716 }
2717
Jiang Liu7c919772014-01-06 14:18:18 +08002718 for_each_active_iommu(iommu, drhd) {
Weidong Hand9630fe2008-12-08 11:06:32 +08002719 g_iommus[iommu->seq_id] = iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002720
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002721 ret = iommu_init_domains(iommu);
2722 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002723 goto free_iommu;
Suresh Siddhae61d98d2008-07-10 11:16:35 -07002724
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002725 /*
2726 * TBD:
2727 * we could share the same root & context tables
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002728 * among all IOMMU's. Need to Split it later.
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002729 */
2730 ret = iommu_alloc_root_entry(iommu);
2731 if (ret) {
2732 printk(KERN_ERR "IOMMU: allocate root entry failed\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002733 goto free_iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002734 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002735 if (!ecap_pass_through(iommu->ecap))
David Woodhouse19943b02009-08-04 16:19:20 +01002736 hw_pass_through = 0;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002737 }
2738
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002739 /*
2740 * Start from the sane iommu hardware state.
2741 */
Jiang Liu7c919772014-01-06 14:18:18 +08002742 for_each_active_iommu(iommu, drhd) {
Suresh Siddha1531a6a2009-03-16 17:04:57 -07002743 /*
2744 * If the queued invalidation is already initialized by us
2745 * (for example, while enabling interrupt-remapping) then
2746 * we got the things already rolling from a sane state.
2747 */
2748 if (iommu->qi)
2749 continue;
2750
2751 /*
2752 * Clear any previous faults.
2753 */
2754 dmar_fault(-1, iommu);
2755 /*
2756 * Disable queued invalidation if supported and already enabled
2757 * before OS handover.
2758 */
2759 dmar_disable_qi(iommu);
2760 }
2761
Jiang Liu7c919772014-01-06 14:18:18 +08002762 for_each_active_iommu(iommu, drhd) {
Youquan Songa77b67d2008-10-16 16:31:56 -07002763 if (dmar_enable_qi(iommu)) {
2764 /*
2765 * Queued Invalidate not enabled, use Register Based
2766 * Invalidate
2767 */
2768 iommu->flush.flush_context = __iommu_flush_context;
2769 iommu->flush.flush_iotlb = __iommu_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002770 printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002771 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002772 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002773 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002774 } else {
2775 iommu->flush.flush_context = qi_flush_context;
2776 iommu->flush.flush_iotlb = qi_flush_iotlb;
Yinghai Lu680a7522010-04-08 19:58:23 +01002777 printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002778 "invalidation\n",
Yinghai Lu680a7522010-04-08 19:58:23 +01002779 iommu->seq_id,
FUJITA Tomonorib4e0f9e2008-11-19 13:53:42 +09002780 (unsigned long long)drhd->reg_base_addr);
Youquan Songa77b67d2008-10-16 16:31:56 -07002781 }
2782 }
2783
David Woodhouse19943b02009-08-04 16:19:20 +01002784 if (iommu_pass_through)
David Woodhousee0fc7e02009-09-30 09:12:17 -07002785 iommu_identity_mapping |= IDENTMAP_ALL;
2786
Suresh Siddhad3f13812011-08-23 17:05:25 -07002787#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
David Woodhousee0fc7e02009-09-30 09:12:17 -07002788 iommu_identity_mapping |= IDENTMAP_GFX;
David Woodhouse19943b02009-08-04 16:19:20 +01002789#endif
David Woodhousee0fc7e02009-09-30 09:12:17 -07002790
2791 check_tylersburg_isoch();
2792
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002793 /*
2794 * If pass through is not set or not enabled, setup context entries for
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002795 * identity mappings for rmrr, gfx, and isa and may fall back to static
2796 * identity mapping if iommu_identity_mapping is set.
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002797 */
David Woodhouse19943b02009-08-04 16:19:20 +01002798 if (iommu_identity_mapping) {
2799 ret = iommu_prepare_static_identity_mapping(hw_pass_through);
2800 if (ret) {
2801 printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
Jiang Liu989d51f2014-02-19 14:07:21 +08002802 goto free_iommu;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002803 }
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07002804 }
David Woodhouse19943b02009-08-04 16:19:20 +01002805 /*
2806 * For each rmrr
2807 * for each dev attached to rmrr
2808 * do
2809 * locate drhd for dev, alloc domain for dev
2810 * allocate free domain
2811 * allocate page table entries for rmrr
2812 * if context not allocated for bus
2813 * allocate and init context
2814 * set present in root table for this bus
2815 * init context with domain, translation etc
2816 * endfor
2817 * endfor
2818 */
2819 printk(KERN_INFO "IOMMU: Setting RMRR:\n");
2820 for_each_rmrr_units(rmrr) {
Jiang Liub683b232014-02-19 14:07:32 +08002821 /* some BIOS lists non-exist devices in DMAR table. */
2822 for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
David Woodhouse832bd852014-03-07 15:08:36 +00002823 i, dev) {
David Woodhouse0b9d9752014-03-09 15:48:15 -07002824 ret = iommu_prepare_rmrr_dev(rmrr, dev);
David Woodhouse19943b02009-08-04 16:19:20 +01002825 if (ret)
2826 printk(KERN_ERR
2827 "IOMMU: mapping reserved region failed\n");
2828 }
2829 }
2830
2831 iommu_prepare_isa();
Keshavamurthy, Anil S49a04292007-10-21 16:41:57 -07002832
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002833 /*
2834 * for each drhd
2835 * enable fault log
2836 * global invalidate context cache
2837 * global invalidate iotlb
2838 * enable translation
2839 */
Jiang Liu7c919772014-01-06 14:18:18 +08002840 for_each_iommu(iommu, drhd) {
Joseph Cihula51a63e62011-03-21 11:04:24 -07002841 if (drhd->ignored) {
2842 /*
2843 * we always have to disable PMRs or DMA may fail on
2844 * this device
2845 */
2846 if (force_on)
Jiang Liu7c919772014-01-06 14:18:18 +08002847 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002848 continue;
Joseph Cihula51a63e62011-03-21 11:04:24 -07002849 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002850
2851 iommu_flush_write_buffer(iommu);
2852
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002853 ret = dmar_set_interrupt(iommu);
2854 if (ret)
Jiang Liu989d51f2014-02-19 14:07:21 +08002855 goto free_iommu;
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002856
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002857 iommu_set_root_entry(iommu);
2858
David Woodhouse4c25a2c2009-05-10 17:16:06 +01002859 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01002860 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
Jiang Liu2a41cce2014-07-11 14:19:33 +08002861 iommu_enable_translation(iommu);
David Woodhouseb94996c2009-09-19 15:28:12 -07002862 iommu_disable_protect_mem_regions(iommu);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002863 }
2864
2865 return 0;
Jiang Liu989d51f2014-02-19 14:07:21 +08002866
2867free_iommu:
Jiang Liu7c919772014-01-06 14:18:18 +08002868 for_each_active_iommu(iommu, drhd)
Jiang Liua868e6b2014-01-06 14:18:20 +08002869 free_dmar_iommu(iommu);
Jiang Liu9bdc5312014-01-06 14:18:27 +08002870 kfree(deferred_flush);
Jiang Liu989d51f2014-02-19 14:07:21 +08002871free_g_iommus:
Weidong Hand9630fe2008-12-08 11:06:32 +08002872 kfree(g_iommus);
Jiang Liu989d51f2014-02-19 14:07:21 +08002873error:
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002874 return ret;
2875}
2876
David Woodhouse5a5e02a2009-07-04 09:35:44 +01002877/* This takes a number of _MM_ pages, not VTD pages */
David Woodhouse875764d2009-06-28 21:20:51 +01002878static struct iova *intel_alloc_iova(struct device *dev,
2879 struct dmar_domain *domain,
2880 unsigned long nrpages, uint64_t dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002881{
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002882 struct iova *iova = NULL;
2883
David Woodhouse875764d2009-06-28 21:20:51 +01002884 /* Restrict dma_mask to the width that the iommu can handle */
2885 dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
2886
2887 if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002888 /*
2889 * First try to allocate an io virtual address in
Yang Hongyang284901a2009-04-06 19:01:15 -07002890 * DMA_BIT_MASK(32) and if that fails then try allocating
Joe Perches36098012007-12-17 11:40:11 -08002891 * from higher range
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002892 */
David Woodhouse875764d2009-06-28 21:20:51 +01002893 iova = alloc_iova(&domain->iovad, nrpages,
2894 IOVA_PFN(DMA_BIT_MASK(32)), 1);
2895 if (iova)
2896 return iova;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002897 }
David Woodhouse875764d2009-06-28 21:20:51 +01002898 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
2899 if (unlikely(!iova)) {
2900 printk(KERN_ERR "Allocating %ld-page iova for %s failed",
David Woodhouse207e3592014-03-09 16:12:32 -07002901 nrpages, dev_name(dev));
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002902 return NULL;
2903 }
2904
2905 return iova;
2906}
2907
David Woodhoused4b709f2014-03-09 16:07:40 -07002908static struct dmar_domain *__get_valid_domain_for_dev(struct device *dev)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002909{
2910 struct dmar_domain *domain;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002911 int ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002912
David Woodhoused4b709f2014-03-09 16:07:40 -07002913 domain = get_domain_for_dev(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002914 if (!domain) {
David Woodhoused4b709f2014-03-09 16:07:40 -07002915 printk(KERN_ERR "Allocating domain for %s failed",
2916 dev_name(dev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002917 return NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002918 }
2919
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002920 /* make sure context mapping is ok */
David Woodhoused4b709f2014-03-09 16:07:40 -07002921 if (unlikely(!domain_context_mapped(dev))) {
2922 ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002923 if (ret) {
David Woodhoused4b709f2014-03-09 16:07:40 -07002924 printk(KERN_ERR "Domain context map for %s failed",
2925 dev_name(dev));
Al Viro4fe05bb2007-10-29 04:51:16 +00002926 return NULL;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002927 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07002928 }
2929
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002930 return domain;
2931}
2932
David Woodhoused4b709f2014-03-09 16:07:40 -07002933static inline struct dmar_domain *get_valid_domain_for_dev(struct device *dev)
David Woodhouse147202a2009-07-07 19:43:20 +01002934{
2935 struct device_domain_info *info;
2936
2937 /* No lock here, assumes no domain exit in normal case */
David Woodhoused4b709f2014-03-09 16:07:40 -07002938 info = dev->archdata.iommu;
David Woodhouse147202a2009-07-07 19:43:20 +01002939 if (likely(info))
2940 return info->domain;
2941
2942 return __get_valid_domain_for_dev(dev);
2943}
2944
David Woodhouse3d891942014-03-06 15:59:26 +00002945static int iommu_dummy(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002946{
David Woodhouse3d891942014-03-06 15:59:26 +00002947 return dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002948}
2949
David Woodhouseecb509e2014-03-09 16:29:55 -07002950/* Check if the dev needs to go through non-identity map and unmap process.*/
David Woodhouse73676832009-07-04 14:08:36 +01002951static int iommu_no_mapping(struct device *dev)
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002952{
2953 int found;
2954
David Woodhouse3d891942014-03-06 15:59:26 +00002955 if (iommu_dummy(dev))
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002956 return 1;
2957
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002958 if (!iommu_identity_mapping)
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002959 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002960
David Woodhouse9b226622014-03-09 14:03:28 -07002961 found = identity_mapping(dev);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002962 if (found) {
David Woodhouseecb509e2014-03-09 16:29:55 -07002963 if (iommu_should_identity_map(dev, 0))
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002964 return 1;
2965 else {
2966 /*
2967 * 32 bit DMA is removed from si_domain and fall back
2968 * to non-identity mapping.
2969 */
David Woodhousebf9c9ed2014-03-09 16:19:13 -07002970 domain_remove_one_dev_info(si_domain, dev);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002971 printk(KERN_INFO "32bit %s uses non-identity mapping\n",
David Woodhouseecb509e2014-03-09 16:29:55 -07002972 dev_name(dev));
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002973 return 0;
2974 }
2975 } else {
2976 /*
2977 * In case of a detached 64 bit DMA device from vm, the device
2978 * is put into si_domain for identity mapping.
2979 */
David Woodhouseecb509e2014-03-09 16:29:55 -07002980 if (iommu_should_identity_map(dev, 0)) {
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002981 int ret;
David Woodhouse5913c9b2014-03-09 16:27:31 -07002982 ret = domain_add_dev_info(si_domain, dev,
David Woodhouse5fe60f42009-08-09 10:53:41 +01002983 hw_pass_through ?
2984 CONTEXT_TT_PASS_THROUGH :
2985 CONTEXT_TT_MULTI_LEVEL);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002986 if (!ret) {
2987 printk(KERN_INFO "64bit %s uses identity mapping\n",
David Woodhouseecb509e2014-03-09 16:29:55 -07002988 dev_name(dev));
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002989 return 1;
2990 }
2991 }
2992 }
2993
David Woodhouse1e4c64c2009-07-04 10:40:38 +01002994 return 0;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07002995}
2996
David Woodhouse5040a912014-03-09 16:14:00 -07002997static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09002998 size_t size, int dir, u64 dma_mask)
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07002999{
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003000 struct dmar_domain *domain;
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003001 phys_addr_t start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003002 struct iova *iova;
3003 int prot = 0;
Ingo Molnar6865f0d2008-04-22 11:09:04 +02003004 int ret;
Weidong Han8c11e792008-12-08 15:29:22 +08003005 struct intel_iommu *iommu;
Fenghua Yu33041ec2009-08-04 15:10:59 -07003006 unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003007
3008 BUG_ON(dir == DMA_NONE);
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003009
David Woodhouse5040a912014-03-09 16:14:00 -07003010 if (iommu_no_mapping(dev))
Ingo Molnar6865f0d2008-04-22 11:09:04 +02003011 return paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003012
David Woodhouse5040a912014-03-09 16:14:00 -07003013 domain = get_valid_domain_for_dev(dev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003014 if (!domain)
3015 return 0;
3016
Weidong Han8c11e792008-12-08 15:29:22 +08003017 iommu = domain_get_iommu(domain);
David Woodhouse88cb6a72009-06-28 15:03:06 +01003018 size = aligned_nrpages(paddr, size);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003019
David Woodhouse5040a912014-03-09 16:14:00 -07003020 iova = intel_alloc_iova(dev, domain, dma_to_mm_pfn(size), dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003021 if (!iova)
3022 goto error;
3023
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003024 /*
3025 * Check if DMAR supports zero-length reads on write only
3026 * mappings..
3027 */
3028 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003029 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003030 prot |= DMA_PTE_READ;
3031 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3032 prot |= DMA_PTE_WRITE;
3033 /*
Ingo Molnar6865f0d2008-04-22 11:09:04 +02003034 * paddr - (paddr + size) might be partial page, we should map the whole
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003035 * page. Note: if two part of one page are separately mapped, we
Ingo Molnar6865f0d2008-04-22 11:09:04 +02003036 * might have two guest_addr mapping to the same host paddr, but this
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003037 * is not a big problem
3038 */
David Woodhouse0ab36de2009-06-28 14:01:43 +01003039 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
Fenghua Yu33041ec2009-08-04 15:10:59 -07003040 mm_to_dma_pfn(paddr_pfn), size, prot);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003041 if (ret)
3042 goto error;
3043
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003044 /* it's a non-present to present mapping. Only flush if caching mode */
3045 if (cap_caching_mode(iommu->cap))
David Woodhouseea8ea462014-03-05 17:09:32 +00003046 iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 0, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003047 else
Weidong Han8c11e792008-12-08 15:29:22 +08003048 iommu_flush_write_buffer(iommu);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003049
David Woodhouse03d6a242009-06-28 15:33:46 +01003050 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
3051 start_paddr += paddr & ~PAGE_MASK;
3052 return start_paddr;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003053
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003054error:
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003055 if (iova)
3056 __free_iova(&domain->iovad, iova);
David Woodhouse4cf2e752009-02-11 17:23:43 +00003057 printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n",
David Woodhouse5040a912014-03-09 16:14:00 -07003058 dev_name(dev), size, (unsigned long long)paddr, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003059 return 0;
3060}
3061
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003062static dma_addr_t intel_map_page(struct device *dev, struct page *page,
3063 unsigned long offset, size_t size,
3064 enum dma_data_direction dir,
3065 struct dma_attrs *attrs)
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003066{
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003067 return __intel_map_single(dev, page_to_phys(page) + offset, size,
David Woodhouse46333e32014-03-10 20:01:21 -07003068 dir, *dev->dma_mask);
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003069}
3070
mark gross5e0d2a62008-03-04 15:22:08 -08003071static void flush_unmaps(void)
3072{
mark gross80b20dd2008-04-18 13:53:58 -07003073 int i, j;
mark gross5e0d2a62008-03-04 15:22:08 -08003074
mark gross5e0d2a62008-03-04 15:22:08 -08003075 timer_on = 0;
3076
3077 /* just flush them all */
3078 for (i = 0; i < g_num_of_iommus; i++) {
Weidong Hana2bb8452008-12-08 11:24:12 +08003079 struct intel_iommu *iommu = g_iommus[i];
3080 if (!iommu)
3081 continue;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07003082
Yu Zhao9dd2fe82009-05-18 13:51:36 +08003083 if (!deferred_flush[i].next)
3084 continue;
3085
Nadav Amit78d5f0f2010-04-08 23:00:41 +03003086 /* In caching mode, global flushes turn emulation expensive */
3087 if (!cap_caching_mode(iommu->cap))
3088 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
Yu Zhao93a23a72009-05-18 13:51:37 +08003089 DMA_TLB_GLOBAL_FLUSH);
Yu Zhao9dd2fe82009-05-18 13:51:36 +08003090 for (j = 0; j < deferred_flush[i].next; j++) {
Yu Zhao93a23a72009-05-18 13:51:37 +08003091 unsigned long mask;
3092 struct iova *iova = deferred_flush[i].iova[j];
Nadav Amit78d5f0f2010-04-08 23:00:41 +03003093 struct dmar_domain *domain = deferred_flush[i].domain[j];
Yu Zhao93a23a72009-05-18 13:51:37 +08003094
Nadav Amit78d5f0f2010-04-08 23:00:41 +03003095 /* On real hardware multiple invalidations are expensive */
3096 if (cap_caching_mode(iommu->cap))
3097 iommu_flush_iotlb_psi(iommu, domain->id,
David Woodhouseea8ea462014-03-05 17:09:32 +00003098 iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1,
3099 !deferred_flush[i].freelist[j], 0);
Nadav Amit78d5f0f2010-04-08 23:00:41 +03003100 else {
3101 mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
3102 iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
3103 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
3104 }
Yu Zhao93a23a72009-05-18 13:51:37 +08003105 __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
David Woodhouseea8ea462014-03-05 17:09:32 +00003106 if (deferred_flush[i].freelist[j])
3107 dma_free_pagelist(deferred_flush[i].freelist[j]);
mark gross80b20dd2008-04-18 13:53:58 -07003108 }
Yu Zhao9dd2fe82009-05-18 13:51:36 +08003109 deferred_flush[i].next = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08003110 }
3111
mark gross5e0d2a62008-03-04 15:22:08 -08003112 list_size = 0;
mark gross5e0d2a62008-03-04 15:22:08 -08003113}
3114
3115static void flush_unmaps_timeout(unsigned long data)
3116{
mark gross80b20dd2008-04-18 13:53:58 -07003117 unsigned long flags;
3118
3119 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08003120 flush_unmaps();
mark gross80b20dd2008-04-18 13:53:58 -07003121 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
mark gross5e0d2a62008-03-04 15:22:08 -08003122}
3123
David Woodhouseea8ea462014-03-05 17:09:32 +00003124static void add_unmap(struct dmar_domain *dom, struct iova *iova, struct page *freelist)
mark gross5e0d2a62008-03-04 15:22:08 -08003125{
3126 unsigned long flags;
mark gross80b20dd2008-04-18 13:53:58 -07003127 int next, iommu_id;
Weidong Han8c11e792008-12-08 15:29:22 +08003128 struct intel_iommu *iommu;
mark gross5e0d2a62008-03-04 15:22:08 -08003129
3130 spin_lock_irqsave(&async_umap_flush_lock, flags);
mark gross80b20dd2008-04-18 13:53:58 -07003131 if (list_size == HIGH_WATER_MARK)
3132 flush_unmaps();
3133
Weidong Han8c11e792008-12-08 15:29:22 +08003134 iommu = domain_get_iommu(dom);
3135 iommu_id = iommu->seq_id;
Suresh Siddhac42d9f32008-07-10 11:16:36 -07003136
mark gross80b20dd2008-04-18 13:53:58 -07003137 next = deferred_flush[iommu_id].next;
3138 deferred_flush[iommu_id].domain[next] = dom;
3139 deferred_flush[iommu_id].iova[next] = iova;
David Woodhouseea8ea462014-03-05 17:09:32 +00003140 deferred_flush[iommu_id].freelist[next] = freelist;
mark gross80b20dd2008-04-18 13:53:58 -07003141 deferred_flush[iommu_id].next++;
mark gross5e0d2a62008-03-04 15:22:08 -08003142
3143 if (!timer_on) {
3144 mod_timer(&unmap_timer, jiffies + msecs_to_jiffies(10));
3145 timer_on = 1;
3146 }
3147 list_size++;
3148 spin_unlock_irqrestore(&async_umap_flush_lock, flags);
3149}
3150
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003151static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
3152 size_t size, enum dma_data_direction dir,
3153 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003154{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003155 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003156 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003157 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003158 struct intel_iommu *iommu;
David Woodhouseea8ea462014-03-05 17:09:32 +00003159 struct page *freelist;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003160
David Woodhouse73676832009-07-04 14:08:36 +01003161 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003162 return;
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07003163
David Woodhouse1525a292014-03-06 16:19:30 +00003164 domain = find_domain(dev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003165 BUG_ON(!domain);
3166
Weidong Han8c11e792008-12-08 15:29:22 +08003167 iommu = domain_get_iommu(domain);
3168
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003169 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
David Woodhouse85b98272009-07-01 19:27:53 +01003170 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
3171 (unsigned long long)dev_addr))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003172 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003173
David Woodhoused794dc92009-06-28 00:27:49 +01003174 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3175 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003176
David Woodhoused794dc92009-06-28 00:27:49 +01003177 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
David Woodhouse207e3592014-03-09 16:12:32 -07003178 dev_name(dev), start_pfn, last_pfn);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003179
David Woodhouseea8ea462014-03-05 17:09:32 +00003180 freelist = domain_unmap(domain, start_pfn, last_pfn);
David Woodhoused794dc92009-06-28 00:27:49 +01003181
mark gross5e0d2a62008-03-04 15:22:08 -08003182 if (intel_iommu_strict) {
David Woodhouse03d6a242009-06-28 15:33:46 +01003183 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
David Woodhouseea8ea462014-03-05 17:09:32 +00003184 last_pfn - start_pfn + 1, !freelist, 0);
mark gross5e0d2a62008-03-04 15:22:08 -08003185 /* free iova */
3186 __free_iova(&domain->iovad, iova);
David Woodhouseea8ea462014-03-05 17:09:32 +00003187 dma_free_pagelist(freelist);
mark gross5e0d2a62008-03-04 15:22:08 -08003188 } else {
David Woodhouseea8ea462014-03-05 17:09:32 +00003189 add_unmap(domain, iova, freelist);
mark gross5e0d2a62008-03-04 15:22:08 -08003190 /*
3191 * queue up the release of the unmap to save the 1/6th of the
3192 * cpu used up by the iotlb flush operation...
3193 */
mark gross5e0d2a62008-03-04 15:22:08 -08003194 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003195}
3196
David Woodhouse5040a912014-03-09 16:14:00 -07003197static void *intel_alloc_coherent(struct device *dev, size_t size,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003198 dma_addr_t *dma_handle, gfp_t flags,
3199 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003200{
Akinobu Mita36746432014-06-04 16:06:51 -07003201 struct page *page = NULL;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003202 int order;
3203
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003204 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003205 order = get_order(size);
Alex Williamsone8bb9102009-11-04 15:59:34 -07003206
David Woodhouse5040a912014-03-09 16:14:00 -07003207 if (!iommu_no_mapping(dev))
Alex Williamsone8bb9102009-11-04 15:59:34 -07003208 flags &= ~(GFP_DMA | GFP_DMA32);
David Woodhouse5040a912014-03-09 16:14:00 -07003209 else if (dev->coherent_dma_mask < dma_get_required_mask(dev)) {
3210 if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
Alex Williamsone8bb9102009-11-04 15:59:34 -07003211 flags |= GFP_DMA;
3212 else
3213 flags |= GFP_DMA32;
3214 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003215
Akinobu Mita36746432014-06-04 16:06:51 -07003216 if (flags & __GFP_WAIT) {
3217 unsigned int count = size >> PAGE_SHIFT;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003218
Akinobu Mita36746432014-06-04 16:06:51 -07003219 page = dma_alloc_from_contiguous(dev, count, order);
3220 if (page && iommu_no_mapping(dev) &&
3221 page_to_phys(page) + size > dev->coherent_dma_mask) {
3222 dma_release_from_contiguous(dev, page, count);
3223 page = NULL;
3224 }
3225 }
3226
3227 if (!page)
3228 page = alloc_pages(flags, order);
3229 if (!page)
3230 return NULL;
3231 memset(page_address(page), 0, size);
3232
3233 *dma_handle = __intel_map_single(dev, page_to_phys(page), size,
FUJITA Tomonoribb9e6d62008-10-15 16:08:28 +09003234 DMA_BIDIRECTIONAL,
David Woodhouse5040a912014-03-09 16:14:00 -07003235 dev->coherent_dma_mask);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003236 if (*dma_handle)
Akinobu Mita36746432014-06-04 16:06:51 -07003237 return page_address(page);
3238 if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
3239 __free_pages(page, order);
3240
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003241 return NULL;
3242}
3243
David Woodhouse5040a912014-03-09 16:14:00 -07003244static void intel_free_coherent(struct device *dev, size_t size, void *vaddr,
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003245 dma_addr_t dma_handle, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003246{
3247 int order;
Akinobu Mita36746432014-06-04 16:06:51 -07003248 struct page *page = virt_to_page(vaddr);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003249
Fenghua Yu5b6985c2008-10-16 18:02:32 -07003250 size = PAGE_ALIGN(size);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003251 order = get_order(size);
3252
David Woodhouse5040a912014-03-09 16:14:00 -07003253 intel_unmap_page(dev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
Akinobu Mita36746432014-06-04 16:06:51 -07003254 if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
3255 __free_pages(page, order);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003256}
3257
David Woodhouse5040a912014-03-09 16:14:00 -07003258static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist,
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003259 int nelems, enum dma_data_direction dir,
3260 struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003261{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003262 struct dmar_domain *domain;
David Woodhoused794dc92009-06-28 00:27:49 +01003263 unsigned long start_pfn, last_pfn;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003264 struct iova *iova;
Weidong Han8c11e792008-12-08 15:29:22 +08003265 struct intel_iommu *iommu;
David Woodhouseea8ea462014-03-05 17:09:32 +00003266 struct page *freelist;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003267
David Woodhouse5040a912014-03-09 16:14:00 -07003268 if (iommu_no_mapping(dev))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003269 return;
3270
David Woodhouse5040a912014-03-09 16:14:00 -07003271 domain = find_domain(dev);
Weidong Han8c11e792008-12-08 15:29:22 +08003272 BUG_ON(!domain);
3273
3274 iommu = domain_get_iommu(domain);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003275
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003276 iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
David Woodhouse85b98272009-07-01 19:27:53 +01003277 if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
3278 (unsigned long long)sglist[0].dma_address))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003279 return;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003280
David Woodhoused794dc92009-06-28 00:27:49 +01003281 start_pfn = mm_to_dma_pfn(iova->pfn_lo);
3282 last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003283
David Woodhouseea8ea462014-03-05 17:09:32 +00003284 freelist = domain_unmap(domain, start_pfn, last_pfn);
David Woodhoused794dc92009-06-28 00:27:49 +01003285
David Woodhouseacea0012009-07-14 01:55:11 +01003286 if (intel_iommu_strict) {
3287 iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
David Woodhouseea8ea462014-03-05 17:09:32 +00003288 last_pfn - start_pfn + 1, !freelist, 0);
David Woodhouseacea0012009-07-14 01:55:11 +01003289 /* free iova */
3290 __free_iova(&domain->iovad, iova);
David Woodhouseea8ea462014-03-05 17:09:32 +00003291 dma_free_pagelist(freelist);
David Woodhouseacea0012009-07-14 01:55:11 +01003292 } else {
David Woodhouseea8ea462014-03-05 17:09:32 +00003293 add_unmap(domain, iova, freelist);
David Woodhouseacea0012009-07-14 01:55:11 +01003294 /*
3295 * queue up the release of the unmap to save the 1/6th of the
3296 * cpu used up by the iotlb flush operation...
3297 */
3298 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003299}
3300
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003301static int intel_nontranslate_map_sg(struct device *hddev,
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003302 struct scatterlist *sglist, int nelems, int dir)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003303{
3304 int i;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003305 struct scatterlist *sg;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003306
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003307 for_each_sg(sglist, sg, nelems, i) {
FUJITA Tomonori12d4d402007-10-23 09:32:25 +02003308 BUG_ON(!sg_page(sg));
David Woodhouse4cf2e752009-02-11 17:23:43 +00003309 sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003310 sg->dma_length = sg->length;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003311 }
3312 return nelems;
3313}
3314
David Woodhouse5040a912014-03-09 16:14:00 -07003315static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nelems,
FUJITA Tomonorid7ab5c42009-01-28 21:53:18 +09003316 enum dma_data_direction dir, struct dma_attrs *attrs)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003317{
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003318 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003319 struct dmar_domain *domain;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003320 size_t size = 0;
3321 int prot = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003322 struct iova *iova = NULL;
3323 int ret;
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003324 struct scatterlist *sg;
David Woodhouseb536d242009-06-28 14:49:31 +01003325 unsigned long start_vpfn;
Weidong Han8c11e792008-12-08 15:29:22 +08003326 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003327
3328 BUG_ON(dir == DMA_NONE);
David Woodhouse5040a912014-03-09 16:14:00 -07003329 if (iommu_no_mapping(dev))
3330 return intel_nontranslate_map_sg(dev, sglist, nelems, dir);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003331
David Woodhouse5040a912014-03-09 16:14:00 -07003332 domain = get_valid_domain_for_dev(dev);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003333 if (!domain)
3334 return 0;
3335
Weidong Han8c11e792008-12-08 15:29:22 +08003336 iommu = domain_get_iommu(domain);
3337
David Woodhouseb536d242009-06-28 14:49:31 +01003338 for_each_sg(sglist, sg, nelems, i)
David Woodhouse88cb6a72009-06-28 15:03:06 +01003339 size += aligned_nrpages(sg->offset, sg->length);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003340
David Woodhouse5040a912014-03-09 16:14:00 -07003341 iova = intel_alloc_iova(dev, domain, dma_to_mm_pfn(size),
3342 *dev->dma_mask);
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003343 if (!iova) {
FUJITA Tomonoric03ab372007-10-21 16:42:00 -07003344 sglist->dma_length = 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003345 return 0;
3346 }
3347
3348 /*
3349 * Check if DMAR supports zero-length reads on write only
3350 * mappings..
3351 */
3352 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
Weidong Han8c11e792008-12-08 15:29:22 +08003353 !cap_zlr(iommu->cap))
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003354 prot |= DMA_PTE_READ;
3355 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3356 prot |= DMA_PTE_WRITE;
3357
David Woodhouseb536d242009-06-28 14:49:31 +01003358 start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
David Woodhousee1605492009-06-29 11:17:38 +01003359
Fenghua Yuf5329592009-08-04 15:09:37 -07003360 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
David Woodhousee1605492009-06-29 11:17:38 +01003361 if (unlikely(ret)) {
3362 /* clear the page */
3363 dma_pte_clear_range(domain, start_vpfn,
3364 start_vpfn + size - 1);
3365 /* free page tables */
3366 dma_pte_free_pagetable(domain, start_vpfn,
3367 start_vpfn + size - 1);
3368 /* free iova */
3369 __free_iova(&domain->iovad, iova);
3370 return 0;
Keshavamurthy, Anil Sf76aec72007-10-21 16:41:58 -07003371 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003372
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003373 /* it's a non-present to present mapping. Only flush if caching mode */
3374 if (cap_caching_mode(iommu->cap))
David Woodhouseea8ea462014-03-05 17:09:32 +00003375 iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 0, 1);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003376 else
Weidong Han8c11e792008-12-08 15:29:22 +08003377 iommu_flush_write_buffer(iommu);
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003378
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003379 return nelems;
3380}
3381
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003382static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
3383{
3384 return !dma_addr;
3385}
3386
FUJITA Tomonori160c1d82009-01-05 23:59:02 +09003387struct dma_map_ops intel_dma_ops = {
Andrzej Pietrasiewiczbaa676f2012-03-27 14:28:18 +02003388 .alloc = intel_alloc_coherent,
3389 .free = intel_free_coherent,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003390 .map_sg = intel_map_sg,
3391 .unmap_sg = intel_unmap_sg,
FUJITA Tomonoriffbbef52009-01-05 23:47:26 +09003392 .map_page = intel_map_page,
3393 .unmap_page = intel_unmap_page,
FUJITA Tomonoridfb805e2009-01-28 21:53:17 +09003394 .mapping_error = intel_mapping_error,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003395};
3396
3397static inline int iommu_domain_cache_init(void)
3398{
3399 int ret = 0;
3400
3401 iommu_domain_cache = kmem_cache_create("iommu_domain",
3402 sizeof(struct dmar_domain),
3403 0,
3404 SLAB_HWCACHE_ALIGN,
3405
3406 NULL);
3407 if (!iommu_domain_cache) {
3408 printk(KERN_ERR "Couldn't create iommu_domain cache\n");
3409 ret = -ENOMEM;
3410 }
3411
3412 return ret;
3413}
3414
3415static inline int iommu_devinfo_cache_init(void)
3416{
3417 int ret = 0;
3418
3419 iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
3420 sizeof(struct device_domain_info),
3421 0,
3422 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003423 NULL);
3424 if (!iommu_devinfo_cache) {
3425 printk(KERN_ERR "Couldn't create devinfo cache\n");
3426 ret = -ENOMEM;
3427 }
3428
3429 return ret;
3430}
3431
3432static inline int iommu_iova_cache_init(void)
3433{
3434 int ret = 0;
3435
3436 iommu_iova_cache = kmem_cache_create("iommu_iova",
3437 sizeof(struct iova),
3438 0,
3439 SLAB_HWCACHE_ALIGN,
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003440 NULL);
3441 if (!iommu_iova_cache) {
3442 printk(KERN_ERR "Couldn't create iova cache\n");
3443 ret = -ENOMEM;
3444 }
3445
3446 return ret;
3447}
3448
3449static int __init iommu_init_mempool(void)
3450{
3451 int ret;
3452 ret = iommu_iova_cache_init();
3453 if (ret)
3454 return ret;
3455
3456 ret = iommu_domain_cache_init();
3457 if (ret)
3458 goto domain_error;
3459
3460 ret = iommu_devinfo_cache_init();
3461 if (!ret)
3462 return ret;
3463
3464 kmem_cache_destroy(iommu_domain_cache);
3465domain_error:
3466 kmem_cache_destroy(iommu_iova_cache);
3467
3468 return -ENOMEM;
3469}
3470
3471static void __init iommu_exit_mempool(void)
3472{
3473 kmem_cache_destroy(iommu_devinfo_cache);
3474 kmem_cache_destroy(iommu_domain_cache);
3475 kmem_cache_destroy(iommu_iova_cache);
3476
3477}
3478
Dan Williams556ab452010-07-23 15:47:56 -07003479static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3480{
3481 struct dmar_drhd_unit *drhd;
3482 u32 vtbar;
3483 int rc;
3484
3485 /* We know that this device on this chipset has its own IOMMU.
3486 * If we find it under a different IOMMU, then the BIOS is lying
3487 * to us. Hope that the IOMMU for this device is actually
3488 * disabled, and it needs no translation...
3489 */
3490 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
3491 if (rc) {
3492 /* "can't" happen */
3493 dev_info(&pdev->dev, "failed to run vt-d quirk\n");
3494 return;
3495 }
3496 vtbar &= 0xffff0000;
3497
3498 /* we know that the this iommu should be at offset 0xa000 from vtbar */
3499 drhd = dmar_find_matched_drhd_unit(pdev);
3500 if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
3501 TAINT_FIRMWARE_WORKAROUND,
3502 "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
3503 pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
3504}
3505DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
3506
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003507static void __init init_no_remapping_devices(void)
3508{
3509 struct dmar_drhd_unit *drhd;
David Woodhouse832bd852014-03-07 15:08:36 +00003510 struct device *dev;
Jiang Liub683b232014-02-19 14:07:32 +08003511 int i;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003512
3513 for_each_drhd_unit(drhd) {
3514 if (!drhd->include_all) {
Jiang Liub683b232014-02-19 14:07:32 +08003515 for_each_active_dev_scope(drhd->devices,
3516 drhd->devices_cnt, i, dev)
3517 break;
David Woodhouse832bd852014-03-07 15:08:36 +00003518 /* ignore DMAR unit if no devices exist */
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003519 if (i == drhd->devices_cnt)
3520 drhd->ignored = 1;
3521 }
3522 }
3523
Jiang Liu7c919772014-01-06 14:18:18 +08003524 for_each_active_drhd_unit(drhd) {
Jiang Liu7c919772014-01-06 14:18:18 +08003525 if (drhd->include_all)
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003526 continue;
3527
Jiang Liub683b232014-02-19 14:07:32 +08003528 for_each_active_dev_scope(drhd->devices,
3529 drhd->devices_cnt, i, dev)
David Woodhouse832bd852014-03-07 15:08:36 +00003530 if (!dev_is_pci(dev) || !IS_GFX_DEVICE(to_pci_dev(dev)))
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003531 break;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003532 if (i < drhd->devices_cnt)
3533 continue;
3534
David Woodhousec0771df2011-10-14 20:59:46 +01003535 /* This IOMMU has *only* gfx devices. Either bypass it or
3536 set the gfx_mapped flag, as appropriate */
3537 if (dmar_map_gfx) {
3538 intel_iommu_gfx_mapped = 1;
3539 } else {
3540 drhd->ignored = 1;
Jiang Liub683b232014-02-19 14:07:32 +08003541 for_each_active_dev_scope(drhd->devices,
3542 drhd->devices_cnt, i, dev)
David Woodhouse832bd852014-03-07 15:08:36 +00003543 dev->archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07003544 }
3545 }
3546}
3547
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003548#ifdef CONFIG_SUSPEND
3549static int init_iommu_hw(void)
3550{
3551 struct dmar_drhd_unit *drhd;
3552 struct intel_iommu *iommu = NULL;
3553
3554 for_each_active_iommu(iommu, drhd)
3555 if (iommu->qi)
3556 dmar_reenable_qi(iommu);
3557
Joseph Cihulab7792602011-05-03 00:08:37 -07003558 for_each_iommu(iommu, drhd) {
3559 if (drhd->ignored) {
3560 /*
3561 * we always have to disable PMRs or DMA may fail on
3562 * this device
3563 */
3564 if (force_on)
3565 iommu_disable_protect_mem_regions(iommu);
3566 continue;
3567 }
3568
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003569 iommu_flush_write_buffer(iommu);
3570
3571 iommu_set_root_entry(iommu);
3572
3573 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003574 DMA_CCMD_GLOBAL_INVL);
Jiang Liu2a41cce2014-07-11 14:19:33 +08003575 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
3576 iommu_enable_translation(iommu);
David Woodhouseb94996c2009-09-19 15:28:12 -07003577 iommu_disable_protect_mem_regions(iommu);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003578 }
3579
3580 return 0;
3581}
3582
3583static void iommu_flush_all(void)
3584{
3585 struct dmar_drhd_unit *drhd;
3586 struct intel_iommu *iommu;
3587
3588 for_each_active_iommu(iommu, drhd) {
3589 iommu->flush.flush_context(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003590 DMA_CCMD_GLOBAL_INVL);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003591 iommu->flush.flush_iotlb(iommu, 0, 0, 0,
David Woodhouse1f0ef2a2009-05-10 19:58:49 +01003592 DMA_TLB_GLOBAL_FLUSH);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003593 }
3594}
3595
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003596static int iommu_suspend(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003597{
3598 struct dmar_drhd_unit *drhd;
3599 struct intel_iommu *iommu = NULL;
3600 unsigned long flag;
3601
3602 for_each_active_iommu(iommu, drhd) {
3603 iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
3604 GFP_ATOMIC);
3605 if (!iommu->iommu_state)
3606 goto nomem;
3607 }
3608
3609 iommu_flush_all();
3610
3611 for_each_active_iommu(iommu, drhd) {
3612 iommu_disable_translation(iommu);
3613
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003614 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003615
3616 iommu->iommu_state[SR_DMAR_FECTL_REG] =
3617 readl(iommu->reg + DMAR_FECTL_REG);
3618 iommu->iommu_state[SR_DMAR_FEDATA_REG] =
3619 readl(iommu->reg + DMAR_FEDATA_REG);
3620 iommu->iommu_state[SR_DMAR_FEADDR_REG] =
3621 readl(iommu->reg + DMAR_FEADDR_REG);
3622 iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
3623 readl(iommu->reg + DMAR_FEUADDR_REG);
3624
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003625 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003626 }
3627 return 0;
3628
3629nomem:
3630 for_each_active_iommu(iommu, drhd)
3631 kfree(iommu->iommu_state);
3632
3633 return -ENOMEM;
3634}
3635
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003636static void iommu_resume(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003637{
3638 struct dmar_drhd_unit *drhd;
3639 struct intel_iommu *iommu = NULL;
3640 unsigned long flag;
3641
3642 if (init_iommu_hw()) {
Joseph Cihulab7792602011-05-03 00:08:37 -07003643 if (force_on)
3644 panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
3645 else
3646 WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003647 return;
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003648 }
3649
3650 for_each_active_iommu(iommu, drhd) {
3651
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003652 raw_spin_lock_irqsave(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003653
3654 writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
3655 iommu->reg + DMAR_FECTL_REG);
3656 writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
3657 iommu->reg + DMAR_FEDATA_REG);
3658 writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
3659 iommu->reg + DMAR_FEADDR_REG);
3660 writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
3661 iommu->reg + DMAR_FEUADDR_REG);
3662
Thomas Gleixner1f5b3c32011-07-19 16:19:51 +02003663 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003664 }
3665
3666 for_each_active_iommu(iommu, drhd)
3667 kfree(iommu->iommu_state);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003668}
3669
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003670static struct syscore_ops iommu_syscore_ops = {
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003671 .resume = iommu_resume,
3672 .suspend = iommu_suspend,
3673};
3674
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003675static void __init init_iommu_pm_ops(void)
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003676{
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01003677 register_syscore_ops(&iommu_syscore_ops);
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003678}
3679
3680#else
Rafael J. Wysocki99592ba2011-06-07 21:32:31 +02003681static inline void init_iommu_pm_ops(void) {}
Fenghua Yuf59c7b62009-03-27 14:22:42 -07003682#endif /* CONFIG_PM */
3683
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003684
3685int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3686{
3687 struct acpi_dmar_reserved_memory *rmrr;
3688 struct dmar_rmrr_unit *rmrru;
3689
3690 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
3691 if (!rmrru)
3692 return -ENOMEM;
3693
3694 rmrru->hdr = header;
3695 rmrr = (struct acpi_dmar_reserved_memory *)header;
3696 rmrru->base_address = rmrr->base_address;
3697 rmrru->end_address = rmrr->end_address;
Jiang Liu2e455282014-02-19 14:07:36 +08003698 rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
3699 ((void *)rmrr) + rmrr->header.length,
3700 &rmrru->devices_cnt);
3701 if (rmrru->devices_cnt && rmrru->devices == NULL) {
3702 kfree(rmrru);
3703 return -ENOMEM;
3704 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003705
Jiang Liu2e455282014-02-19 14:07:36 +08003706 list_add(&rmrru->list, &dmar_rmrr_units);
3707
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003708 return 0;
3709}
3710
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003711int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3712{
3713 struct acpi_dmar_atsr *atsr;
3714 struct dmar_atsr_unit *atsru;
3715
3716 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
3717 atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
3718 if (!atsru)
3719 return -ENOMEM;
3720
3721 atsru->hdr = hdr;
3722 atsru->include_all = atsr->flags & 0x1;
Jiang Liu2e455282014-02-19 14:07:36 +08003723 if (!atsru->include_all) {
3724 atsru->devices = dmar_alloc_dev_scope((void *)(atsr + 1),
3725 (void *)atsr + atsr->header.length,
3726 &atsru->devices_cnt);
3727 if (atsru->devices_cnt && atsru->devices == NULL) {
3728 kfree(atsru);
3729 return -ENOMEM;
3730 }
3731 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003732
Jiang Liu0e2426122014-02-19 14:07:34 +08003733 list_add_rcu(&atsru->list, &dmar_atsr_units);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003734
3735 return 0;
3736}
3737
Jiang Liu9bdc5312014-01-06 14:18:27 +08003738static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
3739{
3740 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
3741 kfree(atsru);
3742}
3743
3744static void intel_iommu_free_dmars(void)
3745{
3746 struct dmar_rmrr_unit *rmrru, *rmrr_n;
3747 struct dmar_atsr_unit *atsru, *atsr_n;
3748
3749 list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
3750 list_del(&rmrru->list);
3751 dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
3752 kfree(rmrru);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003753 }
3754
Jiang Liu9bdc5312014-01-06 14:18:27 +08003755 list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
3756 list_del(&atsru->list);
3757 intel_iommu_free_atsr(atsru);
3758 }
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003759}
3760
3761int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3762{
Jiang Liub683b232014-02-19 14:07:32 +08003763 int i, ret = 1;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003764 struct pci_bus *bus;
David Woodhouse832bd852014-03-07 15:08:36 +00003765 struct pci_dev *bridge = NULL;
3766 struct device *tmp;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003767 struct acpi_dmar_atsr *atsr;
3768 struct dmar_atsr_unit *atsru;
3769
3770 dev = pci_physfn(dev);
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003771 for (bus = dev->bus; bus; bus = bus->parent) {
Jiang Liub5f82dd2014-02-19 14:07:31 +08003772 bridge = bus->self;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003773 if (!bridge || !pci_is_pcie(bridge) ||
Yijing Wang62f87c02012-07-24 17:20:03 +08003774 pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003775 return 0;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003776 if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT)
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003777 break;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003778 }
Jiang Liub5f82dd2014-02-19 14:07:31 +08003779 if (!bridge)
3780 return 0;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003781
Jiang Liu0e2426122014-02-19 14:07:34 +08003782 rcu_read_lock();
Jiang Liub5f82dd2014-02-19 14:07:31 +08003783 list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
3784 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3785 if (atsr->segment != pci_domain_nr(dev->bus))
3786 continue;
3787
Jiang Liub683b232014-02-19 14:07:32 +08003788 for_each_dev_scope(atsru->devices, atsru->devices_cnt, i, tmp)
David Woodhouse832bd852014-03-07 15:08:36 +00003789 if (tmp == &bridge->dev)
Jiang Liub683b232014-02-19 14:07:32 +08003790 goto out;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003791
3792 if (atsru->include_all)
Jiang Liub683b232014-02-19 14:07:32 +08003793 goto out;
Jiang Liub5f82dd2014-02-19 14:07:31 +08003794 }
Jiang Liub683b232014-02-19 14:07:32 +08003795 ret = 0;
3796out:
Jiang Liu0e2426122014-02-19 14:07:34 +08003797 rcu_read_unlock();
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003798
Jiang Liub683b232014-02-19 14:07:32 +08003799 return ret;
Suresh Siddha318fe7d2011-08-23 17:05:20 -07003800}
3801
Jiang Liu59ce0512014-02-19 14:07:35 +08003802int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
3803{
3804 int ret = 0;
3805 struct dmar_rmrr_unit *rmrru;
3806 struct dmar_atsr_unit *atsru;
3807 struct acpi_dmar_atsr *atsr;
3808 struct acpi_dmar_reserved_memory *rmrr;
3809
3810 if (!intel_iommu_enabled && system_state != SYSTEM_BOOTING)
3811 return 0;
3812
3813 list_for_each_entry(rmrru, &dmar_rmrr_units, list) {
3814 rmrr = container_of(rmrru->hdr,
3815 struct acpi_dmar_reserved_memory, header);
3816 if (info->event == BUS_NOTIFY_ADD_DEVICE) {
3817 ret = dmar_insert_dev_scope(info, (void *)(rmrr + 1),
3818 ((void *)rmrr) + rmrr->header.length,
3819 rmrr->segment, rmrru->devices,
3820 rmrru->devices_cnt);
Jiang Liu27e24952014-06-20 15:08:06 +08003821 if(ret < 0)
Jiang Liu59ce0512014-02-19 14:07:35 +08003822 return ret;
3823 } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
Jiang Liu27e24952014-06-20 15:08:06 +08003824 dmar_remove_dev_scope(info, rmrr->segment,
3825 rmrru->devices, rmrru->devices_cnt);
Jiang Liu59ce0512014-02-19 14:07:35 +08003826 }
3827 }
3828
3829 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3830 if (atsru->include_all)
3831 continue;
3832
3833 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3834 if (info->event == BUS_NOTIFY_ADD_DEVICE) {
3835 ret = dmar_insert_dev_scope(info, (void *)(atsr + 1),
3836 (void *)atsr + atsr->header.length,
3837 atsr->segment, atsru->devices,
3838 atsru->devices_cnt);
3839 if (ret > 0)
3840 break;
3841 else if(ret < 0)
3842 return ret;
3843 } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
3844 if (dmar_remove_dev_scope(info, atsr->segment,
3845 atsru->devices, atsru->devices_cnt))
3846 break;
3847 }
3848 }
3849
3850 return 0;
3851}
3852
Fenghua Yu99dcade2009-11-11 07:23:06 -08003853/*
3854 * Here we only respond to action of unbound device from driver.
3855 *
3856 * Added device is not attached to its DMAR domain here yet. That will happen
3857 * when mapping the device to iova.
3858 */
3859static int device_notifier(struct notifier_block *nb,
3860 unsigned long action, void *data)
3861{
3862 struct device *dev = data;
Fenghua Yu99dcade2009-11-11 07:23:06 -08003863 struct dmar_domain *domain;
3864
David Woodhouse3d891942014-03-06 15:59:26 +00003865 if (iommu_dummy(dev))
David Woodhouse44cd6132009-12-02 10:18:30 +00003866 return 0;
3867
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003868 if (action != BUS_NOTIFY_UNBOUND_DRIVER &&
3869 action != BUS_NOTIFY_DEL_DEVICE)
3870 return 0;
3871
David Woodhouse1525a292014-03-06 16:19:30 +00003872 domain = find_domain(dev);
Fenghua Yu99dcade2009-11-11 07:23:06 -08003873 if (!domain)
3874 return 0;
3875
Jiang Liu3a5670e2014-02-19 14:07:33 +08003876 down_read(&dmar_global_lock);
David Woodhousebf9c9ed2014-03-09 16:19:13 -07003877 domain_remove_one_dev_info(domain, dev);
Jiang Liuab8dfe22014-07-11 14:19:27 +08003878 if (!domain_type_is_vm_or_si(domain) && list_empty(&domain->devices))
Jiang Liu7e7dfab2014-02-19 14:07:23 +08003879 domain_exit(domain);
Jiang Liu3a5670e2014-02-19 14:07:33 +08003880 up_read(&dmar_global_lock);
Alex Williamsona97590e2011-03-04 14:52:16 -07003881
Fenghua Yu99dcade2009-11-11 07:23:06 -08003882 return 0;
3883}
3884
3885static struct notifier_block device_nb = {
3886 .notifier_call = device_notifier,
3887};
3888
Jiang Liu75f05562014-02-19 14:07:37 +08003889static int intel_iommu_memory_notifier(struct notifier_block *nb,
3890 unsigned long val, void *v)
3891{
3892 struct memory_notify *mhp = v;
3893 unsigned long long start, end;
3894 unsigned long start_vpfn, last_vpfn;
3895
3896 switch (val) {
3897 case MEM_GOING_ONLINE:
3898 start = mhp->start_pfn << PAGE_SHIFT;
3899 end = ((mhp->start_pfn + mhp->nr_pages) << PAGE_SHIFT) - 1;
3900 if (iommu_domain_identity_map(si_domain, start, end)) {
3901 pr_warn("dmar: failed to build identity map for [%llx-%llx]\n",
3902 start, end);
3903 return NOTIFY_BAD;
3904 }
3905 break;
3906
3907 case MEM_OFFLINE:
3908 case MEM_CANCEL_ONLINE:
3909 start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
3910 last_vpfn = mm_to_dma_pfn(mhp->start_pfn + mhp->nr_pages - 1);
3911 while (start_vpfn <= last_vpfn) {
3912 struct iova *iova;
3913 struct dmar_drhd_unit *drhd;
3914 struct intel_iommu *iommu;
David Woodhouseea8ea462014-03-05 17:09:32 +00003915 struct page *freelist;
Jiang Liu75f05562014-02-19 14:07:37 +08003916
3917 iova = find_iova(&si_domain->iovad, start_vpfn);
3918 if (iova == NULL) {
3919 pr_debug("dmar: failed get IOVA for PFN %lx\n",
3920 start_vpfn);
3921 break;
3922 }
3923
3924 iova = split_and_remove_iova(&si_domain->iovad, iova,
3925 start_vpfn, last_vpfn);
3926 if (iova == NULL) {
3927 pr_warn("dmar: failed to split IOVA PFN [%lx-%lx]\n",
3928 start_vpfn, last_vpfn);
3929 return NOTIFY_BAD;
3930 }
3931
David Woodhouseea8ea462014-03-05 17:09:32 +00003932 freelist = domain_unmap(si_domain, iova->pfn_lo,
3933 iova->pfn_hi);
3934
Jiang Liu75f05562014-02-19 14:07:37 +08003935 rcu_read_lock();
3936 for_each_active_iommu(iommu, drhd)
3937 iommu_flush_iotlb_psi(iommu, si_domain->id,
3938 iova->pfn_lo,
David Woodhouseea8ea462014-03-05 17:09:32 +00003939 iova->pfn_hi - iova->pfn_lo + 1,
3940 !freelist, 0);
Jiang Liu75f05562014-02-19 14:07:37 +08003941 rcu_read_unlock();
David Woodhouseea8ea462014-03-05 17:09:32 +00003942 dma_free_pagelist(freelist);
Jiang Liu75f05562014-02-19 14:07:37 +08003943
3944 start_vpfn = iova->pfn_hi + 1;
3945 free_iova_mem(iova);
3946 }
3947 break;
3948 }
3949
3950 return NOTIFY_OK;
3951}
3952
3953static struct notifier_block intel_iommu_memory_nb = {
3954 .notifier_call = intel_iommu_memory_notifier,
3955 .priority = 0
3956};
3957
Alex Williamsona5459cf2014-06-12 16:12:31 -06003958
3959static ssize_t intel_iommu_show_version(struct device *dev,
3960 struct device_attribute *attr,
3961 char *buf)
3962{
3963 struct intel_iommu *iommu = dev_get_drvdata(dev);
3964 u32 ver = readl(iommu->reg + DMAR_VER_REG);
3965 return sprintf(buf, "%d:%d\n",
3966 DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver));
3967}
3968static DEVICE_ATTR(version, S_IRUGO, intel_iommu_show_version, NULL);
3969
3970static ssize_t intel_iommu_show_address(struct device *dev,
3971 struct device_attribute *attr,
3972 char *buf)
3973{
3974 struct intel_iommu *iommu = dev_get_drvdata(dev);
3975 return sprintf(buf, "%llx\n", iommu->reg_phys);
3976}
3977static DEVICE_ATTR(address, S_IRUGO, intel_iommu_show_address, NULL);
3978
3979static ssize_t intel_iommu_show_cap(struct device *dev,
3980 struct device_attribute *attr,
3981 char *buf)
3982{
3983 struct intel_iommu *iommu = dev_get_drvdata(dev);
3984 return sprintf(buf, "%llx\n", iommu->cap);
3985}
3986static DEVICE_ATTR(cap, S_IRUGO, intel_iommu_show_cap, NULL);
3987
3988static ssize_t intel_iommu_show_ecap(struct device *dev,
3989 struct device_attribute *attr,
3990 char *buf)
3991{
3992 struct intel_iommu *iommu = dev_get_drvdata(dev);
3993 return sprintf(buf, "%llx\n", iommu->ecap);
3994}
3995static DEVICE_ATTR(ecap, S_IRUGO, intel_iommu_show_ecap, NULL);
3996
3997static struct attribute *intel_iommu_attrs[] = {
3998 &dev_attr_version.attr,
3999 &dev_attr_address.attr,
4000 &dev_attr_cap.attr,
4001 &dev_attr_ecap.attr,
4002 NULL,
4003};
4004
4005static struct attribute_group intel_iommu_group = {
4006 .name = "intel-iommu",
4007 .attrs = intel_iommu_attrs,
4008};
4009
4010const struct attribute_group *intel_iommu_groups[] = {
4011 &intel_iommu_group,
4012 NULL,
4013};
4014
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004015int __init intel_iommu_init(void)
4016{
Jiang Liu9bdc5312014-01-06 14:18:27 +08004017 int ret = -ENODEV;
Takao Indoh3a93c842013-04-23 17:35:03 +09004018 struct dmar_drhd_unit *drhd;
Jiang Liu7c919772014-01-06 14:18:18 +08004019 struct intel_iommu *iommu;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004020
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07004021 /* VT-d is required for a TXT/tboot launch, so enforce that */
4022 force_on = tboot_force_iommu();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004023
Jiang Liu3a5670e2014-02-19 14:07:33 +08004024 if (iommu_init_mempool()) {
4025 if (force_on)
4026 panic("tboot: Failed to initialize iommu memory\n");
4027 return -ENOMEM;
4028 }
4029
4030 down_write(&dmar_global_lock);
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07004031 if (dmar_table_init()) {
4032 if (force_on)
4033 panic("tboot: Failed to initialize DMAR table\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08004034 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07004035 }
4036
Takao Indoh3a93c842013-04-23 17:35:03 +09004037 /*
4038 * Disable translation if already enabled prior to OS handover.
4039 */
Jiang Liu7c919772014-01-06 14:18:18 +08004040 for_each_active_iommu(iommu, drhd)
Takao Indoh3a93c842013-04-23 17:35:03 +09004041 if (iommu->gcmd & DMA_GCMD_TE)
4042 iommu_disable_translation(iommu);
Takao Indoh3a93c842013-04-23 17:35:03 +09004043
Suresh Siddhac2c72862011-08-23 17:05:19 -07004044 if (dmar_dev_scope_init() < 0) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07004045 if (force_on)
4046 panic("tboot: Failed to initialize DMAR device scope\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08004047 goto out_free_dmar;
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07004048 }
Suresh Siddha1886e8a2008-07-10 11:16:37 -07004049
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09004050 if (no_iommu || dmar_disabled)
Jiang Liu9bdc5312014-01-06 14:18:27 +08004051 goto out_free_dmar;
Suresh Siddha2ae21012008-07-10 11:16:43 -07004052
Suresh Siddha318fe7d2011-08-23 17:05:20 -07004053 if (list_empty(&dmar_rmrr_units))
4054 printk(KERN_INFO "DMAR: No RMRR found\n");
4055
4056 if (list_empty(&dmar_atsr_units))
4057 printk(KERN_INFO "DMAR: No ATSR found\n");
4058
Joseph Cihula51a63e62011-03-21 11:04:24 -07004059 if (dmar_init_reserved_ranges()) {
4060 if (force_on)
4061 panic("tboot: Failed to reserve iommu ranges\n");
Jiang Liu3a5670e2014-02-19 14:07:33 +08004062 goto out_free_reserved_range;
Joseph Cihula51a63e62011-03-21 11:04:24 -07004063 }
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004064
4065 init_no_remapping_devices();
4066
Joseph Cihulab7792602011-05-03 00:08:37 -07004067 ret = init_dmars();
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004068 if (ret) {
Joseph Cihulaa59b50e2009-06-30 19:31:10 -07004069 if (force_on)
4070 panic("tboot: Failed to initialize DMARs\n");
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004071 printk(KERN_ERR "IOMMU: dmar init failed\n");
Jiang Liu9bdc5312014-01-06 14:18:27 +08004072 goto out_free_reserved_range;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004073 }
Jiang Liu3a5670e2014-02-19 14:07:33 +08004074 up_write(&dmar_global_lock);
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004075 printk(KERN_INFO
4076 "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
4077
mark gross5e0d2a62008-03-04 15:22:08 -08004078 init_timer(&unmap_timer);
FUJITA Tomonori75f1cdf2009-11-10 19:46:20 +09004079#ifdef CONFIG_SWIOTLB
4080 swiotlb = 0;
4081#endif
David Woodhouse19943b02009-08-04 16:19:20 +01004082 dma_ops = &intel_dma_ops;
Fenghua Yu4ed0d3e2009-04-24 17:30:20 -07004083
Rafael J. Wysocki134fac32011-03-23 22:16:14 +01004084 init_iommu_pm_ops();
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004085
Alex Williamsona5459cf2014-06-12 16:12:31 -06004086 for_each_active_iommu(iommu, drhd)
4087 iommu->iommu_dev = iommu_device_create(NULL, iommu,
4088 intel_iommu_groups,
4089 iommu->name);
4090
Joerg Roedel4236d97d2011-09-06 17:56:07 +02004091 bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
Fenghua Yu99dcade2009-11-11 07:23:06 -08004092 bus_register_notifier(&pci_bus_type, &device_nb);
Jiang Liu75f05562014-02-19 14:07:37 +08004093 if (si_domain && !hw_pass_through)
4094 register_memory_notifier(&intel_iommu_memory_nb);
Fenghua Yu99dcade2009-11-11 07:23:06 -08004095
Eugeni Dodonov8bc1f852011-11-23 16:42:14 -02004096 intel_iommu_enabled = 1;
4097
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004098 return 0;
Jiang Liu9bdc5312014-01-06 14:18:27 +08004099
4100out_free_reserved_range:
4101 put_iova_domain(&reserved_iova_list);
Jiang Liu9bdc5312014-01-06 14:18:27 +08004102out_free_dmar:
4103 intel_iommu_free_dmars();
Jiang Liu3a5670e2014-02-19 14:07:33 +08004104 up_write(&dmar_global_lock);
4105 iommu_exit_mempool();
Jiang Liu9bdc5312014-01-06 14:18:27 +08004106 return ret;
Keshavamurthy, Anil Sba395922007-10-21 16:41:49 -07004107}
Keshavamurthy, Anil Se8204822007-10-21 16:41:55 -07004108
Alex Williamson579305f2014-07-03 09:51:43 -06004109static int iommu_detach_dev_cb(struct pci_dev *pdev, u16 alias, void *opaque)
4110{
4111 struct intel_iommu *iommu = opaque;
4112
4113 iommu_detach_dev(iommu, PCI_BUS_NUM(alias), alias & 0xff);
4114 return 0;
4115}
4116
4117/*
4118 * NB - intel-iommu lacks any sort of reference counting for the users of
4119 * dependent devices. If multiple endpoints have intersecting dependent
4120 * devices, unbinding the driver from any one of them will possibly leave
4121 * the others unable to operate.
4122 */
Han, Weidong3199aa62009-02-26 17:31:12 +08004123static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
David Woodhouse0bcb3e22014-03-06 17:12:03 +00004124 struct device *dev)
Han, Weidong3199aa62009-02-26 17:31:12 +08004125{
David Woodhouse0bcb3e22014-03-06 17:12:03 +00004126 if (!iommu || !dev || !dev_is_pci(dev))
Han, Weidong3199aa62009-02-26 17:31:12 +08004127 return;
4128
Alex Williamson579305f2014-07-03 09:51:43 -06004129 pci_for_each_dma_alias(to_pci_dev(dev), &iommu_detach_dev_cb, iommu);
Han, Weidong3199aa62009-02-26 17:31:12 +08004130}
4131
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004132static void domain_remove_one_dev_info(struct dmar_domain *domain,
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004133 struct device *dev)
Weidong Hanc7151a82008-12-08 22:51:37 +08004134{
Yijing Wangbca2b912013-10-31 17:26:04 +08004135 struct device_domain_info *info, *tmp;
Weidong Hanc7151a82008-12-08 22:51:37 +08004136 struct intel_iommu *iommu;
4137 unsigned long flags;
4138 int found = 0;
David Woodhouse156baca2014-03-09 14:00:57 -07004139 u8 bus, devfn;
Weidong Hanc7151a82008-12-08 22:51:37 +08004140
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004141 iommu = device_to_iommu(dev, &bus, &devfn);
Weidong Hanc7151a82008-12-08 22:51:37 +08004142 if (!iommu)
4143 return;
4144
4145 spin_lock_irqsave(&device_domain_lock, flags);
Yijing Wangbca2b912013-10-31 17:26:04 +08004146 list_for_each_entry_safe(info, tmp, &domain->devices, link) {
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004147 if (info->iommu == iommu && info->bus == bus &&
4148 info->devfn == devfn) {
David Woodhouse109b9b02012-05-25 17:43:02 +01004149 unlink_domain_info(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08004150 spin_unlock_irqrestore(&device_domain_lock, flags);
4151
Yu Zhao93a23a72009-05-18 13:51:37 +08004152 iommu_disable_dev_iotlb(info);
Weidong Hanc7151a82008-12-08 22:51:37 +08004153 iommu_detach_dev(iommu, info->bus, info->devfn);
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004154 iommu_detach_dependent_devices(iommu, dev);
Weidong Hanc7151a82008-12-08 22:51:37 +08004155 free_devinfo_mem(info);
4156
4157 spin_lock_irqsave(&device_domain_lock, flags);
4158
4159 if (found)
4160 break;
4161 else
4162 continue;
4163 }
4164
4165 /* if there is no other devices under the same iommu
4166 * owned by this domain, clear this iommu in iommu_bmp
4167 * update iommu count and coherency
4168 */
David Woodhouse8bbc4412014-03-09 13:52:37 -07004169 if (info->iommu == iommu)
Weidong Hanc7151a82008-12-08 22:51:37 +08004170 found = 1;
4171 }
4172
Roland Dreier3e7abe22011-07-20 06:22:21 -07004173 spin_unlock_irqrestore(&device_domain_lock, flags);
4174
Weidong Hanc7151a82008-12-08 22:51:37 +08004175 if (found == 0) {
Jiang Liufb170fb2014-07-11 14:19:28 +08004176 domain_detach_iommu(domain, iommu);
4177 if (!domain_type_is_vm_or_si(domain))
4178 iommu_detach_domain(domain, iommu);
Weidong Hanc7151a82008-12-08 22:51:37 +08004179 }
Weidong Hanc7151a82008-12-08 22:51:37 +08004180}
4181
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004182static int md_domain_init(struct dmar_domain *domain, int guest_width)
Weidong Han5e98c4b2008-12-08 23:03:27 +08004183{
4184 int adjust_width;
4185
4186 init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
Weidong Han5e98c4b2008-12-08 23:03:27 +08004187 domain_reserve_special_ranges(domain);
4188
4189 /* calculate AGAW */
4190 domain->gaw = guest_width;
4191 adjust_width = guestwidth_to_adjustwidth(guest_width);
4192 domain->agaw = width_to_agaw(adjust_width);
4193
Weidong Han5e98c4b2008-12-08 23:03:27 +08004194 domain->iommu_coherency = 0;
Sheng Yangc5b15252009-08-06 13:31:56 +08004195 domain->iommu_snooping = 0;
Youquan Song6dd9a7c2011-05-25 19:13:49 +01004196 domain->iommu_superpage = 0;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004197 domain->max_addr = 0;
Weidong Han5e98c4b2008-12-08 23:03:27 +08004198
4199 /* always allocate the top pgd */
Suresh Siddha4c923d42009-10-02 11:01:24 -07004200 domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
Weidong Han5e98c4b2008-12-08 23:03:27 +08004201 if (!domain->pgd)
4202 return -ENOMEM;
4203 domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
4204 return 0;
4205}
4206
Joerg Roedel5d450802008-12-03 14:52:32 +01004207static int intel_iommu_domain_init(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03004208{
Joerg Roedel5d450802008-12-03 14:52:32 +01004209 struct dmar_domain *dmar_domain;
Kay, Allen M38717942008-09-09 18:37:29 +03004210
Jiang Liuab8dfe22014-07-11 14:19:27 +08004211 dmar_domain = alloc_domain(DOMAIN_FLAG_VIRTUAL_MACHINE);
Joerg Roedel5d450802008-12-03 14:52:32 +01004212 if (!dmar_domain) {
Kay, Allen M38717942008-09-09 18:37:29 +03004213 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01004214 "intel_iommu_domain_init: dmar_domain == NULL\n");
4215 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03004216 }
Fenghua Yu2c2e2c32009-06-19 13:47:29 -07004217 if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
Kay, Allen M38717942008-09-09 18:37:29 +03004218 printk(KERN_ERR
Joerg Roedel5d450802008-12-03 14:52:32 +01004219 "intel_iommu_domain_init() failed\n");
Jiang Liu92d03cc2014-02-19 14:07:28 +08004220 domain_exit(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01004221 return -ENOMEM;
Kay, Allen M38717942008-09-09 18:37:29 +03004222 }
Allen Kay8140a952011-10-14 12:32:17 -07004223 domain_update_iommu_cap(dmar_domain);
Joerg Roedel5d450802008-12-03 14:52:32 +01004224 domain->priv = dmar_domain;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004225
Joerg Roedel8a0e7152012-01-26 19:40:54 +01004226 domain->geometry.aperture_start = 0;
4227 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
4228 domain->geometry.force_aperture = true;
4229
Joerg Roedel5d450802008-12-03 14:52:32 +01004230 return 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004231}
Kay, Allen M38717942008-09-09 18:37:29 +03004232
Joerg Roedel5d450802008-12-03 14:52:32 +01004233static void intel_iommu_domain_destroy(struct iommu_domain *domain)
Kay, Allen M38717942008-09-09 18:37:29 +03004234{
Joerg Roedel5d450802008-12-03 14:52:32 +01004235 struct dmar_domain *dmar_domain = domain->priv;
4236
4237 domain->priv = NULL;
Jiang Liu92d03cc2014-02-19 14:07:28 +08004238 domain_exit(dmar_domain);
Kay, Allen M38717942008-09-09 18:37:29 +03004239}
Kay, Allen M38717942008-09-09 18:37:29 +03004240
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004241static int intel_iommu_attach_device(struct iommu_domain *domain,
4242 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004243{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004244 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004245 struct intel_iommu *iommu;
4246 int addr_width;
David Woodhouse156baca2014-03-09 14:00:57 -07004247 u8 bus, devfn;
Kay, Allen M38717942008-09-09 18:37:29 +03004248
David Woodhouse7207d8f2014-03-09 16:31:06 -07004249 /* normally dev is not mapped */
4250 if (unlikely(domain_context_mapped(dev))) {
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004251 struct dmar_domain *old_domain;
4252
David Woodhouse1525a292014-03-06 16:19:30 +00004253 old_domain = find_domain(dev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004254 if (old_domain) {
Jiang Liuab8dfe22014-07-11 14:19:27 +08004255 if (domain_type_is_vm_or_si(dmar_domain))
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004256 domain_remove_one_dev_info(old_domain, dev);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004257 else
4258 domain_remove_dev_info(old_domain);
4259 }
4260 }
4261
David Woodhouse156baca2014-03-09 14:00:57 -07004262 iommu = device_to_iommu(dev, &bus, &devfn);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004263 if (!iommu)
4264 return -ENODEV;
4265
4266 /* check if this iommu agaw is sufficient for max mapped address */
4267 addr_width = agaw_to_width(iommu->agaw);
Tom Lyona99c47a2010-05-17 08:20:45 +01004268 if (addr_width > cap_mgaw(iommu->cap))
4269 addr_width = cap_mgaw(iommu->cap);
4270
4271 if (dmar_domain->max_addr > (1LL << addr_width)) {
4272 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004273 "sufficient for the mapped address (%llx)\n",
Tom Lyona99c47a2010-05-17 08:20:45 +01004274 __func__, addr_width, dmar_domain->max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004275 return -EFAULT;
4276 }
Tom Lyona99c47a2010-05-17 08:20:45 +01004277 dmar_domain->gaw = addr_width;
4278
4279 /*
4280 * Knock out extra levels of page tables if necessary
4281 */
4282 while (iommu->agaw < dmar_domain->agaw) {
4283 struct dma_pte *pte;
4284
4285 pte = dmar_domain->pgd;
4286 if (dma_pte_present(pte)) {
Sheng Yang25cbff12010-06-12 19:21:42 +08004287 dmar_domain->pgd = (struct dma_pte *)
4288 phys_to_virt(dma_pte_addr(pte));
Jan Kiszka7a661012010-11-02 08:05:51 +01004289 free_pgtable_page(pte);
Tom Lyona99c47a2010-05-17 08:20:45 +01004290 }
4291 dmar_domain->agaw--;
4292 }
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004293
David Woodhouse5913c9b2014-03-09 16:27:31 -07004294 return domain_add_dev_info(dmar_domain, dev, CONTEXT_TT_MULTI_LEVEL);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004295}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004296
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004297static void intel_iommu_detach_device(struct iommu_domain *domain,
4298 struct device *dev)
Kay, Allen M38717942008-09-09 18:37:29 +03004299{
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004300 struct dmar_domain *dmar_domain = domain->priv;
Joerg Roedel4c5478c2008-12-03 14:58:24 +01004301
David Woodhousebf9c9ed2014-03-09 16:19:13 -07004302 domain_remove_one_dev_info(dmar_domain, dev);
Kay, Allen M38717942008-09-09 18:37:29 +03004303}
Kay, Allen M38717942008-09-09 18:37:29 +03004304
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004305static int intel_iommu_map(struct iommu_domain *domain,
4306 unsigned long iova, phys_addr_t hpa,
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004307 size_t size, int iommu_prot)
Kay, Allen M38717942008-09-09 18:37:29 +03004308{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004309 struct dmar_domain *dmar_domain = domain->priv;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004310 u64 max_addr;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004311 int prot = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004312 int ret;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004313
Joerg Roedeldde57a22008-12-03 15:04:09 +01004314 if (iommu_prot & IOMMU_READ)
4315 prot |= DMA_PTE_READ;
4316 if (iommu_prot & IOMMU_WRITE)
4317 prot |= DMA_PTE_WRITE;
Sheng Yang9cf06692009-03-18 15:33:07 +08004318 if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
4319 prot |= DMA_PTE_SNP;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004320
David Woodhouse163cc522009-06-28 00:51:17 +01004321 max_addr = iova + size;
Joerg Roedeldde57a22008-12-03 15:04:09 +01004322 if (dmar_domain->max_addr < max_addr) {
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004323 u64 end;
4324
4325 /* check if minimum agaw is sufficient for mapped address */
Tom Lyon8954da12010-05-17 08:19:52 +01004326 end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004327 if (end < max_addr) {
Tom Lyon8954da12010-05-17 08:19:52 +01004328 printk(KERN_ERR "%s: iommu width (%d) is not "
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004329 "sufficient for the mapped address (%llx)\n",
Tom Lyon8954da12010-05-17 08:19:52 +01004330 __func__, dmar_domain->gaw, max_addr);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004331 return -EFAULT;
4332 }
Joerg Roedeldde57a22008-12-03 15:04:09 +01004333 dmar_domain->max_addr = max_addr;
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004334 }
David Woodhousead051222009-06-28 14:22:28 +01004335 /* Round up size to next multiple of PAGE_SIZE, if it and
4336 the low bits of hpa would take us onto the next page */
David Woodhouse88cb6a72009-06-28 15:03:06 +01004337 size = aligned_nrpages(hpa, size);
David Woodhousead051222009-06-28 14:22:28 +01004338 ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
4339 hpa >> VTD_PAGE_SHIFT, size, prot);
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004340 return ret;
Kay, Allen M38717942008-09-09 18:37:29 +03004341}
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004342
Ohad Ben-Cohen50090652011-11-10 11:32:25 +02004343static size_t intel_iommu_unmap(struct iommu_domain *domain,
David Woodhouseea8ea462014-03-05 17:09:32 +00004344 unsigned long iova, size_t size)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004345{
Joerg Roedeldde57a22008-12-03 15:04:09 +01004346 struct dmar_domain *dmar_domain = domain->priv;
David Woodhouseea8ea462014-03-05 17:09:32 +00004347 struct page *freelist = NULL;
4348 struct intel_iommu *iommu;
4349 unsigned long start_pfn, last_pfn;
4350 unsigned int npages;
4351 int iommu_id, num, ndomains, level = 0;
Sheng Yang4b99d352009-07-08 11:52:52 +01004352
David Woodhouse5cf0a762014-03-19 16:07:49 +00004353 /* Cope with horrid API which requires us to unmap more than the
4354 size argument if it happens to be a large-page mapping. */
4355 if (!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level))
4356 BUG();
4357
4358 if (size < VTD_PAGE_SIZE << level_to_offset_bits(level))
4359 size = VTD_PAGE_SIZE << level_to_offset_bits(level);
4360
David Woodhouseea8ea462014-03-05 17:09:32 +00004361 start_pfn = iova >> VTD_PAGE_SHIFT;
4362 last_pfn = (iova + size - 1) >> VTD_PAGE_SHIFT;
4363
4364 freelist = domain_unmap(dmar_domain, start_pfn, last_pfn);
4365
4366 npages = last_pfn - start_pfn + 1;
4367
4368 for_each_set_bit(iommu_id, dmar_domain->iommu_bmp, g_num_of_iommus) {
4369 iommu = g_iommus[iommu_id];
4370
4371 /*
4372 * find bit position of dmar_domain
4373 */
4374 ndomains = cap_ndoms(iommu->cap);
4375 for_each_set_bit(num, iommu->domain_ids, ndomains) {
4376 if (iommu->domains[num] == dmar_domain)
4377 iommu_flush_iotlb_psi(iommu, num, start_pfn,
4378 npages, !freelist, 0);
4379 }
4380
4381 }
4382
4383 dma_free_pagelist(freelist);
Weidong Hanfe40f1e2008-12-08 23:10:23 +08004384
David Woodhouse163cc522009-06-28 00:51:17 +01004385 if (dmar_domain->max_addr == iova + size)
4386 dmar_domain->max_addr = iova;
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004387
David Woodhouse5cf0a762014-03-19 16:07:49 +00004388 return size;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004389}
Kay, Allen M38717942008-09-09 18:37:29 +03004390
Joerg Roedeld14d6572008-12-03 15:06:57 +01004391static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
Varun Sethibb5547a2013-03-29 01:23:58 +05304392 dma_addr_t iova)
Kay, Allen M38717942008-09-09 18:37:29 +03004393{
Joerg Roedeld14d6572008-12-03 15:06:57 +01004394 struct dmar_domain *dmar_domain = domain->priv;
Kay, Allen M38717942008-09-09 18:37:29 +03004395 struct dma_pte *pte;
David Woodhouse5cf0a762014-03-19 16:07:49 +00004396 int level = 0;
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004397 u64 phys = 0;
Kay, Allen M38717942008-09-09 18:37:29 +03004398
David Woodhouse5cf0a762014-03-19 16:07:49 +00004399 pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
Kay, Allen M38717942008-09-09 18:37:29 +03004400 if (pte)
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004401 phys = dma_pte_addr(pte);
Kay, Allen M38717942008-09-09 18:37:29 +03004402
Weidong Hanfaa3d6f2008-12-08 23:09:29 +08004403 return phys;
Kay, Allen M38717942008-09-09 18:37:29 +03004404}
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004405
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004406static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4407 unsigned long cap)
4408{
4409 struct dmar_domain *dmar_domain = domain->priv;
4410
4411 if (cap == IOMMU_CAP_CACHE_COHERENCY)
4412 return dmar_domain->iommu_snooping;
Tom Lyon323f99c2010-07-02 16:56:14 -04004413 if (cap == IOMMU_CAP_INTR_REMAP)
Suresh Siddha95a02e92012-03-30 11:47:07 -07004414 return irq_remapping_enabled;
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004415
4416 return 0;
4417}
4418
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004419static int intel_iommu_add_device(struct device *dev)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004420{
Alex Williamsona5459cf2014-06-12 16:12:31 -06004421 struct intel_iommu *iommu;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004422 struct iommu_group *group;
David Woodhouse156baca2014-03-09 14:00:57 -07004423 u8 bus, devfn;
Alex Williamson70ae6f02011-10-21 15:56:11 -04004424
Alex Williamsona5459cf2014-06-12 16:12:31 -06004425 iommu = device_to_iommu(dev, &bus, &devfn);
4426 if (!iommu)
Alex Williamson70ae6f02011-10-21 15:56:11 -04004427 return -ENODEV;
4428
Alex Williamsona5459cf2014-06-12 16:12:31 -06004429 iommu_device_link(iommu->iommu_dev, dev);
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004430
Alex Williamsone17f9ff2014-07-03 09:51:37 -06004431 group = iommu_group_get_for_dev(dev);
Alex Williamson783f1572012-05-30 14:19:43 -06004432
Alex Williamsone17f9ff2014-07-03 09:51:37 -06004433 if (IS_ERR(group))
4434 return PTR_ERR(group);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004435
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004436 iommu_group_put(group);
Alex Williamsone17f9ff2014-07-03 09:51:37 -06004437 return 0;
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004438}
4439
4440static void intel_iommu_remove_device(struct device *dev)
4441{
Alex Williamsona5459cf2014-06-12 16:12:31 -06004442 struct intel_iommu *iommu;
4443 u8 bus, devfn;
4444
4445 iommu = device_to_iommu(dev, &bus, &devfn);
4446 if (!iommu)
4447 return;
4448
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004449 iommu_group_remove_device(dev);
Alex Williamsona5459cf2014-06-12 16:12:31 -06004450
4451 iommu_device_unlink(iommu->iommu_dev, dev);
Alex Williamson70ae6f02011-10-21 15:56:11 -04004452}
4453
Thierry Redingb22f6432014-06-27 09:03:12 +02004454static const struct iommu_ops intel_iommu_ops = {
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004455 .domain_init = intel_iommu_domain_init,
4456 .domain_destroy = intel_iommu_domain_destroy,
4457 .attach_dev = intel_iommu_attach_device,
4458 .detach_dev = intel_iommu_detach_device,
Joerg Roedelb146a1c9f2010-01-20 17:17:37 +01004459 .map = intel_iommu_map,
4460 .unmap = intel_iommu_unmap,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004461 .iova_to_phys = intel_iommu_iova_to_phys,
Sheng Yangdbb9fd82009-03-18 15:33:06 +08004462 .domain_has_cap = intel_iommu_domain_has_cap,
Alex Williamsonabdfdde2012-05-30 14:19:19 -06004463 .add_device = intel_iommu_add_device,
4464 .remove_device = intel_iommu_remove_device,
Ohad Ben-Cohen6d1c56a2011-11-10 11:32:30 +02004465 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
Joerg Roedela8bcbb0d2008-12-03 15:14:02 +01004466};
David Woodhouse9af88142009-02-13 23:18:03 +00004467
Daniel Vetter94526182013-01-20 23:50:13 +01004468static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
4469{
4470 /* G4x/GM45 integrated gfx dmar support is totally busted. */
4471 printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
4472 dmar_map_gfx = 0;
4473}
4474
4475DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
4476DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
4477DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
4478DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
4479DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
4480DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
4481DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
4482
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004483static void quirk_iommu_rwbf(struct pci_dev *dev)
David Woodhouse9af88142009-02-13 23:18:03 +00004484{
4485 /*
4486 * Mobile 4 Series Chipset neglects to set RWBF capability,
Daniel Vetter210561f2013-01-21 19:48:59 +01004487 * but needs it. Same seems to hold for the desktop versions.
David Woodhouse9af88142009-02-13 23:18:03 +00004488 */
4489 printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
4490 rwbf_quirk = 1;
4491}
4492
4493DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
Daniel Vetter210561f2013-01-21 19:48:59 +01004494DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
4495DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
4496DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
4497DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
4498DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
4499DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
David Woodhousee0fc7e02009-09-30 09:12:17 -07004500
Adam Jacksoneecfd572010-08-25 21:17:34 +01004501#define GGC 0x52
4502#define GGC_MEMORY_SIZE_MASK (0xf << 8)
4503#define GGC_MEMORY_SIZE_NONE (0x0 << 8)
4504#define GGC_MEMORY_SIZE_1M (0x1 << 8)
4505#define GGC_MEMORY_SIZE_2M (0x3 << 8)
4506#define GGC_MEMORY_VT_ENABLED (0x8 << 8)
4507#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8)
4508#define GGC_MEMORY_SIZE_3M_VT (0xa << 8)
4509#define GGC_MEMORY_SIZE_4M_VT (0xb << 8)
4510
Greg Kroah-Hartmand34d6512012-12-21 15:05:21 -08004511static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
David Woodhouse9eecabc2010-09-21 22:28:23 +01004512{
4513 unsigned short ggc;
4514
Adam Jacksoneecfd572010-08-25 21:17:34 +01004515 if (pci_read_config_word(dev, GGC, &ggc))
David Woodhouse9eecabc2010-09-21 22:28:23 +01004516 return;
4517
Adam Jacksoneecfd572010-08-25 21:17:34 +01004518 if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
David Woodhouse9eecabc2010-09-21 22:28:23 +01004519 printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
4520 dmar_map_gfx = 0;
David Woodhouse6fbcfb32011-09-25 19:11:14 -07004521 } else if (dmar_map_gfx) {
4522 /* we have to ensure the gfx device is idle before we flush */
4523 printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
4524 intel_iommu_strict = 1;
4525 }
David Woodhouse9eecabc2010-09-21 22:28:23 +01004526}
4527DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
4528DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
4529DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
4530DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
4531
David Woodhousee0fc7e02009-09-30 09:12:17 -07004532/* On Tylersburg chipsets, some BIOSes have been known to enable the
4533 ISOCH DMAR unit for the Azalia sound device, but not give it any
4534 TLB entries, which causes it to deadlock. Check for that. We do
4535 this in a function called from init_dmars(), instead of in a PCI
4536 quirk, because we don't want to print the obnoxious "BIOS broken"
4537 message if VT-d is actually disabled.
4538*/
4539static void __init check_tylersburg_isoch(void)
4540{
4541 struct pci_dev *pdev;
4542 uint32_t vtisochctrl;
4543
4544 /* If there's no Azalia in the system anyway, forget it. */
4545 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
4546 if (!pdev)
4547 return;
4548 pci_dev_put(pdev);
4549
4550 /* System Management Registers. Might be hidden, in which case
4551 we can't do the sanity check. But that's OK, because the
4552 known-broken BIOSes _don't_ actually hide it, so far. */
4553 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
4554 if (!pdev)
4555 return;
4556
4557 if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
4558 pci_dev_put(pdev);
4559 return;
4560 }
4561
4562 pci_dev_put(pdev);
4563
4564 /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
4565 if (vtisochctrl & 1)
4566 return;
4567
4568 /* Drop all bits other than the number of TLB entries */
4569 vtisochctrl &= 0x1c;
4570
4571 /* If we have the recommended number of TLB entries (16), fine. */
4572 if (vtisochctrl == 0x10)
4573 return;
4574
4575 /* Zero TLB entries? You get to ride the short bus to school. */
4576 if (!vtisochctrl) {
4577 WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
4578 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
4579 dmi_get_system_info(DMI_BIOS_VENDOR),
4580 dmi_get_system_info(DMI_BIOS_VERSION),
4581 dmi_get_system_info(DMI_PRODUCT_VERSION));
4582 iommu_identity_mapping |= IDENTMAP_AZALIA;
4583 return;
4584 }
4585
4586 printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
4587 vtisochctrl);
4588}