Blame view

drivers/iommu/amd_iommu_init.c 67.3 KB
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
1
  /*
5d0d71569   Joerg Roedel   x86/amd-iommu: Up...
2
   * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
63ce3ae88   Joerg Roedel   iommu: Update my ...
3
   * Author: Joerg Roedel <jroedel@suse.de>
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
   *         Leo Duran <leo.duran@amd.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published
   * by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
  
  #include <linux/pci.h>
  #include <linux/acpi.h>
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
22
  #include <linux/list.h>
5c87f62dd   Baoquan He   iommu/amd: Use st...
23
  #include <linux/bitmap.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
24
  #include <linux/slab.h>
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
25
  #include <linux/syscore_ops.h>
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
26
27
  #include <linux/interrupt.h>
  #include <linux/msi.h>
403f81d8e   Joerg Roedel   iommu/amd: Move m...
28
  #include <linux/amd-iommu.h>
400a28a05   Joerg Roedel   iommu/amd: Add io...
29
  #include <linux/export.h>
066f2e98d   Alex Williamson   iommu/amd: Add sy...
30
  #include <linux/iommu.h>
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
31
  #include <asm/pci-direct.h>
46a7fa270   FUJITA Tomonori   x86: make only GA...
32
  #include <asm/iommu.h>
1d9b16d16   Joerg Roedel   x86: move GART sp...
33
  #include <asm/gart.h>
ea1b0d394   FUJITA Tomonori   x86: amd_iommu: C...
34
  #include <asm/x86_init.h>
22e6daf41   Konrad Rzeszutek Wilk   x86, GART/AMD-VI:...
35
  #include <asm/iommu_table.h>
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
36
  #include <asm/io_apic.h>
6b474b822   Joerg Roedel   iommu/amd: Add in...
37
  #include <asm/irq_remapping.h>
403f81d8e   Joerg Roedel   iommu/amd: Move m...
38
39
40
  
  #include "amd_iommu_proto.h"
  #include "amd_iommu_types.h"
05152a049   Joerg Roedel   iommu/amd: Add sl...
41
  #include "irq_remapping.h"
403f81d8e   Joerg Roedel   iommu/amd: Move m...
42

f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
43
44
45
  /*
   * definitions for the ACPI scanning code
   */
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
46
  #define IVRS_HEADER_LENGTH 48
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
47

8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
48
  #define ACPI_IVHD_TYPE_MAX_SUPPORTED	0x40
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
49
50
51
52
53
54
55
56
57
58
59
60
  #define ACPI_IVMD_TYPE_ALL              0x20
  #define ACPI_IVMD_TYPE                  0x21
  #define ACPI_IVMD_TYPE_RANGE            0x22
  
  #define IVHD_DEV_ALL                    0x01
  #define IVHD_DEV_SELECT                 0x02
  #define IVHD_DEV_SELECT_RANGE_START     0x03
  #define IVHD_DEV_RANGE_END              0x04
  #define IVHD_DEV_ALIAS                  0x42
  #define IVHD_DEV_ALIAS_RANGE            0x43
  #define IVHD_DEV_EXT_SELECT             0x46
  #define IVHD_DEV_EXT_SELECT_RANGE       0x47
6efed63be   Joerg Roedel   iommu/amd: Keep t...
61
  #define IVHD_DEV_SPECIAL		0x48
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
62
  #define IVHD_DEV_ACPI_HID		0xf0
6efed63be   Joerg Roedel   iommu/amd: Keep t...
63

2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
64
65
66
  #define UID_NOT_PRESENT                 0
  #define UID_IS_INTEGER                  1
  #define UID_IS_CHARACTER                2
6efed63be   Joerg Roedel   iommu/amd: Keep t...
67
68
  #define IVHD_SPECIAL_IOAPIC		1
  #define IVHD_SPECIAL_HPET		2
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
69

6da7342ff   Joerg Roedel   amd-iommu: fix io...
70
71
72
73
  #define IVHD_FLAG_HT_TUN_EN_MASK        0x01
  #define IVHD_FLAG_PASSPW_EN_MASK        0x02
  #define IVHD_FLAG_RESPASSPW_EN_MASK     0x04
  #define IVHD_FLAG_ISOC_EN_MASK          0x08
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
74
75
76
77
78
79
80
81
82
83
84
85
  
  #define IVMD_FLAG_EXCL_RANGE            0x08
  #define IVMD_FLAG_UNITY_MAP             0x01
  
  #define ACPI_DEVFLAG_INITPASS           0x01
  #define ACPI_DEVFLAG_EXTINT             0x02
  #define ACPI_DEVFLAG_NMI                0x04
  #define ACPI_DEVFLAG_SYSMGT1            0x10
  #define ACPI_DEVFLAG_SYSMGT2            0x20
  #define ACPI_DEVFLAG_LINT0              0x40
  #define ACPI_DEVFLAG_LINT1              0x80
  #define ACPI_DEVFLAG_ATSDIS             0x10000000
8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
86
  #define LOOP_TIMEOUT	100000
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
87
88
89
90
91
92
93
94
95
96
97
  /*
   * ACPI table definitions
   *
   * These data structures are laid over the table to parse the important values
   * out of it.
   */
  
  /*
   * structure describing one IOMMU in the ACPI table. Typically followed by one
   * or more ivhd_entrys.
   */
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
98
99
100
101
102
103
104
105
106
  struct ivhd_header {
  	u8 type;
  	u8 flags;
  	u16 length;
  	u16 devid;
  	u16 cap_ptr;
  	u64 mmio_phys;
  	u16 pci_seg;
  	u16 info;
7d7d38afb   Suravee Suthikulpanit   iommu/amd: Adding...
107
108
109
110
111
  	u32 efr_attr;
  
  	/* Following only valid on IVHD type 11h and 40h */
  	u64 efr_reg; /* Exact copy of MMIO_EXT_FEATURES */
  	u64 res;
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
112
  } __attribute__((packed));
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
113
114
115
116
  /*
   * A device entry describing which devices a specific IOMMU translates and
   * which requestor ids they use.
   */
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
117
118
119
120
121
  struct ivhd_entry {
  	u8 type;
  	u16 devid;
  	u8 flags;
  	u32 ext;
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
122
123
124
125
126
  	u32 hidh;
  	u64 cid;
  	u8 uidf;
  	u8 uidl;
  	u8 uid;
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
127
  } __attribute__((packed));
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
128
129
130
131
  /*
   * An AMD IOMMU memory definition structure. It defines things like exclusion
   * ranges for devices and regions that should be unity mapped.
   */
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
132
133
134
135
136
137
138
139
140
141
  struct ivmd_header {
  	u8 type;
  	u8 flags;
  	u16 length;
  	u16 devid;
  	u16 aux;
  	u64 resv;
  	u64 range_start;
  	u64 range_length;
  } __attribute__((packed));
fefda117d   Joerg Roedel   amd-iommu: add am...
142
  bool amd_iommu_dump;
05152a049   Joerg Roedel   iommu/amd: Add sl...
143
  bool amd_iommu_irq_remap __read_mostly;
fefda117d   Joerg Roedel   amd-iommu: add am...
144

d98de49a5   Suravee Suthikulpanit   iommu/amd: Enable...
145
  int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
146

02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
147
  static bool amd_iommu_detected;
a52357259   Joerg Roedel   x86/amd-iommu: Ad...
148
  static bool __initdata amd_iommu_disabled;
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
149
  static int amd_iommu_target_ivhd_type;
c1cbebeec   Joerg Roedel   x86, AMD IOMMU: d...
150

b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
151
152
  u16 amd_iommu_last_bdf;			/* largest PCI device id we have
  					   to handle */
2e22847fb   Joerg Roedel   x86, AMD IOMMU: d...
153
  LIST_HEAD(amd_iommu_unity_map);		/* a list of required unity mappings
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
154
  					   we find in ACPI */
621a5f7ad   Viresh Kumar   debugfs: Pass boo...
155
  bool amd_iommu_unmap_flush;		/* if true, flush on every unmap */
928abd254   Joerg Roedel   x86, AMD IOMMU: a...
156

2e22847fb   Joerg Roedel   x86, AMD IOMMU: d...
157
  LIST_HEAD(amd_iommu_list);		/* list of all AMD IOMMUs in the
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
158
  					   system */
928abd254   Joerg Roedel   x86, AMD IOMMU: a...
159

bb52777ec   Joerg Roedel   x86/amd-iommu: Ad...
160
161
162
  /* Array to assign indices to IOMMUs*/
  struct amd_iommu *amd_iommus[MAX_IOMMUS];
  int amd_iommus_present;
318afd41d   Joerg Roedel   x86/amd-iommu: Ma...
163
164
  /* IOMMUs have a non-present cache? */
  bool amd_iommu_np_cache __read_mostly;
60f723b41   Joerg Roedel   x86/amd-iommu: Ad...
165
  bool amd_iommu_iotlb_sup __read_mostly = true;
318afd41d   Joerg Roedel   x86/amd-iommu: Ma...
166

a919a018c   Suravee Suthikulpanit   iommu/amd: Fix lo...
167
  u32 amd_iommu_max_pasid __read_mostly = ~0;
62f71abbc   Joerg Roedel   iommu/amd: Get th...
168

400a28a05   Joerg Roedel   iommu/amd: Add io...
169
  bool amd_iommu_v2_present __read_mostly;
4160cd9e5   Joerg Roedel   iommu/amd: Make a...
170
  static bool amd_iommu_pc_present __read_mostly;
400a28a05   Joerg Roedel   iommu/amd: Add io...
171

5abcdba4f   Joerg Roedel   iommu/amd: Put IO...
172
  bool amd_iommu_force_isolation __read_mostly;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
173
  /*
aeb26f553   Joerg Roedel   x86/amd-iommu: Im...
174
175
176
177
178
179
   * List of protection domains - used during resume
   */
  LIST_HEAD(amd_iommu_pd_list);
  spinlock_t amd_iommu_pd_lock;
  
  /*
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
180
181
182
183
184
   * Pointer to the device table which is shared by all AMD IOMMUs
   * it is indexed by the PCI device id or the HT unit id and contains
   * information about the domain the device belongs to as well as the
   * page table root pointer.
   */
928abd254   Joerg Roedel   x86, AMD IOMMU: a...
185
  struct dev_table_entry *amd_iommu_dev_table;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
186
187
188
189
190
191
  
  /*
   * The alias table is a driver specific data structure which contains the
   * mappings of the PCI device ids to the actual requestor ids on the IOMMU.
   * More than one device can share the same requestor id.
   */
928abd254   Joerg Roedel   x86, AMD IOMMU: a...
192
  u16 *amd_iommu_alias_table;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
193
194
195
196
197
  
  /*
   * The rlookup table is used to find the IOMMU which is responsible
   * for a specific device. It is also indexed by the PCI device id.
   */
928abd254   Joerg Roedel   x86, AMD IOMMU: a...
198
  struct amd_iommu **amd_iommu_rlookup_table;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
199
200
  
  /*
0ea2c422b   Joerg Roedel   iommu/amd: Alloca...
201
202
203
204
205
206
   * This table is used to find the irq remapping table for a given device id
   * quickly.
   */
  struct irq_remap_table **irq_lookup_table;
  
  /*
df805abb2   Frank Arnold   iommu/amd: Fix so...
207
   * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
208
209
   * to know which ones are already in use.
   */
928abd254   Joerg Roedel   x86, AMD IOMMU: a...
210
  unsigned long *amd_iommu_pd_alloc_bitmap;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
211
212
213
  static u32 dev_table_size;	/* size of the device table */
  static u32 alias_table_size;	/* size of the alias table */
  static u32 rlookup_table_size;	/* size if the rlookup table */
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
214

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
215
216
217
218
219
220
221
222
223
224
225
226
  enum iommu_init_state {
  	IOMMU_START_STATE,
  	IOMMU_IVRS_DETECTED,
  	IOMMU_ACPI_FINISHED,
  	IOMMU_ENABLED,
  	IOMMU_PCI_INIT,
  	IOMMU_INTERRUPTS_EN,
  	IOMMU_DMA_OPS,
  	IOMMU_INITIALIZED,
  	IOMMU_NOT_FOUND,
  	IOMMU_INIT_ERROR,
  };
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
227
228
229
230
  /* Early ioapic and hpet maps from kernel command line */
  #define EARLY_MAP_SIZE		4
  static struct devid_map __initdata early_ioapic_map[EARLY_MAP_SIZE];
  static struct devid_map __initdata early_hpet_map[EARLY_MAP_SIZE];
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
231
  static struct acpihid_map_entry __initdata early_acpihid_map[EARLY_MAP_SIZE];
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
232
233
  static int __initdata early_ioapic_map_size;
  static int __initdata early_hpet_map_size;
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
234
  static int __initdata early_acpihid_map_size;
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
235
  static bool __initdata cmdline_maps;
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
236

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
237
  static enum iommu_init_state init_state = IOMMU_START_STATE;
ae295142d   Gerard Snitselaar   iommu/amd: Fix se...
238
  static int amd_iommu_enable_interrupts(void);
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
239
  static int __init iommu_go_to_state(enum iommu_init_state state);
aafd8ba0c   Joerg Roedel   iommu/amd: Implem...
240
  static void init_device_table_dma(void);
3d9761e7a   Joerg Roedel   iommu/amd: Move i...
241

38e45d02e   Suravee Suthikulpanit   iommu/amd: Fix bo...
242
243
244
  static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
  				    u8 bank, u8 cntr, u8 fxn,
  				    u64 *value, bool is_write);
208ec8c94   Joerg Roedel   x86, AMD IOMMU: r...
245
246
247
248
249
  static inline void update_last_devid(u16 devid)
  {
  	if (devid > amd_iommu_last_bdf)
  		amd_iommu_last_bdf = devid;
  }
c571484e5   Joerg Roedel   x86, AMD IOMMU: r...
250
251
252
  static inline unsigned long tbl_size(int entry_size)
  {
  	unsigned shift = PAGE_SHIFT +
421f909c8   Neil Turton   amd-iommu: fix an...
253
  			 get_order(((int)amd_iommu_last_bdf + 1) * entry_size);
c571484e5   Joerg Roedel   x86, AMD IOMMU: r...
254
255
256
  
  	return 1UL << shift;
  }
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  /* Access to l1 and l2 indexed register spaces */
  
  static u32 iommu_read_l1(struct amd_iommu *iommu, u16 l1, u8 address)
  {
  	u32 val;
  
  	pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16));
  	pci_read_config_dword(iommu->dev, 0xfc, &val);
  	return val;
  }
  
  static void iommu_write_l1(struct amd_iommu *iommu, u16 l1, u8 address, u32 val)
  {
  	pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16 | 1 << 31));
  	pci_write_config_dword(iommu->dev, 0xfc, val);
  	pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16));
  }
  
  static u32 iommu_read_l2(struct amd_iommu *iommu, u8 address)
  {
  	u32 val;
  
  	pci_write_config_dword(iommu->dev, 0xf0, address);
  	pci_read_config_dword(iommu->dev, 0xf4, &val);
  	return val;
  }
  
  static void iommu_write_l2(struct amd_iommu *iommu, u8 address, u32 val)
  {
  	pci_write_config_dword(iommu->dev, 0xf0, (address | 1 << 8));
  	pci_write_config_dword(iommu->dev, 0xf4, val);
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
289
290
291
292
293
294
295
296
  /****************************************************************************
   *
   * AMD IOMMU MMIO register space handling functions
   *
   * These functions are used to program the IOMMU device registers in
   * MMIO space required for that driver.
   *
   ****************************************************************************/
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
297

b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
298
299
300
301
  /*
   * This function set the exclusion range in the IOMMU. DMA accesses to the
   * exclusion range are passed through untranslated
   */
05f92db9f   Joerg Roedel   amd_iommu: un __i...
302
  static void iommu_set_exclusion_range(struct amd_iommu *iommu)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  {
  	u64 start = iommu->exclusion_start & PAGE_MASK;
  	u64 limit = (start + iommu->exclusion_length) & PAGE_MASK;
  	u64 entry;
  
  	if (!iommu->exclusion_start)
  		return;
  
  	entry = start | MMIO_EXCL_ENABLE_MASK;
  	memcpy_toio(iommu->mmio_base + MMIO_EXCL_BASE_OFFSET,
  			&entry, sizeof(entry));
  
  	entry = limit;
  	memcpy_toio(iommu->mmio_base + MMIO_EXCL_LIMIT_OFFSET,
  			&entry, sizeof(entry));
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
319
  /* Programs the physical address of the device table into the IOMMU hardware */
6b7f000eb   Jan Beulich   x86/amd: iommu_se...
320
  static void iommu_set_device_table(struct amd_iommu *iommu)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
321
  {
f609891f4   Andreas Herrmann   amd_iommu: fix na...
322
  	u64 entry;
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
323
324
325
326
327
328
329
330
  
  	BUG_ON(iommu->mmio_base == NULL);
  
  	entry = virt_to_phys(amd_iommu_dev_table);
  	entry |= (dev_table_size >> 12) - 1;
  	memcpy_toio(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET,
  			&entry, sizeof(entry));
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
331
  /* Generic functions to enable/disable certain features of the IOMMU. */
05f92db9f   Joerg Roedel   amd_iommu: un __i...
332
  static void iommu_feature_enable(struct amd_iommu *iommu, u8 bit)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
333
334
335
336
337
338
339
  {
  	u32 ctrl;
  
  	ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
  	ctrl |= (1 << bit);
  	writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET);
  }
ca0207114   Joerg Roedel   x86/amd-iommu: Un...
340
  static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
341
342
  {
  	u32 ctrl;
199d0d501   Joerg Roedel   AMD IOMMU: remove...
343
  	ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
344
345
346
  	ctrl &= ~(1 << bit);
  	writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET);
  }
1456e9d2c   Joerg Roedel   iommu/amd: Set IO...
347
348
349
350
351
352
353
354
355
  static void iommu_set_inv_tlb_timeout(struct amd_iommu *iommu, int timeout)
  {
  	u32 ctrl;
  
  	ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
  	ctrl &= ~CTRL_INV_TO_MASK;
  	ctrl |= (timeout << CONTROL_INV_TIMEOUT) & CTRL_INV_TO_MASK;
  	writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET);
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
356
  /* Function to enable the hardware */
05f92db9f   Joerg Roedel   amd_iommu: un __i...
357
  static void iommu_enable(struct amd_iommu *iommu)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
358
  {
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
359
  	iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
360
  }
92ac4320a   Joerg Roedel   amd-iommu: add fu...
361
  static void iommu_disable(struct amd_iommu *iommu)
126c52be4   Joerg Roedel   AMD IOMMU: enable...
362
  {
a8c485bb6   Chris Wright   amd-iommu: disabl...
363
364
365
366
367
368
  	/* Disable command buffer */
  	iommu_feature_disable(iommu, CONTROL_CMDBUF_EN);
  
  	/* Disable event logging and event interrupts */
  	iommu_feature_disable(iommu, CONTROL_EVT_INT_EN);
  	iommu_feature_disable(iommu, CONTROL_EVT_LOG_EN);
8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
369
370
371
  	/* Disable IOMMU GA_LOG */
  	iommu_feature_disable(iommu, CONTROL_GALOG_EN);
  	iommu_feature_disable(iommu, CONTROL_GAINT_EN);
a8c485bb6   Chris Wright   amd-iommu: disabl...
372
  	/* Disable IOMMU hardware itself */
92ac4320a   Joerg Roedel   amd-iommu: add fu...
373
  	iommu_feature_disable(iommu, CONTROL_IOMMU_EN);
126c52be4   Joerg Roedel   AMD IOMMU: enable...
374
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
375
376
377
378
  /*
   * mapping and unmapping functions for the IOMMU MMIO space. Each AMD IOMMU in
   * the system has one.
   */
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
379
  static u8 __iomem * __init iommu_map_mmio_space(u64 address, u64 end)
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
380
  {
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
381
382
383
384
  	if (!request_mem_region(address, end, "amd_iommu")) {
  		pr_err("AMD-Vi: Can not reserve memory region %llx-%llx for mmio
  ",
  			address, end);
e82752d8b   Joerg Roedel   x86/amd-iommu: Fi...
385
386
  		pr_err("AMD-Vi: This is a BIOS bug. Please contact your hardware vendor
  ");
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
387
  		return NULL;
e82752d8b   Joerg Roedel   x86/amd-iommu: Fi...
388
  	}
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
389

30861ddc9   Steven L Kinney   perf/x86/amd: Add...
390
  	return (u8 __iomem *)ioremap_nocache(address, end);
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
391
392
393
394
395
396
  }
  
  static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu)
  {
  	if (iommu->mmio_base)
  		iounmap(iommu->mmio_base);
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
397
  	release_mem_region(iommu->mmio_phys, iommu->mmio_phys_end);
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
398
  }
ac7ccf676   Suravee Suthikulpanit   iommu/amd: Modify...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
  static inline u32 get_ivhd_header_size(struct ivhd_header *h)
  {
  	u32 size = 0;
  
  	switch (h->type) {
  	case 0x10:
  		size = 24;
  		break;
  	case 0x11:
  	case 0x40:
  		size = 40;
  		break;
  	}
  	return size;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
414
415
416
417
418
419
420
421
422
423
  /****************************************************************************
   *
   * The functions below belong to the first pass of AMD IOMMU ACPI table
   * parsing. In this pass we try to find out the highest device id this
   * code has to handle. Upon this information the size of the shared data
   * structures is determined later.
   *
   ****************************************************************************/
  
  /*
b514e5556   Joerg Roedel   AMD IOMMU: calcul...
424
425
426
427
   * This function calculates the length of a given IVHD entry
   */
  static inline int ivhd_entry_length(u8 *ivhd)
  {
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
428
429
430
431
432
433
434
435
436
  	u32 type = ((struct ivhd_entry *)ivhd)->type;
  
  	if (type < 0x80) {
  		return 0x04 << (*ivhd >> 6);
  	} else if (type == IVHD_DEV_ACPI_HID) {
  		/* For ACPI_HID, offset 21 is uid len */
  		return *((u8 *)ivhd + 21) + 22;
  	}
  	return 0;
b514e5556   Joerg Roedel   AMD IOMMU: calcul...
437
438
439
  }
  
  /*
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
440
441
442
   * After reading the highest device id from the IOMMU PCI capability header
   * this function looks if there is a higher device id defined in the ACPI table
   */
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
443
444
445
446
  static int __init find_last_devid_from_ivhd(struct ivhd_header *h)
  {
  	u8 *p = (void *)h, *end = (void *)h;
  	struct ivhd_entry *dev;
ac7ccf676   Suravee Suthikulpanit   iommu/amd: Modify...
447
448
449
450
451
452
453
454
455
  	u32 ivhd_size = get_ivhd_header_size(h);
  
  	if (!ivhd_size) {
  		pr_err("AMD-Vi: Unsupported IVHD type %#x
  ", h->type);
  		return -EINVAL;
  	}
  
  	p += ivhd_size;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
456
  	end += h->length;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
457
458
459
  	while (p < end) {
  		dev = (struct ivhd_entry *)p;
  		switch (dev->type) {
d12594169   Joerg Roedel   iommu/amd: Initia...
460
461
462
463
  		case IVHD_DEV_ALL:
  			/* Use maximum BDF value for DEV_ALL */
  			update_last_devid(0xffff);
  			break;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
464
465
466
467
  		case IVHD_DEV_SELECT:
  		case IVHD_DEV_RANGE_END:
  		case IVHD_DEV_ALIAS:
  		case IVHD_DEV_EXT_SELECT:
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
468
  			/* all the above subfield types refer to device ids */
208ec8c94   Joerg Roedel   x86, AMD IOMMU: r...
469
  			update_last_devid(dev->devid);
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
470
471
472
473
  			break;
  		default:
  			break;
  		}
b514e5556   Joerg Roedel   AMD IOMMU: calcul...
474
  		p += ivhd_entry_length(p);
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
475
476
477
478
479
480
  	}
  
  	WARN_ON(p != end);
  
  	return 0;
  }
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  static int __init check_ivrs_checksum(struct acpi_table_header *table)
  {
  	int i;
  	u8 checksum = 0, *p = (u8 *)table;
  
  	for (i = 0; i < table->length; ++i)
  		checksum += p[i];
  	if (checksum != 0) {
  		/* ACPI table corrupt */
  		pr_err(FW_BUG "AMD-Vi: IVRS invalid checksum
  ");
  		return -ENODEV;
  	}
  
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
497
498
499
500
501
  /*
   * Iterate over all IVHD entries in the ACPI table and find the highest device
   * id which we need to handle. This is the first of three functions which parse
   * the ACPI table. So we check the checksum here.
   */
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
502
503
  static int __init find_last_devid_acpi(struct acpi_table_header *table)
  {
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
504
  	u8 *p = (u8 *)table, *end = (u8 *)table;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
505
  	struct ivhd_header *h;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
506
507
508
509
510
  	p += IVRS_HEADER_LENGTH;
  
  	end += table->length;
  	while (p < end) {
  		h = (struct ivhd_header *)p;
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
511
512
513
514
515
  		if (h->type == amd_iommu_target_ivhd_type) {
  			int ret = find_last_devid_from_ivhd(h);
  
  			if (ret)
  				return ret;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
516
517
518
519
520
521
522
  		}
  		p += h->length;
  	}
  	WARN_ON(p != end);
  
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
523
524
  /****************************************************************************
   *
df805abb2   Frank Arnold   iommu/amd: Fix so...
525
   * The following functions belong to the code path which parses the ACPI table
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
526
527
528
529
530
531
532
533
534
535
536
   * the second time. In this ACPI parsing iteration we allocate IOMMU specific
   * data structures, initialize the device/alias/rlookup table and also
   * basically initialize the hardware.
   *
   ****************************************************************************/
  
  /*
   * Allocates the command buffer. This buffer is per AMD IOMMU. We can
   * write commands to that buffer later and the IOMMU will execute them
   * asynchronously
   */
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
537
  static int __init alloc_command_buffer(struct amd_iommu *iommu)
b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
538
  {
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
539
540
  	iommu->cmd_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
  						  get_order(CMD_BUFFER_SIZE));
b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
541

f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
542
  	return iommu->cmd_buf ? 0 : -ENOMEM;
58492e128   Joerg Roedel   amd-iommu: consol...
543
544
545
  }
  
  /*
93f1cc67c   Joerg Roedel   x86/amd-iommu: Ad...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
   * This function resets the command buffer if the IOMMU stopped fetching
   * commands from it.
   */
  void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu)
  {
  	iommu_feature_disable(iommu, CONTROL_CMDBUF_EN);
  
  	writel(0x00, iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
  	writel(0x00, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
  
  	iommu_feature_enable(iommu, CONTROL_CMDBUF_EN);
  }
  
  /*
58492e128   Joerg Roedel   amd-iommu: consol...
560
561
562
563
564
565
566
567
568
569
   * This function writes the command buffer address to the hardware and
   * enables it.
   */
  static void iommu_enable_command_buffer(struct amd_iommu *iommu)
  {
  	u64 entry;
  
  	BUG_ON(iommu->cmd_buf == NULL);
  
  	entry = (u64)virt_to_phys(iommu->cmd_buf);
b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
570
  	entry |= MMIO_CMD_SIZE_512;
58492e128   Joerg Roedel   amd-iommu: consol...
571

b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
572
  	memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET,
58492e128   Joerg Roedel   amd-iommu: consol...
573
  		    &entry, sizeof(entry));
b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
574

93f1cc67c   Joerg Roedel   x86/amd-iommu: Ad...
575
  	amd_iommu_reset_cmd_buffer(iommu);
b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
576
577
578
579
  }
  
  static void __init free_command_buffer(struct amd_iommu *iommu)
  {
deba4bce1   Joerg Roedel   iommu/amd: Remove...
580
  	free_pages((unsigned long)iommu->cmd_buf, get_order(CMD_BUFFER_SIZE));
b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
581
  }
335503e57   Joerg Roedel   AMD IOMMU: add ev...
582
  /* allocates the memory where the IOMMU will log its events to */
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
583
  static int __init alloc_event_buffer(struct amd_iommu *iommu)
335503e57   Joerg Roedel   AMD IOMMU: add ev...
584
  {
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
585
586
  	iommu->evt_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
  						  get_order(EVT_BUFFER_SIZE));
335503e57   Joerg Roedel   AMD IOMMU: add ev...
587

f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
588
  	return iommu->evt_buf ? 0 : -ENOMEM;
58492e128   Joerg Roedel   amd-iommu: consol...
589
590
591
592
593
594
595
  }
  
  static void iommu_enable_event_buffer(struct amd_iommu *iommu)
  {
  	u64 entry;
  
  	BUG_ON(iommu->evt_buf == NULL);
335503e57   Joerg Roedel   AMD IOMMU: add ev...
596
  	entry = (u64)virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK;
58492e128   Joerg Roedel   amd-iommu: consol...
597

335503e57   Joerg Roedel   AMD IOMMU: add ev...
598
599
  	memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
  		    &entry, sizeof(entry));
09067207f   Joerg Roedel   amd-iommu: set ev...
600
601
602
  	/* set head and tail to zero manually */
  	writel(0x00, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
  	writel(0x00, iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
58492e128   Joerg Roedel   amd-iommu: consol...
603
  	iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
335503e57   Joerg Roedel   AMD IOMMU: add ev...
604
605
606
607
608
609
  }
  
  static void __init free_event_buffer(struct amd_iommu *iommu)
  {
  	free_pages((unsigned long)iommu->evt_buf, get_order(EVT_BUFFER_SIZE));
  }
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
610
  /* allocates the memory where the IOMMU will log its events to */
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
611
  static int __init alloc_ppr_log(struct amd_iommu *iommu)
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
612
  {
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
613
614
  	iommu->ppr_log = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
  						  get_order(PPR_LOG_SIZE));
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
615

f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
616
  	return iommu->ppr_log ? 0 : -ENOMEM;
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
  }
  
  static void iommu_enable_ppr_log(struct amd_iommu *iommu)
  {
  	u64 entry;
  
  	if (iommu->ppr_log == NULL)
  		return;
  
  	entry = (u64)virt_to_phys(iommu->ppr_log) | PPR_LOG_SIZE_512;
  
  	memcpy_toio(iommu->mmio_base + MMIO_PPR_LOG_OFFSET,
  		    &entry, sizeof(entry));
  
  	/* set head and tail to zero manually */
  	writel(0x00, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
  	writel(0x00, iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);
  
  	iommu_feature_enable(iommu, CONTROL_PPFLOG_EN);
  	iommu_feature_enable(iommu, CONTROL_PPR_EN);
  }
  
  static void __init free_ppr_log(struct amd_iommu *iommu)
  {
  	if (iommu->ppr_log == NULL)
  		return;
  
  	free_pages((unsigned long)iommu->ppr_log, get_order(PPR_LOG_SIZE));
  }
8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  static void free_ga_log(struct amd_iommu *iommu)
  {
  #ifdef CONFIG_IRQ_REMAP
  	if (iommu->ga_log)
  		free_pages((unsigned long)iommu->ga_log,
  			    get_order(GA_LOG_SIZE));
  	if (iommu->ga_log_tail)
  		free_pages((unsigned long)iommu->ga_log_tail,
  			    get_order(8));
  #endif
  }
  
  static int iommu_ga_log_enable(struct amd_iommu *iommu)
  {
  #ifdef CONFIG_IRQ_REMAP
  	u32 status, i;
  
  	if (!iommu->ga_log)
  		return -EINVAL;
  
  	status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
  
  	/* Check if already running */
  	if (status & (MMIO_STATUS_GALOG_RUN_MASK))
  		return 0;
  
  	iommu_feature_enable(iommu, CONTROL_GAINT_EN);
  	iommu_feature_enable(iommu, CONTROL_GALOG_EN);
  
  	for (i = 0; i < LOOP_TIMEOUT; ++i) {
  		status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
  		if (status & (MMIO_STATUS_GALOG_RUN_MASK))
  			break;
  	}
  
  	if (i >= LOOP_TIMEOUT)
  		return -EINVAL;
  #endif /* CONFIG_IRQ_REMAP */
  	return 0;
  }
  
  #ifdef CONFIG_IRQ_REMAP
  static int iommu_init_ga_log(struct amd_iommu *iommu)
  {
  	u64 entry;
  
  	if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))
  		return 0;
  
  	iommu->ga_log = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
  					get_order(GA_LOG_SIZE));
  	if (!iommu->ga_log)
  		goto err_out;
  
  	iommu->ga_log_tail = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
  					get_order(8));
  	if (!iommu->ga_log_tail)
  		goto err_out;
  
  	entry = (u64)virt_to_phys(iommu->ga_log) | GA_LOG_SIZE_512;
  	memcpy_toio(iommu->mmio_base + MMIO_GA_LOG_BASE_OFFSET,
  		    &entry, sizeof(entry));
  	entry = ((u64)virt_to_phys(iommu->ga_log) & 0xFFFFFFFFFFFFFULL) & ~7ULL;
  	memcpy_toio(iommu->mmio_base + MMIO_GA_LOG_TAIL_OFFSET,
  		    &entry, sizeof(entry));
  	writel(0x00, iommu->mmio_base + MMIO_GA_HEAD_OFFSET);
  	writel(0x00, iommu->mmio_base + MMIO_GA_TAIL_OFFSET);
  
  	return 0;
  err_out:
  	free_ga_log(iommu);
  	return -EINVAL;
  }
  #endif /* CONFIG_IRQ_REMAP */
  
  static int iommu_init_ga(struct amd_iommu *iommu)
  {
  	int ret = 0;
  
  #ifdef CONFIG_IRQ_REMAP
  	/* Note: We have already checked GASup from IVRS table.
  	 *       Now, we need to make sure that GAMSup is set.
  	 */
  	if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) &&
  	    !iommu_feature(iommu, FEATURE_GAM_VAPIC))
  		amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY_GA;
  
  	ret = iommu_init_ga_log(iommu);
  #endif /* CONFIG_IRQ_REMAP */
  
  	return ret;
  }
cbc33a908   Joerg Roedel   iommu/amd: Enable...
738
739
740
741
742
743
744
  static void iommu_enable_gt(struct amd_iommu *iommu)
  {
  	if (!iommu_feature(iommu, FEATURE_GT))
  		return;
  
  	iommu_feature_enable(iommu, CONTROL_GT_EN);
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
745
  /* sets a specific bit in the device table entry. */
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
746
747
  static void set_dev_entry_bit(u16 devid, u8 bit)
  {
ee6c28684   Joerg Roedel   iommu/amd: Conver...
748
749
  	int i = (bit >> 6) & 0x03;
  	int _bit = bit & 0x3f;
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
750

ee6c28684   Joerg Roedel   iommu/amd: Conver...
751
  	amd_iommu_dev_table[devid].data[i] |= (1UL << _bit);
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
752
  }
c5cca146a   Joerg Roedel   x86/amd-iommu: Wo...
753
754
  static int get_dev_entry_bit(u16 devid, u8 bit)
  {
ee6c28684   Joerg Roedel   iommu/amd: Conver...
755
756
  	int i = (bit >> 6) & 0x03;
  	int _bit = bit & 0x3f;
c5cca146a   Joerg Roedel   x86/amd-iommu: Wo...
757

ee6c28684   Joerg Roedel   iommu/amd: Conver...
758
  	return (amd_iommu_dev_table[devid].data[i] & (1UL << _bit)) >> _bit;
c5cca146a   Joerg Roedel   x86/amd-iommu: Wo...
759
760
761
762
763
764
765
766
767
768
769
770
771
  }
  
  
  void amd_iommu_apply_erratum_63(u16 devid)
  {
  	int sysmgt;
  
  	sysmgt = get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1) |
  		 (get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2) << 1);
  
  	if (sysmgt == 0x01)
  		set_dev_entry_bit(devid, DEV_ENTRY_IW);
  }
5ff4789d0   Joerg Roedel   AMD IOMMU: set io...
772
773
774
775
776
  /* Writes the specific IOMMU for a device into the rlookup table */
  static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid)
  {
  	amd_iommu_rlookup_table[devid] = iommu;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
777
778
779
780
  /*
   * This function takes the device specific flags read from the ACPI
   * table and sets up the device table entry with that information
   */
5ff4789d0   Joerg Roedel   AMD IOMMU: set io...
781
782
  static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu,
  					   u16 devid, u32 flags, u32 ext_flags)
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
  {
  	if (flags & ACPI_DEVFLAG_INITPASS)
  		set_dev_entry_bit(devid, DEV_ENTRY_INIT_PASS);
  	if (flags & ACPI_DEVFLAG_EXTINT)
  		set_dev_entry_bit(devid, DEV_ENTRY_EINT_PASS);
  	if (flags & ACPI_DEVFLAG_NMI)
  		set_dev_entry_bit(devid, DEV_ENTRY_NMI_PASS);
  	if (flags & ACPI_DEVFLAG_SYSMGT1)
  		set_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1);
  	if (flags & ACPI_DEVFLAG_SYSMGT2)
  		set_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2);
  	if (flags & ACPI_DEVFLAG_LINT0)
  		set_dev_entry_bit(devid, DEV_ENTRY_LINT0_PASS);
  	if (flags & ACPI_DEVFLAG_LINT1)
  		set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS);
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
798

c5cca146a   Joerg Roedel   x86/amd-iommu: Wo...
799
  	amd_iommu_apply_erratum_63(devid);
5ff4789d0   Joerg Roedel   AMD IOMMU: set io...
800
  	set_iommu_for_device(iommu, devid);
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
801
  }
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
802
  static int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line)
6efed63be   Joerg Roedel   iommu/amd: Keep t...
803
804
805
  {
  	struct devid_map *entry;
  	struct list_head *list;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
806
807
808
809
810
  	if (type == IVHD_SPECIAL_IOAPIC)
  		list = &ioapic_map;
  	else if (type == IVHD_SPECIAL_HPET)
  		list = &hpet_map;
  	else
6efed63be   Joerg Roedel   iommu/amd: Keep t...
811
  		return -EINVAL;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
812
813
814
815
816
817
818
  	list_for_each_entry(entry, list, list) {
  		if (!(entry->id == id && entry->cmd_line))
  			continue;
  
  		pr_info("AMD-Vi: Command-line override present for %s id %d - ignoring
  ",
  			type == IVHD_SPECIAL_IOAPIC ? "IOAPIC" : "HPET", id);
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
819
  		*devid = entry->devid;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
820
821
  		return 0;
  	}
6efed63be   Joerg Roedel   iommu/amd: Keep t...
822
823
824
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  	if (!entry)
  		return -ENOMEM;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
825
  	entry->id	= id;
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
826
  	entry->devid	= *devid;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
827
  	entry->cmd_line	= cmd_line;
6efed63be   Joerg Roedel   iommu/amd: Keep t...
828
829
830
831
832
  
  	list_add_tail(&entry->list, list);
  
  	return 0;
  }
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
  static int __init add_acpi_hid_device(u8 *hid, u8 *uid, u16 *devid,
  				      bool cmd_line)
  {
  	struct acpihid_map_entry *entry;
  	struct list_head *list = &acpihid_map;
  
  	list_for_each_entry(entry, list, list) {
  		if (strcmp(entry->hid, hid) ||
  		    (*uid && *entry->uid && strcmp(entry->uid, uid)) ||
  		    !entry->cmd_line)
  			continue;
  
  		pr_info("AMD-Vi: Command-line override for hid:%s uid:%s
  ",
  			hid, uid);
  		*devid = entry->devid;
  		return 0;
  	}
  
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  	if (!entry)
  		return -ENOMEM;
  
  	memcpy(entry->uid, uid, strlen(uid));
  	memcpy(entry->hid, hid, strlen(hid));
  	entry->devid = *devid;
  	entry->cmd_line	= cmd_line;
  	entry->root_devid = (entry->devid & (~0x7));
  
  	pr_info("AMD-Vi:%s, add hid:%s, uid:%s, rdevid:%d
  ",
  		entry->cmd_line ? "cmd" : "ivrs",
  		entry->hid, entry->uid, entry->root_devid);
  
  	list_add_tail(&entry->list, list);
  	return 0;
  }
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
870
871
872
873
874
875
876
  static int __init add_early_maps(void)
  {
  	int i, ret;
  
  	for (i = 0; i < early_ioapic_map_size; ++i) {
  		ret = add_special_device(IVHD_SPECIAL_IOAPIC,
  					 early_ioapic_map[i].id,
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
877
  					 &early_ioapic_map[i].devid,
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
878
879
880
881
882
883
884
885
  					 early_ioapic_map[i].cmd_line);
  		if (ret)
  			return ret;
  	}
  
  	for (i = 0; i < early_hpet_map_size; ++i) {
  		ret = add_special_device(IVHD_SPECIAL_HPET,
  					 early_hpet_map[i].id,
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
886
  					 &early_hpet_map[i].devid,
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
887
888
889
890
  					 early_hpet_map[i].cmd_line);
  		if (ret)
  			return ret;
  	}
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
891
892
893
894
895
896
897
898
  	for (i = 0; i < early_acpihid_map_size; ++i) {
  		ret = add_acpi_hid_device(early_acpihid_map[i].hid,
  					  early_acpihid_map[i].uid,
  					  &early_acpihid_map[i].devid,
  					  early_acpihid_map[i].cmd_line);
  		if (ret)
  			return ret;
  	}
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
899
900
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
901
  /*
df805abb2   Frank Arnold   iommu/amd: Fix so...
902
   * Reads the device exclusion range from ACPI and initializes the IOMMU with
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
903
904
   * it
   */
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
905
906
907
908
909
910
911
912
  static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m)
  {
  	struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
  
  	if (!(m->flags & IVMD_FLAG_EXCL_RANGE))
  		return;
  
  	if (iommu) {
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
913
914
915
916
917
  		/*
  		 * We only can configure exclusion ranges per IOMMU, not
  		 * per device. But we can enable the exclusion range per
  		 * device. This is done here
  		 */
2c16c9fda   Su Friendy   iommu/amd: fix en...
918
  		set_dev_entry_bit(devid, DEV_ENTRY_EX);
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
919
920
921
922
  		iommu->exclusion_start = m->range_start;
  		iommu->exclusion_length = m->range_length;
  	}
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
923
  /*
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
924
925
926
   * Takes a pointer to an AMD IOMMU entry in the ACPI table and
   * initializes the hardware and our data structures with it.
   */
6efed63be   Joerg Roedel   iommu/amd: Keep t...
927
  static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
928
929
930
931
  					struct ivhd_header *h)
  {
  	u8 *p = (u8 *)h;
  	u8 *end = p, flags = 0;
0de66d5b3   Joerg Roedel   x86/amd-iommu: Fi...
932
933
  	u16 devid = 0, devid_start = 0, devid_to = 0;
  	u32 dev_i, ext_flags = 0;
58a3bee56   Joerg Roedel   x86, AMD IOMMU: u...
934
  	bool alias = false;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
935
  	struct ivhd_entry *e;
ac7ccf676   Suravee Suthikulpanit   iommu/amd: Modify...
936
  	u32 ivhd_size;
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
937
938
939
940
941
942
  	int ret;
  
  
  	ret = add_early_maps();
  	if (ret)
  		return ret;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
943
944
  
  	/*
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
945
  	 * First save the recommended feature enable bits from ACPI
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
946
  	 */
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
947
  	iommu->acpi_flags = h->flags;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
948
949
950
951
  
  	/*
  	 * Done. Now parse the device entries
  	 */
ac7ccf676   Suravee Suthikulpanit   iommu/amd: Modify...
952
953
954
955
956
957
958
959
  	ivhd_size = get_ivhd_header_size(h);
  	if (!ivhd_size) {
  		pr_err("AMD-Vi: Unsupported IVHD type %#x
  ", h->type);
  		return -EINVAL;
  	}
  
  	p += ivhd_size;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
960
  	end += h->length;
42a698f40   Joerg Roedel   amd-iommu: print ...
961

5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
962
963
964
965
  	while (p < end) {
  		e = (struct ivhd_entry *)p;
  		switch (e->type) {
  		case IVHD_DEV_ALL:
42a698f40   Joerg Roedel   amd-iommu: print ...
966

226e889b2   Joerg Roedel   iommu/amd: Remove...
967
968
  			DUMP_printk("  DEV_ALL\t\t\tflags: %02x
  ", e->flags);
42a698f40   Joerg Roedel   amd-iommu: print ...
969

226e889b2   Joerg Roedel   iommu/amd: Remove...
970
971
  			for (dev_i = 0; dev_i <= amd_iommu_last_bdf; ++dev_i)
  				set_dev_entry_from_acpi(iommu, dev_i, e->flags, 0);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
972
973
  			break;
  		case IVHD_DEV_SELECT:
42a698f40   Joerg Roedel   amd-iommu: print ...
974
975
976
977
  
  			DUMP_printk("  DEV_SELECT\t\t\t devid: %02x:%02x.%x "
  				    "flags: %02x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
978
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
979
980
981
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
982
  			devid = e->devid;
5ff4789d0   Joerg Roedel   AMD IOMMU: set io...
983
  			set_dev_entry_from_acpi(iommu, devid, e->flags, 0);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
984
985
  			break;
  		case IVHD_DEV_SELECT_RANGE_START:
42a698f40   Joerg Roedel   amd-iommu: print ...
986
987
988
989
  
  			DUMP_printk("  DEV_SELECT_RANGE_START\t "
  				    "devid: %02x:%02x.%x flags: %02x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
990
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
991
992
993
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
994
995
996
  			devid_start = e->devid;
  			flags = e->flags;
  			ext_flags = 0;
58a3bee56   Joerg Roedel   x86, AMD IOMMU: u...
997
  			alias = false;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
998
999
  			break;
  		case IVHD_DEV_ALIAS:
42a698f40   Joerg Roedel   amd-iommu: print ...
1000
1001
1002
1003
  
  			DUMP_printk("  DEV_ALIAS\t\t\t devid: %02x:%02x.%x "
  				    "flags: %02x devid_to: %02x:%02x.%x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1004
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1005
1006
1007
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags,
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1008
  				    PCI_BUS_NUM(e->ext >> 8),
42a698f40   Joerg Roedel   amd-iommu: print ...
1009
1010
  				    PCI_SLOT(e->ext >> 8),
  				    PCI_FUNC(e->ext >> 8));
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1011
1012
  			devid = e->devid;
  			devid_to = e->ext >> 8;
7a6a3a086   Joerg Roedel   amd-iommu: handle...
1013
  			set_dev_entry_from_acpi(iommu, devid   , e->flags, 0);
7455aab1f   Neil Turton   amd-iommu: fix th...
1014
  			set_dev_entry_from_acpi(iommu, devid_to, e->flags, 0);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1015
1016
1017
  			amd_iommu_alias_table[devid] = devid_to;
  			break;
  		case IVHD_DEV_ALIAS_RANGE:
42a698f40   Joerg Roedel   amd-iommu: print ...
1018
1019
1020
1021
1022
  
  			DUMP_printk("  DEV_ALIAS_RANGE\t\t "
  				    "devid: %02x:%02x.%x flags: %02x "
  				    "devid_to: %02x:%02x.%x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1023
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1024
1025
1026
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags,
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1027
  				    PCI_BUS_NUM(e->ext >> 8),
42a698f40   Joerg Roedel   amd-iommu: print ...
1028
1029
  				    PCI_SLOT(e->ext >> 8),
  				    PCI_FUNC(e->ext >> 8));
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1030
1031
1032
1033
  			devid_start = e->devid;
  			flags = e->flags;
  			devid_to = e->ext >> 8;
  			ext_flags = 0;
58a3bee56   Joerg Roedel   x86, AMD IOMMU: u...
1034
  			alias = true;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1035
1036
  			break;
  		case IVHD_DEV_EXT_SELECT:
42a698f40   Joerg Roedel   amd-iommu: print ...
1037
1038
1039
1040
  
  			DUMP_printk("  DEV_EXT_SELECT\t\t devid: %02x:%02x.%x "
  				    "flags: %02x ext: %08x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1041
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1042
1043
1044
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags, e->ext);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1045
  			devid = e->devid;
5ff4789d0   Joerg Roedel   AMD IOMMU: set io...
1046
1047
  			set_dev_entry_from_acpi(iommu, devid, e->flags,
  						e->ext);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1048
1049
  			break;
  		case IVHD_DEV_EXT_SELECT_RANGE:
42a698f40   Joerg Roedel   amd-iommu: print ...
1050
1051
1052
1053
  
  			DUMP_printk("  DEV_EXT_SELECT_RANGE\t devid: "
  				    "%02x:%02x.%x flags: %02x ext: %08x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1054
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1055
1056
1057
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags, e->ext);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1058
1059
1060
  			devid_start = e->devid;
  			flags = e->flags;
  			ext_flags = e->ext;
58a3bee56   Joerg Roedel   x86, AMD IOMMU: u...
1061
  			alias = false;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1062
1063
  			break;
  		case IVHD_DEV_RANGE_END:
42a698f40   Joerg Roedel   amd-iommu: print ...
1064
1065
1066
  
  			DUMP_printk("  DEV_RANGE_END\t\t devid: %02x:%02x.%x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1067
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1068
1069
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid));
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1070
1071
  			devid = e->devid;
  			for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
7a6a3a086   Joerg Roedel   amd-iommu: handle...
1072
  				if (alias) {
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1073
  					amd_iommu_alias_table[dev_i] = devid_to;
7a6a3a086   Joerg Roedel   amd-iommu: handle...
1074
1075
1076
1077
1078
  					set_dev_entry_from_acpi(iommu,
  						devid_to, flags, ext_flags);
  				}
  				set_dev_entry_from_acpi(iommu, dev_i,
  							flags, ext_flags);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1079
1080
  			}
  			break;
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  		case IVHD_DEV_SPECIAL: {
  			u8 handle, type;
  			const char *var;
  			u16 devid;
  			int ret;
  
  			handle = e->ext & 0xff;
  			devid  = (e->ext >>  8) & 0xffff;
  			type   = (e->ext >> 24) & 0xff;
  
  			if (type == IVHD_SPECIAL_IOAPIC)
  				var = "IOAPIC";
  			else if (type == IVHD_SPECIAL_HPET)
  				var = "HPET";
  			else
  				var = "UNKNOWN";
  
  			DUMP_printk("  DEV_SPECIAL(%s[%d])\t\tdevid: %02x:%02x.%x
  ",
  				    var, (int)handle,
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1101
  				    PCI_BUS_NUM(devid),
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1102
1103
  				    PCI_SLOT(devid),
  				    PCI_FUNC(devid));
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
1104
  			ret = add_special_device(type, handle, &devid, false);
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1105
1106
  			if (ret)
  				return ret;
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
1107
1108
1109
1110
1111
1112
1113
  
  			/*
  			 * add_special_device might update the devid in case a
  			 * command-line override is present. So call
  			 * set_dev_entry_from_acpi after add_special_device.
  			 */
  			set_dev_entry_from_acpi(iommu, devid, e->flags, 0);
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1114
1115
  			break;
  		}
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  		case IVHD_DEV_ACPI_HID: {
  			u16 devid;
  			u8 hid[ACPIHID_HID_LEN] = {0};
  			u8 uid[ACPIHID_UID_LEN] = {0};
  			int ret;
  
  			if (h->type != 0x40) {
  				pr_err(FW_BUG "Invalid IVHD device type %#x
  ",
  				       e->type);
  				break;
  			}
  
  			memcpy(hid, (u8 *)(&e->ext), ACPIHID_HID_LEN - 1);
  			hid[ACPIHID_HID_LEN - 1] = '\0';
  
  			if (!(*hid)) {
  				pr_err(FW_BUG "Invalid HID.
  ");
  				break;
  			}
  
  			switch (e->uidf) {
  			case UID_NOT_PRESENT:
  
  				if (e->uidl != 0)
  					pr_warn(FW_BUG "Invalid UID length.
  ");
  
  				break;
  			case UID_IS_INTEGER:
  
  				sprintf(uid, "%d", e->uid);
  
  				break;
  			case UID_IS_CHARACTER:
  
  				memcpy(uid, (u8 *)(&e->uid), ACPIHID_UID_LEN - 1);
  				uid[ACPIHID_UID_LEN - 1] = '\0';
  
  				break;
  			default:
  				break;
  			}
6082ee72e   Nicolas Iooss   iommu/amd: Initia...
1160
  			devid = e->devid;
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
1161
1162
1163
1164
1165
1166
  			DUMP_printk("  DEV_ACPI_HID(%s[%s])\t\tdevid: %02x:%02x.%x
  ",
  				    hid, uid,
  				    PCI_BUS_NUM(devid),
  				    PCI_SLOT(devid),
  				    PCI_FUNC(devid));
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
  			flags = e->flags;
  
  			ret = add_acpi_hid_device(hid, uid, &devid, false);
  			if (ret)
  				return ret;
  
  			/*
  			 * add_special_device might update the devid in case a
  			 * command-line override is present. So call
  			 * set_dev_entry_from_acpi after add_special_device.
  			 */
  			set_dev_entry_from_acpi(iommu, devid, e->flags, 0);
  
  			break;
  		}
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1182
1183
1184
  		default:
  			break;
  		}
b514e5556   Joerg Roedel   AMD IOMMU: calcul...
1185
  		p += ivhd_entry_length(p);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1186
  	}
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1187
1188
  
  	return 0;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1189
  }
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1190
1191
1192
  static void __init free_iommu_one(struct amd_iommu *iommu)
  {
  	free_command_buffer(iommu);
335503e57   Joerg Roedel   AMD IOMMU: add ev...
1193
  	free_event_buffer(iommu);
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
1194
  	free_ppr_log(iommu);
8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
1195
  	free_ga_log(iommu);
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1196
1197
1198
1199
1200
1201
  	iommu_unmap_mmio_space(iommu);
  }
  
  static void __init free_iommu_all(void)
  {
  	struct amd_iommu *iommu, *next;
3bd221724   Joerg Roedel   amd-iommu: introd...
1202
  	for_each_iommu_safe(iommu, next) {
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1203
1204
1205
1206
1207
  		list_del(&iommu->list);
  		free_iommu_one(iommu);
  		kfree(iommu);
  	}
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1208
  /*
318fe7825   Suravee Suthikulpanit   IOMMU, AMD Family...
1209
1210
1211
1212
1213
   * Family15h Model 10h-1fh erratum 746 (IOMMU Logging May Stall Translations)
   * Workaround:
   *     BIOS should disable L2B micellaneous clock gating by setting
   *     L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b
   */
e2f1a3bd8   Nikola Pajkovsky   amd_iommu_init: r...
1214
  static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
318fe7825   Suravee Suthikulpanit   IOMMU, AMD Family...
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  {
  	u32 value;
  
  	if ((boot_cpu_data.x86 != 0x15) ||
  	    (boot_cpu_data.x86_model < 0x10) ||
  	    (boot_cpu_data.x86_model > 0x1f))
  		return;
  
  	pci_write_config_dword(iommu->dev, 0xf0, 0x90);
  	pci_read_config_dword(iommu->dev, 0xf4, &value);
  
  	if (value & BIT(2))
  		return;
  
  	/* Select NB indirect register 0x90 and enable writing */
  	pci_write_config_dword(iommu->dev, 0xf0, 0x90 | (1 << 8));
  
  	pci_write_config_dword(iommu->dev, 0xf4, value | 0x4);
  	pr_info("AMD-Vi: Applying erratum 746 workaround for IOMMU at %s
  ",
  		dev_name(&iommu->dev->dev));
  
  	/* Clear the enable writing bit */
  	pci_write_config_dword(iommu->dev, 0xf0, 0x90);
  }
  
  /*
358875fd5   Jay Cornwall   iommu/amd: Apply ...
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
   * Family15h Model 30h-3fh (IOMMU Mishandles ATS Write Permission)
   * Workaround:
   *     BIOS should enable ATS write permission check by setting
   *     L2_DEBUG_3[AtsIgnoreIWDis](D0F2xF4_x47[0]) = 1b
   */
  static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu)
  {
  	u32 value;
  
  	if ((boot_cpu_data.x86 != 0x15) ||
  	    (boot_cpu_data.x86_model < 0x30) ||
  	    (boot_cpu_data.x86_model > 0x3f))
  		return;
  
  	/* Test L2_DEBUG_3[AtsIgnoreIWDis] == 1 */
  	value = iommu_read_l2(iommu, 0x47);
  
  	if (value & BIT(0))
  		return;
  
  	/* Set L2_DEBUG_3[AtsIgnoreIWDis] = 1 */
  	iommu_write_l2(iommu, 0x47, value | BIT(0));
  
  	pr_info("AMD-Vi: Applying ATS write check workaround for IOMMU at %s
  ",
  		dev_name(&iommu->dev->dev));
  }
  
  /*
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1271
1272
1273
1274
   * This function clues the initialization function for one IOMMU
   * together and also allocates the command buffer and programs the
   * hardware. It does NOT enable the IOMMU. This is done afterwards.
   */
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1275
1276
  static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
  {
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1277
  	int ret;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1278
  	spin_lock_init(&iommu->lock);
bb52777ec   Joerg Roedel   x86/amd-iommu: Ad...
1279
1280
  
  	/* Add IOMMU to internal data structures */
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1281
  	list_add_tail(&iommu->list, &amd_iommu_list);
bb52777ec   Joerg Roedel   x86/amd-iommu: Ad...
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  	iommu->index             = amd_iommus_present++;
  
  	if (unlikely(iommu->index >= MAX_IOMMUS)) {
  		WARN(1, "AMD-Vi: System has more IOMMUs than supported by this driver
  ");
  		return -ENOSYS;
  	}
  
  	/* Index is fine - add IOMMU to the array */
  	amd_iommus[iommu->index] = iommu;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1292
1293
1294
1295
  
  	/*
  	 * Copy data from ACPI table entry to the iommu struct
  	 */
23c742db2   Joerg Roedel   iommu/amd: Split ...
1296
  	iommu->devid   = h->devid;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1297
  	iommu->cap_ptr = h->cap_ptr;
ee893c24e   Joerg Roedel   AMD IOMMU: save p...
1298
  	iommu->pci_seg = h->pci_seg;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1299
  	iommu->mmio_phys = h->mmio_phys;
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1300

7d7d38afb   Suravee Suthikulpanit   iommu/amd: Adding...
1301
1302
1303
1304
1305
1306
1307
1308
1309
  	switch (h->type) {
  	case 0x10:
  		/* Check if IVHD EFR contains proper max banks/counters */
  		if ((h->efr_attr != 0) &&
  		    ((h->efr_attr & (0xF << 13)) != 0) &&
  		    ((h->efr_attr & (0x3F << 17)) != 0))
  			iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
  		else
  			iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1310
1311
  		if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
  			amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
7d7d38afb   Suravee Suthikulpanit   iommu/amd: Adding...
1312
1313
1314
1315
1316
1317
1318
  		break;
  	case 0x11:
  	case 0x40:
  		if (h->efr_reg & (1 << 9))
  			iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
  		else
  			iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1319
1320
  		if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0))
  			amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
7d7d38afb   Suravee Suthikulpanit   iommu/amd: Adding...
1321
1322
1323
  		break;
  	default:
  		return -EINVAL;
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1324
1325
1326
1327
  	}
  
  	iommu->mmio_base = iommu_map_mmio_space(iommu->mmio_phys,
  						iommu->mmio_phys_end);
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1328
1329
  	if (!iommu->mmio_base)
  		return -ENOMEM;
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
1330
  	if (alloc_command_buffer(iommu))
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1331
  		return -ENOMEM;
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
1332
  	if (alloc_event_buffer(iommu))
335503e57   Joerg Roedel   AMD IOMMU: add ev...
1333
  		return -ENOMEM;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1334
  	iommu->int_enabled = false;
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1335
1336
1337
  	ret = init_iommu_from_acpi(iommu, h);
  	if (ret)
  		return ret;
f6fec00a9   Joerg Roedel   iommu/amd: Make s...
1338

7c71d306c   Jiang Liu   irq_remapping/amd...
1339
1340
1341
  	ret = amd_iommu_create_irq_domain(iommu);
  	if (ret)
  		return ret;
f6fec00a9   Joerg Roedel   iommu/amd: Make s...
1342
1343
1344
1345
1346
  	/*
  	 * Make sure IOMMU is not considered to translate itself. The IVRS
  	 * table tells us so, but this is a lie!
  	 */
  	amd_iommu_rlookup_table[iommu->devid] = NULL;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1347
  	return 0;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1348
  }
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
  /**
   * get_highest_supported_ivhd_type - Look up the appropriate IVHD type
   * @ivrs          Pointer to the IVRS header
   *
   * This function search through all IVDB of the maximum supported IVHD
   */
  static u8 get_highest_supported_ivhd_type(struct acpi_table_header *ivrs)
  {
  	u8 *base = (u8 *)ivrs;
  	struct ivhd_header *ivhd = (struct ivhd_header *)
  					(base + IVRS_HEADER_LENGTH);
  	u8 last_type = ivhd->type;
  	u16 devid = ivhd->devid;
  
  	while (((u8 *)ivhd - base < ivrs->length) &&
  	       (ivhd->type <= ACPI_IVHD_TYPE_MAX_SUPPORTED)) {
  		u8 *p = (u8 *) ivhd;
  
  		if (ivhd->devid == devid)
  			last_type = ivhd->type;
  		ivhd = (struct ivhd_header *)(p + ivhd->length);
  	}
  
  	return last_type;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1374
1375
1376
1377
  /*
   * Iterates over all IOMMU entries in the ACPI table, allocates the
   * IOMMU structure and initializes it with init_iommu_one()
   */
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1378
1379
1380
1381
1382
1383
  static int __init init_iommu_all(struct acpi_table_header *table)
  {
  	u8 *p = (u8 *)table, *end = (u8 *)table;
  	struct ivhd_header *h;
  	struct amd_iommu *iommu;
  	int ret;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1384
1385
1386
1387
1388
  	end += table->length;
  	p += IVRS_HEADER_LENGTH;
  
  	while (p < end) {
  		h = (struct ivhd_header *)p;
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
1389
  		if (*p == amd_iommu_target_ivhd_type) {
9c72041f7   Joerg Roedel   amd-iommu: add du...
1390

ae908c22a   Joerg Roedel   x86/amd-iommu: Re...
1391
  			DUMP_printk("device: %02x:%02x.%01x cap: %04x "
9c72041f7   Joerg Roedel   amd-iommu: add du...
1392
1393
  				    "seg: %d flags: %01x info %04x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1394
  				    PCI_BUS_NUM(h->devid), PCI_SLOT(h->devid),
9c72041f7   Joerg Roedel   amd-iommu: add du...
1395
1396
1397
1398
1399
  				    PCI_FUNC(h->devid), h->cap_ptr,
  				    h->pci_seg, h->flags, h->info);
  			DUMP_printk("       mmio-addr: %016llx
  ",
  				    h->mmio_phys);
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1400
  			iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL);
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
1401
1402
  			if (iommu == NULL)
  				return -ENOMEM;
3551a708f   Joerg Roedel   x86/amd-iommu: Re...
1403

e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1404
  			ret = init_iommu_one(iommu, h);
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
1405
1406
  			if (ret)
  				return ret;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1407
1408
1409
1410
1411
1412
1413
1414
  		}
  		p += h->length;
  
  	}
  	WARN_ON(p != end);
  
  	return 0;
  }
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
  
  static void init_iommu_perf_ctr(struct amd_iommu *iommu)
  {
  	u64 val = 0xabcd, val2 = 0;
  
  	if (!iommu_feature(iommu, FEATURE_PC))
  		return;
  
  	amd_iommu_pc_present = true;
  
  	/* Check if the performance counters can be written to */
38e45d02e   Suravee Suthikulpanit   iommu/amd: Fix bo...
1426
1427
  	if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) ||
  	    (0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) ||
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
  	    (val != val2)) {
  		pr_err("AMD-Vi: Unable to write to IOMMU perf counter.
  ");
  		amd_iommu_pc_present = false;
  		return;
  	}
  
  	pr_info("AMD-Vi: IOMMU performance counters supported
  ");
  
  	val = readl(iommu->mmio_base + MMIO_CNTR_CONF_OFFSET);
  	iommu->max_banks = (u8) ((val >> 12) & 0x3f);
  	iommu->max_counters = (u8) ((val >> 7) & 0xf);
  }
066f2e98d   Alex Williamson   iommu/amd: Add sy...
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
  static ssize_t amd_iommu_show_cap(struct device *dev,
  				  struct device_attribute *attr,
  				  char *buf)
  {
  	struct amd_iommu *iommu = dev_get_drvdata(dev);
  	return sprintf(buf, "%x
  ", iommu->cap);
  }
  static DEVICE_ATTR(cap, S_IRUGO, amd_iommu_show_cap, NULL);
  
  static ssize_t amd_iommu_show_features(struct device *dev,
  				       struct device_attribute *attr,
  				       char *buf)
  {
  	struct amd_iommu *iommu = dev_get_drvdata(dev);
  	return sprintf(buf, "%llx
  ", iommu->features);
  }
  static DEVICE_ATTR(features, S_IRUGO, amd_iommu_show_features, NULL);
  
  static struct attribute *amd_iommu_attrs[] = {
  	&dev_attr_cap.attr,
  	&dev_attr_features.attr,
  	NULL,
  };
  
  static struct attribute_group amd_iommu_group = {
  	.name = "amd-iommu",
  	.attrs = amd_iommu_attrs,
  };
  
  static const struct attribute_group *amd_iommu_groups[] = {
  	&amd_iommu_group,
  	NULL,
  };
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1477

23c742db2   Joerg Roedel   iommu/amd: Split ...
1478
1479
1480
1481
  static int iommu_init_pci(struct amd_iommu *iommu)
  {
  	int cap_ptr = iommu->cap_ptr;
  	u32 range, misc, low, high;
8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
1482
  	int ret;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1483

c5081cd7a   Shuah Khan   iommu/amd: Remove...
1484
  	iommu->dev = pci_get_bus_and_slot(PCI_BUS_NUM(iommu->devid),
23c742db2   Joerg Roedel   iommu/amd: Split ...
1485
1486
1487
  					  iommu->devid & 0xff);
  	if (!iommu->dev)
  		return -ENODEV;
cbbc00be2   Jiang Liu   iommu/amd: Preven...
1488
1489
  	/* Prevent binding other PCI device drivers to IOMMU devices */
  	iommu->dev->match_driver = false;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1490
1491
1492
1493
1494
1495
  	pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
  			      &iommu->cap);
  	pci_read_config_dword(iommu->dev, cap_ptr + MMIO_RANGE_OFFSET,
  			      &range);
  	pci_read_config_dword(iommu->dev, cap_ptr + MMIO_MISC_OFFSET,
  			      &misc);
23c742db2   Joerg Roedel   iommu/amd: Split ...
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
  	if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
  		amd_iommu_iotlb_sup = false;
  
  	/* read extended feature bits */
  	low  = readl(iommu->mmio_base + MMIO_EXT_FEATURES);
  	high = readl(iommu->mmio_base + MMIO_EXT_FEATURES + 4);
  
  	iommu->features = ((u64)high << 32) | low;
  
  	if (iommu_feature(iommu, FEATURE_GT)) {
  		int glxval;
a919a018c   Suravee Suthikulpanit   iommu/amd: Fix lo...
1507
1508
  		u32 max_pasid;
  		u64 pasmax;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1509

a919a018c   Suravee Suthikulpanit   iommu/amd: Fix lo...
1510
1511
1512
  		pasmax = iommu->features & FEATURE_PASID_MASK;
  		pasmax >>= FEATURE_PASID_SHIFT;
  		max_pasid  = (1 << (pasmax + 1)) - 1;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1513

a919a018c   Suravee Suthikulpanit   iommu/amd: Fix lo...
1514
1515
1516
  		amd_iommu_max_pasid = min(amd_iommu_max_pasid, max_pasid);
  
  		BUG_ON(amd_iommu_max_pasid & ~PASID_MASK);
23c742db2   Joerg Roedel   iommu/amd: Split ...
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
  
  		glxval   = iommu->features & FEATURE_GLXVAL_MASK;
  		glxval >>= FEATURE_GLXVAL_SHIFT;
  
  		if (amd_iommu_max_glx_val == -1)
  			amd_iommu_max_glx_val = glxval;
  		else
  			amd_iommu_max_glx_val = min(amd_iommu_max_glx_val, glxval);
  	}
  
  	if (iommu_feature(iommu, FEATURE_GT) &&
  	    iommu_feature(iommu, FEATURE_PPR)) {
  		iommu->is_iommu_v2   = true;
  		amd_iommu_v2_present = true;
  	}
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
1532
1533
  	if (iommu_feature(iommu, FEATURE_PPR) && alloc_ppr_log(iommu))
  		return -ENOMEM;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1534

8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
1535
1536
1537
  	ret = iommu_init_ga(iommu);
  	if (ret)
  		return ret;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1538

23c742db2   Joerg Roedel   iommu/amd: Split ...
1539
1540
  	if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE))
  		amd_iommu_np_cache = true;
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1541
  	init_iommu_perf_ctr(iommu);
23c742db2   Joerg Roedel   iommu/amd: Split ...
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
  	if (is_rd890_iommu(iommu->dev)) {
  		int i, j;
  
  		iommu->root_pdev = pci_get_bus_and_slot(iommu->dev->bus->number,
  				PCI_DEVFN(0, 0));
  
  		/*
  		 * Some rd890 systems may not be fully reconfigured by the
  		 * BIOS, so it's necessary for us to store this information so
  		 * it can be reprogrammed on resume
  		 */
  		pci_read_config_dword(iommu->dev, iommu->cap_ptr + 4,
  				&iommu->stored_addr_lo);
  		pci_read_config_dword(iommu->dev, iommu->cap_ptr + 8,
  				&iommu->stored_addr_hi);
  
  		/* Low bit locks writes to configuration space */
  		iommu->stored_addr_lo &= ~1;
  
  		for (i = 0; i < 6; i++)
  			for (j = 0; j < 0x12; j++)
  				iommu->stored_l1[i][j] = iommu_read_l1(iommu, i, j);
  
  		for (i = 0; i < 0x83; i++)
  			iommu->stored_l2[i] = iommu_read_l2(iommu, i);
  	}
318fe7825   Suravee Suthikulpanit   IOMMU, AMD Family...
1568
  	amd_iommu_erratum_746_workaround(iommu);
358875fd5   Jay Cornwall   iommu/amd: Apply ...
1569
  	amd_iommu_ats_write_check_workaround(iommu);
318fe7825   Suravee Suthikulpanit   IOMMU, AMD Family...
1570

066f2e98d   Alex Williamson   iommu/amd: Add sy...
1571
1572
1573
  	iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
  					       amd_iommu_groups, "ivhd%d",
  					       iommu->index);
23c742db2   Joerg Roedel   iommu/amd: Split ...
1574
1575
  	return pci_enable_device(iommu->dev);
  }
4d121c325   Joerg Roedel   iommu/amd: Move i...
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
  static void print_iommu_info(void)
  {
  	static const char * const feat_str[] = {
  		"PreF", "PPR", "X2APIC", "NX", "GT", "[5]",
  		"IA", "GA", "HE", "PC"
  	};
  	struct amd_iommu *iommu;
  
  	for_each_iommu(iommu) {
  		int i;
  
  		pr_info("AMD-Vi: Found IOMMU at %s cap 0x%hx
  ",
  			dev_name(&iommu->dev->dev), iommu->cap_ptr);
  
  		if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1592
1593
1594
  			pr_info("AMD-Vi: Extended features (%#llx):
  ",
  				iommu->features);
2bd5ed002   Joerg Roedel   iommu/amd: Fix wr...
1595
  			for (i = 0; i < ARRAY_SIZE(feat_str); ++i) {
4d121c325   Joerg Roedel   iommu/amd: Move i...
1596
1597
1598
  				if (iommu_feature(iommu, (1ULL << i)))
  					pr_cont(" %s", feat_str[i]);
  			}
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1599
1600
1601
  
  			if (iommu->features & FEATURE_GAM_VAPIC)
  				pr_cont(" GA_vAPIC");
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1602
1603
  			pr_cont("
  ");
500c25edd   Borislav Petkov   iommu/amd: Fix fe...
1604
  		}
4d121c325   Joerg Roedel   iommu/amd: Move i...
1605
  	}
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1606
  	if (irq_remapping_enabled) {
ebe60bbfd   Joerg Roedel   iommu/amd: Print ...
1607
1608
  		pr_info("AMD-Vi: Interrupt remapping enabled
  ");
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1609
1610
1611
1612
  		if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))
  			pr_info("AMD-Vi: virtual APIC enabled
  ");
  	}
4d121c325   Joerg Roedel   iommu/amd: Move i...
1613
  }
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
1614
  static int __init amd_iommu_init_pci(void)
23c742db2   Joerg Roedel   iommu/amd: Split ...
1615
1616
1617
1618
1619
1620
1621
1622
1623
  {
  	struct amd_iommu *iommu;
  	int ret = 0;
  
  	for_each_iommu(iommu) {
  		ret = iommu_init_pci(iommu);
  		if (ret)
  			break;
  	}
522e5cb76   Joerg Roedel   iommu/amd: Fix un...
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
  	/*
  	 * Order is important here to make sure any unity map requirements are
  	 * fulfilled. The unity mappings are created and written to the device
  	 * table during the amd_iommu_init_api() call.
  	 *
  	 * After that we call init_device_table_dma() to make sure any
  	 * uninitialized DTE will block DMA, and in the end we flush the caches
  	 * of all IOMMUs to make sure the changes to the device table are
  	 * active.
  	 */
  	ret = amd_iommu_init_api();
aafd8ba0c   Joerg Roedel   iommu/amd: Implem...
1635
1636
1637
1638
  	init_device_table_dma();
  
  	for_each_iommu(iommu)
  		iommu_flush_all_caches(iommu);
3a18404cd   Joerg Roedel   iommu/amd: Propag...
1639
1640
  	if (!ret)
  		print_iommu_info();
4d121c325   Joerg Roedel   iommu/amd: Move i...
1641

23c742db2   Joerg Roedel   iommu/amd: Split ...
1642
1643
  	return ret;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1644
1645
  /****************************************************************************
   *
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1646
   * The following functions initialize the MSI interrupts for all IOMMUs
df805abb2   Frank Arnold   iommu/amd: Fix so...
1647
   * in the system. It's a bit challenging because there could be multiple
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1648
1649
1650
1651
   * IOMMUs per PCI BDF but we can call pci_enable_msi(x) only once per
   * pci_dev.
   *
   ****************************************************************************/
9f800de38   Joerg Roedel   x86/amd-iommu: un...
1652
  static int iommu_setup_msi(struct amd_iommu *iommu)
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1653
1654
  {
  	int r;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1655

9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1656
1657
1658
  	r = pci_enable_msi(iommu->dev);
  	if (r)
  		return r;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1659

72fe00f01   Joerg Roedel   x86/amd-iommu: Us...
1660
1661
1662
1663
  	r = request_threaded_irq(iommu->dev->irq,
  				 amd_iommu_int_handler,
  				 amd_iommu_int_thread,
  				 0, "AMD-Vi",
3f398bc77   Suravee Suthikulpanit   iommu/AMD: Per-th...
1664
  				 iommu);
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1665
1666
1667
  
  	if (r) {
  		pci_disable_msi(iommu->dev);
9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1668
  		return r;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1669
  	}
fab6afa30   Joerg Roedel   amd-iommu: drop p...
1670
  	iommu->int_enabled = true;
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
1671

a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1672
1673
  	return 0;
  }
05f92db9f   Joerg Roedel   amd_iommu: un __i...
1674
  static int iommu_init_msi(struct amd_iommu *iommu)
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1675
  {
9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1676
  	int ret;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1677
  	if (iommu->int_enabled)
9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1678
  		goto enable_faults;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1679

82fcfc674   Yijing Wang   iommu/amd: Clean ...
1680
  	if (iommu->dev->msi_cap)
9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1681
1682
1683
1684
1685
1686
  		ret = iommu_setup_msi(iommu);
  	else
  		ret = -ENODEV;
  
  	if (ret)
  		return ret;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1687

9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1688
1689
  enable_faults:
  	iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1690

9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1691
1692
  	if (iommu->ppr_log != NULL)
  		iommu_feature_enable(iommu, CONTROL_PPFINT_EN);
8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
1693
  	iommu_ga_log_enable(iommu);
9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1694
  	return 0;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1695
1696
1697
1698
  }
  
  /****************************************************************************
   *
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1699
1700
   * The next functions belong to the third pass of parsing the ACPI
   * table. In this last pass the memory mapping requirements are
df805abb2   Frank Arnold   iommu/amd: Fix so...
1701
   * gathered (like exclusion and unity mapping ranges).
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1702
1703
   *
   ****************************************************************************/
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1704
1705
1706
1707
1708
1709
1710
1711
1712
  static void __init free_unity_maps(void)
  {
  	struct unity_map_entry *entry, *next;
  
  	list_for_each_entry_safe(entry, next, &amd_iommu_unity_map, list) {
  		list_del(&entry->list);
  		kfree(entry);
  	}
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1713
  /* called when we find an exclusion range definition in ACPI */
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1714
1715
1716
1717
1718
1719
1720
1721
1722
  static int __init init_exclusion_range(struct ivmd_header *m)
  {
  	int i;
  
  	switch (m->type) {
  	case ACPI_IVMD_TYPE:
  		set_device_exclusion_range(m->devid, m);
  		break;
  	case ACPI_IVMD_TYPE_ALL:
3a61ec387   Joerg Roedel   x86, AMD IOMMU: i...
1723
  		for (i = 0; i <= amd_iommu_last_bdf; ++i)
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
  			set_device_exclusion_range(i, m);
  		break;
  	case ACPI_IVMD_TYPE_RANGE:
  		for (i = m->devid; i <= m->aux; ++i)
  			set_device_exclusion_range(i, m);
  		break;
  	default:
  		break;
  	}
  
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1736
  /* called for unity map ACPI definition */
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1737
1738
  static int __init init_unity_map_range(struct ivmd_header *m)
  {
98f1ad258   Joerg Roedel   iommu/amd: Fix sp...
1739
  	struct unity_map_entry *e = NULL;
02acc43a2   Joerg Roedel   amd-iommu: print ...
1740
  	char *s;
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1741
1742
1743
1744
1745
1746
1747
  
  	e = kzalloc(sizeof(*e), GFP_KERNEL);
  	if (e == NULL)
  		return -ENOMEM;
  
  	switch (m->type) {
  	default:
0bc252f43   Joerg Roedel   amd-iommu: make s...
1748
1749
  		kfree(e);
  		return 0;
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1750
  	case ACPI_IVMD_TYPE:
02acc43a2   Joerg Roedel   amd-iommu: print ...
1751
  		s = "IVMD_TYPEi\t\t\t";
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1752
1753
1754
  		e->devid_start = e->devid_end = m->devid;
  		break;
  	case ACPI_IVMD_TYPE_ALL:
02acc43a2   Joerg Roedel   amd-iommu: print ...
1755
  		s = "IVMD_TYPE_ALL\t\t";
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1756
1757
1758
1759
  		e->devid_start = 0;
  		e->devid_end = amd_iommu_last_bdf;
  		break;
  	case ACPI_IVMD_TYPE_RANGE:
02acc43a2   Joerg Roedel   amd-iommu: print ...
1760
  		s = "IVMD_TYPE_RANGE\t\t";
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1761
1762
1763
1764
1765
1766
1767
  		e->devid_start = m->devid;
  		e->devid_end = m->aux;
  		break;
  	}
  	e->address_start = PAGE_ALIGN(m->range_start);
  	e->address_end = e->address_start + PAGE_ALIGN(m->range_length);
  	e->prot = m->flags >> 1;
02acc43a2   Joerg Roedel   amd-iommu: print ...
1768
1769
1770
  	DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
  		    " range_start: %016llx range_end: %016llx flags: %x
  ", s,
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1771
1772
  		    PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
  		    PCI_FUNC(e->devid_start), PCI_BUS_NUM(e->devid_end),
02acc43a2   Joerg Roedel   amd-iommu: print ...
1773
1774
  		    PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end),
  		    e->address_start, e->address_end, m->flags);
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1775
1776
1777
1778
  	list_add_tail(&e->list, &amd_iommu_unity_map);
  
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1779
  /* iterates over all memory definitions we find in the ACPI table */
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1780
1781
1782
1783
  static int __init init_memory_definitions(struct acpi_table_header *table)
  {
  	u8 *p = (u8 *)table, *end = (u8 *)table;
  	struct ivmd_header *m;
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
  	end += table->length;
  	p += IVRS_HEADER_LENGTH;
  
  	while (p < end) {
  		m = (struct ivmd_header *)p;
  		if (m->flags & IVMD_FLAG_EXCL_RANGE)
  			init_exclusion_range(m);
  		else if (m->flags & IVMD_FLAG_UNITY_MAP)
  			init_unity_map_range(m);
  
  		p += m->length;
  	}
  
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1799
  /*
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1800
1801
1802
   * Init the device table to not allow DMA access for devices and
   * suppress all page faults
   */
33f28c59e   Joerg Roedel   iommu/amd: Split ...
1803
  static void init_device_table_dma(void)
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1804
  {
0de66d5b3   Joerg Roedel   x86/amd-iommu: Fi...
1805
  	u32 devid;
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1806
1807
1808
1809
  
  	for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
  		set_dev_entry_bit(devid, DEV_ENTRY_VALID);
  		set_dev_entry_bit(devid, DEV_ENTRY_TRANSLATION);
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1810
1811
  	}
  }
d04e0ba34   Joerg Roedel   iommu/amd: Make s...
1812
1813
1814
1815
1816
1817
1818
1819
1820
  static void __init uninit_device_table_dma(void)
  {
  	u32 devid;
  
  	for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
  		amd_iommu_dev_table[devid].data[0] = 0ULL;
  		amd_iommu_dev_table[devid].data[1] = 0ULL;
  	}
  }
33f28c59e   Joerg Roedel   iommu/amd: Split ...
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
  static void init_device_table(void)
  {
  	u32 devid;
  
  	if (!amd_iommu_irq_remap)
  		return;
  
  	for (devid = 0; devid <= amd_iommu_last_bdf; ++devid)
  		set_dev_entry_bit(devid, DEV_ENTRY_IRQ_TBL_EN);
  }
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
  static void iommu_init_flags(struct amd_iommu *iommu)
  {
  	iommu->acpi_flags & IVHD_FLAG_HT_TUN_EN_MASK ?
  		iommu_feature_enable(iommu, CONTROL_HT_TUN_EN) :
  		iommu_feature_disable(iommu, CONTROL_HT_TUN_EN);
  
  	iommu->acpi_flags & IVHD_FLAG_PASSPW_EN_MASK ?
  		iommu_feature_enable(iommu, CONTROL_PASSPW_EN) :
  		iommu_feature_disable(iommu, CONTROL_PASSPW_EN);
  
  	iommu->acpi_flags & IVHD_FLAG_RESPASSPW_EN_MASK ?
  		iommu_feature_enable(iommu, CONTROL_RESPASSPW_EN) :
  		iommu_feature_disable(iommu, CONTROL_RESPASSPW_EN);
  
  	iommu->acpi_flags & IVHD_FLAG_ISOC_EN_MASK ?
  		iommu_feature_enable(iommu, CONTROL_ISOC_EN) :
  		iommu_feature_disable(iommu, CONTROL_ISOC_EN);
  
  	/*
  	 * make IOMMU memory accesses cache coherent
  	 */
  	iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
1456e9d2c   Joerg Roedel   iommu/amd: Set IO...
1853
1854
1855
  
  	/* Set IOTLB invalidation timeout to 1s */
  	iommu_set_inv_tlb_timeout(iommu, CTRL_INV_TO_1S);
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
1856
  }
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1857
  static void iommu_apply_resume_quirks(struct amd_iommu *iommu)
4c894f47b   Joerg Roedel   x86/amd-iommu: Wo...
1858
  {
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1859
1860
  	int i, j;
  	u32 ioc_feature_control;
c1bf94ec1   Joerg Roedel   iommu/amd: Cache ...
1861
  	struct pci_dev *pdev = iommu->root_pdev;
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1862
1863
  
  	/* RD890 BIOSes may not have completely reconfigured the iommu */
c1bf94ec1   Joerg Roedel   iommu/amd: Cache ...
1864
  	if (!is_rd890_iommu(iommu->dev) || !pdev)
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1865
1866
1867
1868
1869
1870
  		return;
  
  	/*
  	 * First, we need to ensure that the iommu is enabled. This is
  	 * controlled by a register in the northbridge
  	 */
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1871
1872
1873
1874
1875
1876
1877
1878
  
  	/* Select Northbridge indirect register 0x75 and enable writing */
  	pci_write_config_dword(pdev, 0x60, 0x75 | (1 << 7));
  	pci_read_config_dword(pdev, 0x64, &ioc_feature_control);
  
  	/* Enable the iommu */
  	if (!(ioc_feature_control & 0x1))
  		pci_write_config_dword(pdev, 0x64, ioc_feature_control | 1);
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
  	/* Restore the iommu BAR */
  	pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
  			       iommu->stored_addr_lo);
  	pci_write_config_dword(iommu->dev, iommu->cap_ptr + 8,
  			       iommu->stored_addr_hi);
  
  	/* Restore the l1 indirect regs for each of the 6 l1s */
  	for (i = 0; i < 6; i++)
  		for (j = 0; j < 0x12; j++)
  			iommu_write_l1(iommu, i, j, iommu->stored_l1[i][j]);
  
  	/* Restore the l2 indirect regs */
  	for (i = 0; i < 0x83; i++)
  		iommu_write_l2(iommu, i, iommu->stored_l2[i]);
  
  	/* Lock PCI setup registers */
  	pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
  			       iommu->stored_addr_lo | 1);
4c894f47b   Joerg Roedel   x86/amd-iommu: Wo...
1897
  }
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1898
1899
1900
1901
1902
1903
1904
1905
1906
  static void iommu_enable_ga(struct amd_iommu *iommu)
  {
  #ifdef CONFIG_IRQ_REMAP
  	switch (amd_iommu_guest_ir) {
  	case AMD_IOMMU_GUEST_IR_VAPIC:
  		iommu_feature_enable(iommu, CONTROL_GAM_EN);
  		/* Fall through */
  	case AMD_IOMMU_GUEST_IR_LEGACY_GA:
  		iommu_feature_enable(iommu, CONTROL_GA_EN);
77bdab46f   Suravee Suthikulpanit   iommu/amd: Add su...
1907
  		iommu->irte_ops = &irte_128_ops;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1908
1909
  		break;
  	default:
77bdab46f   Suravee Suthikulpanit   iommu/amd: Add su...
1910
  		iommu->irte_ops = &irte_32_ops;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1911
1912
1913
1914
  		break;
  	}
  #endif
  }
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1915
  /*
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1916
1917
1918
   * This function finally enables all IOMMUs found in the system after
   * they have been initialized
   */
11ee5ac47   Joerg Roedel   iommu/amd: Split ...
1919
  static void early_enable_iommus(void)
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1920
1921
  {
  	struct amd_iommu *iommu;
3bd221724   Joerg Roedel   amd-iommu: introd...
1922
  	for_each_iommu(iommu) {
a8c485bb6   Chris Wright   amd-iommu: disabl...
1923
  		iommu_disable(iommu);
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
1924
  		iommu_init_flags(iommu);
58492e128   Joerg Roedel   amd-iommu: consol...
1925
1926
1927
  		iommu_set_device_table(iommu);
  		iommu_enable_command_buffer(iommu);
  		iommu_enable_event_buffer(iommu);
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1928
  		iommu_set_exclusion_range(iommu);
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1929
  		iommu_enable_ga(iommu);
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1930
  		iommu_enable(iommu);
7d0c5cc5b   Joerg Roedel   x86/amd-iommu: Fl...
1931
  		iommu_flush_all_caches(iommu);
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1932
  	}
d98de49a5   Suravee Suthikulpanit   iommu/amd: Enable...
1933
1934
1935
1936
1937
  
  #ifdef CONFIG_IRQ_REMAP
  	if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))
  		amd_iommu_irq_ops.capability |= (1 << IRQ_POSTING_CAP);
  #endif
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1938
  }
11ee5ac47   Joerg Roedel   iommu/amd: Split ...
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
  static void enable_iommus_v2(void)
  {
  	struct amd_iommu *iommu;
  
  	for_each_iommu(iommu) {
  		iommu_enable_ppr_log(iommu);
  		iommu_enable_gt(iommu);
  	}
  }
  
  static void enable_iommus(void)
  {
  	early_enable_iommus();
  
  	enable_iommus_v2();
  }
92ac4320a   Joerg Roedel   amd-iommu: add fu...
1955
1956
1957
1958
1959
1960
  static void disable_iommus(void)
  {
  	struct amd_iommu *iommu;
  
  	for_each_iommu(iommu)
  		iommu_disable(iommu);
d98de49a5   Suravee Suthikulpanit   iommu/amd: Enable...
1961
1962
1963
1964
1965
  
  #ifdef CONFIG_IRQ_REMAP
  	if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))
  		amd_iommu_irq_ops.capability &= ~(1 << IRQ_POSTING_CAP);
  #endif
92ac4320a   Joerg Roedel   amd-iommu: add fu...
1966
  }
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1967
1968
1969
1970
  /*
   * Suspend/Resume support
   * disable suspend until real resume implemented
   */
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
1971
  static void amd_iommu_resume(void)
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1972
  {
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1973
1974
1975
1976
  	struct amd_iommu *iommu;
  
  	for_each_iommu(iommu)
  		iommu_apply_resume_quirks(iommu);
736501ee0   Joerg Roedel   amd-iommu: implem...
1977
1978
  	/* re-load the hardware */
  	enable_iommus();
3d9761e7a   Joerg Roedel   iommu/amd: Move i...
1979
1980
  
  	amd_iommu_enable_interrupts();
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1981
  }
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
1982
  static int amd_iommu_suspend(void)
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1983
  {
736501ee0   Joerg Roedel   amd-iommu: implem...
1984
1985
1986
1987
  	/* disable IOMMUs to go out of the way for BIOS */
  	disable_iommus();
  
  	return 0;
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1988
  }
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
1989
  static struct syscore_ops amd_iommu_syscore_ops = {
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1990
1991
1992
  	.suspend = amd_iommu_suspend,
  	.resume = amd_iommu_resume,
  };
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
1993
1994
  static void __init free_on_init_error(void)
  {
0ea2c422b   Joerg Roedel   iommu/amd: Alloca...
1995
1996
  	free_pages((unsigned long)irq_lookup_table,
  		   get_order(rlookup_table_size));
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
1997

a591989a7   Julia Lawall   iommu/amd: Drop n...
1998
1999
  	kmem_cache_destroy(amd_iommu_irq_cache);
  	amd_iommu_irq_cache = NULL;
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
  
  	free_pages((unsigned long)amd_iommu_rlookup_table,
  		   get_order(rlookup_table_size));
  
  	free_pages((unsigned long)amd_iommu_alias_table,
  		   get_order(alias_table_size));
  
  	free_pages((unsigned long)amd_iommu_dev_table,
  		   get_order(dev_table_size));
  
  	free_iommu_all();
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2011
2012
2013
2014
2015
2016
2017
2018
2019
  #ifdef CONFIG_GART_IOMMU
  	/*
  	 * We failed to initialize the AMD IOMMU - try fallback to GART
  	 * if possible.
  	 */
  	gart_iommu_init();
  
  #endif
  }
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2020
2021
  /* SB IOAPIC is always on this device in AMD systems */
  #define IOAPIC_SB_DEVID		((0x00 << 8) | PCI_DEVFN(0x14, 0))
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2022
2023
  static bool __init check_ioapic_information(void)
  {
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2024
  	const char *fw_bug = FW_BUG;
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2025
  	bool ret, has_sb_ioapic;
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2026
  	int idx;
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2027
2028
  	has_sb_ioapic = false;
  	ret           = false;
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2029

dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2030
2031
2032
2033
2034
2035
2036
  	/*
  	 * If we have map overrides on the kernel command line the
  	 * messages in this function might not describe firmware bugs
  	 * anymore - so be careful
  	 */
  	if (cmdline_maps)
  		fw_bug = "";
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2037
2038
2039
2040
2041
  	for (idx = 0; idx < nr_ioapics; idx++) {
  		int devid, id = mpc_ioapic_id(idx);
  
  		devid = get_ioapic_devid(id);
  		if (devid < 0) {
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2042
2043
2044
  			pr_err("%sAMD-Vi: IOAPIC[%d] not in IVRS table
  ",
  				fw_bug, id);
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2045
2046
2047
2048
  			ret = false;
  		} else if (devid == IOAPIC_SB_DEVID) {
  			has_sb_ioapic = true;
  			ret           = true;
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2049
2050
  		}
  	}
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2051
2052
2053
2054
2055
2056
2057
2058
2059
  	if (!has_sb_ioapic) {
  		/*
  		 * We expect the SB IOAPIC to be listed in the IVRS
  		 * table. The system timer is connected to the SB IOAPIC
  		 * and if we don't have it in the list the system will
  		 * panic at boot time.  This situation usually happens
  		 * when the BIOS is buggy and provides us the wrong
  		 * device id for the IOAPIC in the system.
  		 */
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2060
2061
  		pr_err("%sAMD-Vi: No southbridge IOAPIC found
  ", fw_bug);
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2062
2063
2064
  	}
  
  	if (!ret)
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2065
2066
  		pr_err("AMD-Vi: Disabling interrupt remapping
  ");
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2067
2068
  
  	return ret;
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2069
  }
d04e0ba34   Joerg Roedel   iommu/amd: Make s...
2070
2071
  static void __init free_dma_resources(void)
  {
d04e0ba34   Joerg Roedel   iommu/amd: Make s...
2072
2073
2074
2075
2076
  	free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
  		   get_order(MAX_DOMAIN_ID/8));
  
  	free_unity_maps();
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2077
  /*
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2078
2079
2080
   * This is the hardware init function for AMD IOMMU in the system.
   * This function is called either from amd_iommu_init or from the interrupt
   * remapping setup code.
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2081
2082
   *
   * This function basically parses the ACPI table for AMD IOMMU (IVRS)
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2083
   * four times:
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2084
   *
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2085
2086
2087
   *	1 pass) Discover the most comprehensive IVHD type to use.
   *
   *	2 pass) Find the highest PCI device id the driver has to handle.
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2088
2089
2090
   *		Upon this information the size of the data structures is
   *		determined that needs to be allocated.
   *
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2091
   *	3 pass) Initialize the data structures just allocated with the
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2092
2093
2094
2095
   *		information in the ACPI table about available AMD IOMMUs
   *		in the system. It also maps the PCI devices in the
   *		system to specific IOMMUs
   *
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2096
   *	4 pass) After the basic data structures are allocated and
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2097
2098
2099
2100
   *		initialized we update them with information about memory
   *		remapping requirements parsed out of the ACPI table in
   *		this last pass.
   *
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2101
2102
   * After everything is set up the IOMMUs are enabled and the necessary
   * hotplug and suspend notifiers are registered.
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2103
   */
643511b37   Joerg Roedel   iommu/amd: Introd...
2104
  static int __init early_amd_iommu_init(void)
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2105
  {
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2106
2107
2108
  	struct acpi_table_header *ivrs_base;
  	acpi_size ivrs_size;
  	acpi_status status;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
2109
  	int i, remap_cache_sz, ret = 0;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2110

643511b37   Joerg Roedel   iommu/amd: Introd...
2111
  	if (!amd_iommu_detected)
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2112
  		return -ENODEV;
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2113
2114
2115
2116
2117
2118
2119
2120
2121
  	status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size);
  	if (status == AE_NOT_FOUND)
  		return -ENODEV;
  	else if (ACPI_FAILURE(status)) {
  		const char *err = acpi_format_exception(status);
  		pr_err("AMD-Vi: IVRS table error: %s
  ", err);
  		return -EINVAL;
  	}
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2122
  	/*
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
  	 * Validate checksum here so we don't need to do it when
  	 * we actually parse the table
  	 */
  	ret = check_ivrs_checksum(ivrs_base);
  	if (ret)
  		return ret;
  
  	amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base);
  	DUMP_printk("Using IVHD type %#x
  ", amd_iommu_target_ivhd_type);
  
  	/*
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2135
2136
2137
2138
  	 * First parse ACPI tables to find the largest Bus/Dev/Func
  	 * we need to handle. Upon this information the shared data
  	 * structures for the IOMMUs in the system will be allocated
  	 */
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2139
2140
  	ret = find_last_devid_acpi(ivrs_base);
  	if (ret)
3551a708f   Joerg Roedel   x86/amd-iommu: Re...
2141
  		goto out;
c571484e5   Joerg Roedel   x86, AMD IOMMU: r...
2142
2143
2144
  	dev_table_size     = tbl_size(DEV_TABLE_ENTRY_SIZE);
  	alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
  	rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2145

fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2146
  	/* Device table - directly used by all IOMMUs */
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2147
  	ret = -ENOMEM;
5dc8bff0f   Joerg Roedel   x86, AMD IOMMU: r...
2148
  	amd_iommu_dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
  				      get_order(dev_table_size));
  	if (amd_iommu_dev_table == NULL)
  		goto out;
  
  	/*
  	 * Alias table - map PCI Bus/Dev/Func to Bus/Dev/Func the
  	 * IOMMU see for that device
  	 */
  	amd_iommu_alias_table = (void *)__get_free_pages(GFP_KERNEL,
  			get_order(alias_table_size));
  	if (amd_iommu_alias_table == NULL)
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2160
  		goto out;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2161
2162
  
  	/* IOMMU rlookup table - find the IOMMU for a specific device */
83fd5cc64   Joerg Roedel   AMD IOMMU: alloca...
2163
2164
  	amd_iommu_rlookup_table = (void *)__get_free_pages(
  			GFP_KERNEL | __GFP_ZERO,
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2165
2166
  			get_order(rlookup_table_size));
  	if (amd_iommu_rlookup_table == NULL)
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2167
  		goto out;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2168

5dc8bff0f   Joerg Roedel   x86, AMD IOMMU: r...
2169
2170
  	amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages(
  					    GFP_KERNEL | __GFP_ZERO,
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2171
2172
  					    get_order(MAX_DOMAIN_ID/8));
  	if (amd_iommu_pd_alloc_bitmap == NULL)
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2173
  		goto out;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2174
2175
  
  	/*
5dc8bff0f   Joerg Roedel   x86, AMD IOMMU: r...
2176
  	 * let all alias entries point to itself
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2177
  	 */
3a61ec387   Joerg Roedel   x86, AMD IOMMU: i...
2178
  	for (i = 0; i <= amd_iommu_last_bdf; ++i)
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2179
  		amd_iommu_alias_table[i] = i;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2180
2181
2182
2183
  	/*
  	 * never allocate domain 0 because its used as the non-allocated and
  	 * error value placeholder
  	 */
5c87f62dd   Baoquan He   iommu/amd: Use st...
2184
  	__set_bit(0, amd_iommu_pd_alloc_bitmap);
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2185

aeb26f553   Joerg Roedel   x86/amd-iommu: Im...
2186
  	spin_lock_init(&amd_iommu_pd_lock);
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2187
2188
2189
2190
  	/*
  	 * now the data structures are allocated and basically initialized
  	 * start the real acpi table scan
  	 */
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2191
2192
  	ret = init_iommu_all(ivrs_base);
  	if (ret)
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2193
  		goto out;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2194

eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2195
2196
  	if (amd_iommu_irq_remap)
  		amd_iommu_irq_remap = check_ioapic_information();
05152a049   Joerg Roedel   iommu/amd: Add sl...
2197
2198
2199
2200
2201
  	if (amd_iommu_irq_remap) {
  		/*
  		 * Interrupt remapping enabled, create kmem_cache for the
  		 * remapping tables.
  		 */
83ed9c13e   Wei Yongjun   iommu/amd: fix er...
2202
  		ret = -ENOMEM;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
2203
2204
2205
2206
  		if (!AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir))
  			remap_cache_sz = MAX_IRQS_PER_TABLE * sizeof(u32);
  		else
  			remap_cache_sz = MAX_IRQS_PER_TABLE * (sizeof(u64) * 2);
05152a049   Joerg Roedel   iommu/amd: Add sl...
2207
  		amd_iommu_irq_cache = kmem_cache_create("irq_remap_cache",
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
2208
2209
2210
  							remap_cache_sz,
  							IRQ_TABLE_ALIGNMENT,
  							0, NULL);
05152a049   Joerg Roedel   iommu/amd: Add sl...
2211
2212
  		if (!amd_iommu_irq_cache)
  			goto out;
0ea2c422b   Joerg Roedel   iommu/amd: Alloca...
2213
2214
2215
2216
2217
2218
  
  		irq_lookup_table = (void *)__get_free_pages(
  				GFP_KERNEL | __GFP_ZERO,
  				get_order(rlookup_table_size));
  		if (!irq_lookup_table)
  			goto out;
05152a049   Joerg Roedel   iommu/amd: Add sl...
2219
  	}
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2220
2221
  	ret = init_memory_definitions(ivrs_base);
  	if (ret)
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2222
  		goto out;
3551a708f   Joerg Roedel   x86/amd-iommu: Re...
2223

eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2224
2225
  	/* init the device table */
  	init_device_table();
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2226
  out:
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2227
2228
2229
  	/* Don't leak any ACPI memory */
  	early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
  	ivrs_base = NULL;
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2230
  	return ret;
643511b37   Joerg Roedel   iommu/amd: Introd...
2231
  }
ae295142d   Gerard Snitselaar   iommu/amd: Fix se...
2232
  static int amd_iommu_enable_interrupts(void)
3d9761e7a   Joerg Roedel   iommu/amd: Move i...
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
  {
  	struct amd_iommu *iommu;
  	int ret = 0;
  
  	for_each_iommu(iommu) {
  		ret = iommu_init_msi(iommu);
  		if (ret)
  			goto out;
  	}
  
  out:
  	return ret;
  }
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
  static bool detect_ivrs(void)
  {
  	struct acpi_table_header *ivrs_base;
  	acpi_size ivrs_size;
  	acpi_status status;
  
  	status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size);
  	if (status == AE_NOT_FOUND)
  		return false;
  	else if (ACPI_FAILURE(status)) {
  		const char *err = acpi_format_exception(status);
  		pr_err("AMD-Vi: IVRS table error: %s
  ", err);
  		return false;
  	}
  
  	early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
1adb7d31b   Joerg Roedel   iommu/amd: Fix pc...
2263
2264
  	/* Make sure ACS will be enabled during PCI probe */
  	pci_request_acs();
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2265
2266
  	return true;
  }
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2267
  /****************************************************************************
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2268
   *
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2269
2270
2271
2272
2273
   * AMD IOMMU Initialization State Machine
   *
   ****************************************************************************/
  
  static int __init state_next(void)
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2274
2275
  {
  	int ret = 0;
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
  	switch (init_state) {
  	case IOMMU_START_STATE:
  		if (!detect_ivrs()) {
  			init_state	= IOMMU_NOT_FOUND;
  			ret		= -ENODEV;
  		} else {
  			init_state	= IOMMU_IVRS_DETECTED;
  		}
  		break;
  	case IOMMU_IVRS_DETECTED:
  		ret = early_amd_iommu_init();
  		init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED;
  		break;
  	case IOMMU_ACPI_FINISHED:
  		early_enable_iommus();
  		register_syscore_ops(&amd_iommu_syscore_ops);
  		x86_platform.iommu_shutdown = disable_iommus;
  		init_state = IOMMU_ENABLED;
  		break;
  	case IOMMU_ENABLED:
  		ret = amd_iommu_init_pci();
  		init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT;
  		enable_iommus_v2();
  		break;
  	case IOMMU_PCI_INIT:
  		ret = amd_iommu_enable_interrupts();
  		init_state = ret ? IOMMU_INIT_ERROR : IOMMU_INTERRUPTS_EN;
  		break;
  	case IOMMU_INTERRUPTS_EN:
1e6a7b04c   Joerg Roedel   iommu/amd: Use io...
2305
  		ret = amd_iommu_init_dma_ops();
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
  		init_state = ret ? IOMMU_INIT_ERROR : IOMMU_DMA_OPS;
  		break;
  	case IOMMU_DMA_OPS:
  		init_state = IOMMU_INITIALIZED;
  		break;
  	case IOMMU_INITIALIZED:
  		/* Nothing to do */
  		break;
  	case IOMMU_NOT_FOUND:
  	case IOMMU_INIT_ERROR:
  		/* Error states => do nothing */
  		ret = -EINVAL;
  		break;
  	default:
  		/* Unknown state */
  		BUG();
  	}
3d9761e7a   Joerg Roedel   iommu/amd: Move i...
2323

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2324
2325
  	return ret;
  }
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
2326

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2327
2328
2329
  static int __init iommu_go_to_state(enum iommu_init_state state)
  {
  	int ret = 0;
f53250943   Joerg Roedel   x86/amd-iommu: Fi...
2330

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2331
2332
2333
2334
2335
2336
  	while (init_state != state) {
  		ret = state_next();
  		if (init_state == IOMMU_NOT_FOUND ||
  		    init_state == IOMMU_INIT_ERROR)
  			break;
  	}
f2f12b6fc   Shuah Khan   iommu/amd: Fix mi...
2337

fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2338
  	return ret;
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2339
  }
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2340

6b474b822   Joerg Roedel   iommu/amd: Add in...
2341
2342
2343
  #ifdef CONFIG_IRQ_REMAP
  int __init amd_iommu_prepare(void)
  {
3f4cb7c06   Thomas Gleixner   iommu/amd: Fix ir...
2344
  	int ret;
7fa1c842c   Jiang Liu   iommu/irq_remappi...
2345
  	amd_iommu_irq_remap = true;
84d077930   Joerg Roedel   iommu/amd: Check ...
2346

3f4cb7c06   Thomas Gleixner   iommu/amd: Fix ir...
2347
2348
2349
2350
  	ret = iommu_go_to_state(IOMMU_ACPI_FINISHED);
  	if (ret)
  		return ret;
  	return amd_iommu_irq_remap ? 0 : -ENODEV;
6b474b822   Joerg Roedel   iommu/amd: Add in...
2351
  }
d7f077697   Joerg Roedel   x86/amd-iommu: Fa...
2352

6b474b822   Joerg Roedel   iommu/amd: Add in...
2353
2354
2355
2356
2357
2358
2359
  int __init amd_iommu_enable(void)
  {
  	int ret;
  
  	ret = iommu_go_to_state(IOMMU_ENABLED);
  	if (ret)
  		return ret;
d7f077697   Joerg Roedel   x86/amd-iommu: Fa...
2360

6b474b822   Joerg Roedel   iommu/amd: Add in...
2361
  	irq_remapping_enabled = 1;
d7f077697   Joerg Roedel   x86/amd-iommu: Fa...
2362

6b474b822   Joerg Roedel   iommu/amd: Add in...
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
  	return 0;
  }
  
  void amd_iommu_disable(void)
  {
  	amd_iommu_suspend();
  }
  
  int amd_iommu_reenable(int mode)
  {
  	amd_iommu_resume();
  
  	return 0;
  }
d7f077697   Joerg Roedel   x86/amd-iommu: Fa...
2377

6b474b822   Joerg Roedel   iommu/amd: Add in...
2378
2379
2380
2381
2382
2383
  int __init amd_iommu_enable_faulting(void)
  {
  	/* We enable MSI later when PCI is initialized */
  	return 0;
  }
  #endif
d7f077697   Joerg Roedel   x86/amd-iommu: Fa...
2384

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
  /*
   * This is the core init function for AMD IOMMU hardware in the system.
   * This function is called from the generic x86 DMA layer initialization
   * code.
   */
  static int __init amd_iommu_init(void)
  {
  	int ret;
  
  	ret = iommu_go_to_state(IOMMU_INITIALIZED);
  	if (ret) {
d04e0ba34   Joerg Roedel   iommu/amd: Make s...
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
  		free_dma_resources();
  		if (!irq_remapping_enabled) {
  			disable_iommus();
  			free_on_init_error();
  		} else {
  			struct amd_iommu *iommu;
  
  			uninit_device_table_dma();
  			for_each_iommu(iommu)
  				iommu_flush_all_caches(iommu);
  		}
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2407
2408
2409
  	}
  
  	return ret;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2410
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2411
2412
2413
2414
2415
2416
2417
  /****************************************************************************
   *
   * Early detect code. This code runs at IOMMU detection time in the DMA
   * layer. It just looks if there is an IVRS ACPI table to detect AMD
   * IOMMUs
   *
   ****************************************************************************/
480125ba4   Konrad Rzeszutek Wilk   x86, iommu: Make ...
2418
  int __init amd_iommu_detect(void)
ae7877de9   Joerg Roedel   x86, AMD IOMMU: a...
2419
  {
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2420
  	int ret;
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2421

75f1cdf1d   FUJITA Tomonori   x86: Handle HW IO...
2422
  	if (no_iommu || (iommu_detected && !gart_iommu_aperture))
480125ba4   Konrad Rzeszutek Wilk   x86, iommu: Make ...
2423
  		return -ENODEV;
ae7877de9   Joerg Roedel   x86, AMD IOMMU: a...
2424

a52357259   Joerg Roedel   x86/amd-iommu: Ad...
2425
  	if (amd_iommu_disabled)
480125ba4   Konrad Rzeszutek Wilk   x86, iommu: Make ...
2426
  		return -ENODEV;
a52357259   Joerg Roedel   x86/amd-iommu: Ad...
2427

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2428
2429
2430
  	ret = iommu_go_to_state(IOMMU_IVRS_DETECTED);
  	if (ret)
  		return ret;
11bd04f6f   Linus Torvalds   Merge branch 'lin...
2431

02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2432
2433
2434
  	amd_iommu_detected = true;
  	iommu_detected = 1;
  	x86_init.iommu.iommu_init = amd_iommu_init;
4781bc427   Jérôme Glisse   iommu/amd: Return...
2435
  	return 1;
ae7877de9   Joerg Roedel   x86, AMD IOMMU: a...
2436
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2437
2438
2439
2440
2441
2442
  /****************************************************************************
   *
   * Parsing functions for the AMD IOMMU specific kernel command line
   * options.
   *
   ****************************************************************************/
fefda117d   Joerg Roedel   amd-iommu: add am...
2443
2444
2445
2446
2447
2448
  static int __init parse_amd_iommu_dump(char *str)
  {
  	amd_iommu_dump = true;
  
  	return 1;
  }
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
  static int __init parse_amd_iommu_intr(char *str)
  {
  	for (; *str; ++str) {
  		if (strncmp(str, "legacy", 6) == 0) {
  			amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
  			break;
  		}
  		if (strncmp(str, "vapic", 5) == 0) {
  			amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC;
  			break;
  		}
  	}
  	return 1;
  }
918ad6c54   Joerg Roedel   x86, AMD IOMMU: a...
2463
2464
2465
  static int __init parse_amd_iommu_options(char *str)
  {
  	for (; *str; ++str) {
695b5676c   Joerg Roedel   AMD IOMMU: fix fu...
2466
  		if (strncmp(str, "fullflush", 9) == 0)
afa9fdc2f   FUJITA Tomonori   iommu: remove ful...
2467
  			amd_iommu_unmap_flush = true;
a52357259   Joerg Roedel   x86/amd-iommu: Ad...
2468
2469
  		if (strncmp(str, "off", 3) == 0)
  			amd_iommu_disabled = true;
5abcdba4f   Joerg Roedel   iommu/amd: Put IO...
2470
2471
  		if (strncmp(str, "force_isolation", 15) == 0)
  			amd_iommu_force_isolation = true;
918ad6c54   Joerg Roedel   x86, AMD IOMMU: a...
2472
2473
2474
2475
  	}
  
  	return 1;
  }
440e89980   Joerg Roedel   iommu/amd: Add io...
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
  static int __init parse_ivrs_ioapic(char *str)
  {
  	unsigned int bus, dev, fn;
  	int ret, id, i;
  	u16 devid;
  
  	ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn);
  
  	if (ret != 4) {
  		pr_err("AMD-Vi: Invalid command line: ivrs_ioapic%s
  ", str);
  		return 1;
  	}
  
  	if (early_ioapic_map_size == EARLY_MAP_SIZE) {
  		pr_err("AMD-Vi: Early IOAPIC map overflow - ignoring ivrs_ioapic%s
  ",
  			str);
  		return 1;
  	}
  
  	devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2498
  	cmdline_maps			= true;
440e89980   Joerg Roedel   iommu/amd: Add io...
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
  	i				= early_ioapic_map_size++;
  	early_ioapic_map[i].id		= id;
  	early_ioapic_map[i].devid	= devid;
  	early_ioapic_map[i].cmd_line	= true;
  
  	return 1;
  }
  
  static int __init parse_ivrs_hpet(char *str)
  {
  	unsigned int bus, dev, fn;
  	int ret, id, i;
  	u16 devid;
  
  	ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn);
  
  	if (ret != 4) {
  		pr_err("AMD-Vi: Invalid command line: ivrs_hpet%s
  ", str);
  		return 1;
  	}
  
  	if (early_hpet_map_size == EARLY_MAP_SIZE) {
  		pr_err("AMD-Vi: Early HPET map overflow - ignoring ivrs_hpet%s
  ",
  			str);
  		return 1;
  	}
  
  	devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2529
  	cmdline_maps			= true;
440e89980   Joerg Roedel   iommu/amd: Add io...
2530
2531
2532
2533
2534
2535
2536
  	i				= early_hpet_map_size++;
  	early_hpet_map[i].id		= id;
  	early_hpet_map[i].devid		= devid;
  	early_hpet_map[i].cmd_line	= true;
  
  	return 1;
  }
ca3bf5d47   Suravee Suthikulpanit   iommu/amd: Introd...
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
  static int __init parse_ivrs_acpihid(char *str)
  {
  	u32 bus, dev, fn;
  	char *hid, *uid, *p;
  	char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0};
  	int ret, i;
  
  	ret = sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid);
  	if (ret != 4) {
  		pr_err("AMD-Vi: Invalid command line: ivrs_acpihid(%s)
  ", str);
  		return 1;
  	}
  
  	p = acpiid;
  	hid = strsep(&p, ":");
  	uid = p;
  
  	if (!hid || !(*hid) || !uid) {
  		pr_err("AMD-Vi: Invalid command line: hid or uid
  ");
  		return 1;
  	}
  
  	i = early_acpihid_map_size++;
  	memcpy(early_acpihid_map[i].hid, hid, strlen(hid));
  	memcpy(early_acpihid_map[i].uid, uid, strlen(uid));
  	early_acpihid_map[i].devid =
  		((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
  	early_acpihid_map[i].cmd_line	= true;
  
  	return 1;
  }
440e89980   Joerg Roedel   iommu/amd: Add io...
2570
2571
  __setup("amd_iommu_dump",	parse_amd_iommu_dump);
  __setup("amd_iommu=",		parse_amd_iommu_options);
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
2572
  __setup("amd_iommu_intr=",	parse_amd_iommu_intr);
440e89980   Joerg Roedel   iommu/amd: Add io...
2573
2574
  __setup("ivrs_ioapic",		parse_ivrs_ioapic);
  __setup("ivrs_hpet",		parse_ivrs_hpet);
ca3bf5d47   Suravee Suthikulpanit   iommu/amd: Introd...
2575
  __setup("ivrs_acpihid",		parse_ivrs_acpihid);
22e6daf41   Konrad Rzeszutek Wilk   x86, GART/AMD-VI:...
2576
2577
2578
  
  IOMMU_INIT_FINISH(amd_iommu_detect,
  		  gart_iommu_hole_init,
98f1ad258   Joerg Roedel   iommu/amd: Fix sp...
2579
2580
  		  NULL,
  		  NULL);
400a28a05   Joerg Roedel   iommu/amd: Add io...
2581
2582
2583
2584
2585
2586
  
  bool amd_iommu_v2_supported(void)
  {
  	return amd_iommu_v2_present;
  }
  EXPORT_SYMBOL(amd_iommu_v2_supported);
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
  
  /****************************************************************************
   *
   * IOMMU EFR Performance Counter support functionality. This code allows
   * access to the IOMMU PC functionality.
   *
   ****************************************************************************/
  
  u8 amd_iommu_pc_get_max_banks(u16 devid)
  {
  	struct amd_iommu *iommu;
  	u8 ret = 0;
  
  	/* locate the iommu governing the devid */
  	iommu = amd_iommu_rlookup_table[devid];
  	if (iommu)
  		ret = iommu->max_banks;
  
  	return ret;
  }
  EXPORT_SYMBOL(amd_iommu_pc_get_max_banks);
  
  bool amd_iommu_pc_supported(void)
  {
  	return amd_iommu_pc_present;
  }
  EXPORT_SYMBOL(amd_iommu_pc_supported);
  
  u8 amd_iommu_pc_get_max_counters(u16 devid)
  {
  	struct amd_iommu *iommu;
  	u8 ret = 0;
  
  	/* locate the iommu governing the devid */
  	iommu = amd_iommu_rlookup_table[devid];
  	if (iommu)
  		ret = iommu->max_counters;
  
  	return ret;
  }
  EXPORT_SYMBOL(amd_iommu_pc_get_max_counters);
38e45d02e   Suravee Suthikulpanit   iommu/amd: Fix bo...
2628
2629
  static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
  				    u8 bank, u8 cntr, u8 fxn,
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
2630
2631
  				    u64 *value, bool is_write)
  {
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
2632
2633
  	u32 offset;
  	u32 max_offset_lim;
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
2634
  	/* Check for valid iommu and pc register indexing */
38e45d02e   Suravee Suthikulpanit   iommu/amd: Fix bo...
2635
  	if (WARN_ON((fxn > 0x28) || (fxn & 7)))
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
  		return -ENODEV;
  
  	offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn);
  
  	/* Limit the offset to the hw defined mmio region aperture */
  	max_offset_lim = (u32)(((0x40|iommu->max_banks) << 12) |
  				(iommu->max_counters << 8) | 0x28);
  	if ((offset < MMIO_CNTR_REG_OFFSET) ||
  	    (offset > max_offset_lim))
  		return -EINVAL;
  
  	if (is_write) {
  		writel((u32)*value, iommu->mmio_base + offset);
  		writel((*value >> 32), iommu->mmio_base + offset + 4);
  	} else {
  		*value = readl(iommu->mmio_base + offset + 4);
  		*value <<= 32;
  		*value = readl(iommu->mmio_base + offset);
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val);
38e45d02e   Suravee Suthikulpanit   iommu/amd: Fix bo...
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
  
  int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
  				    u64 *value, bool is_write)
  {
  	struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
  
  	/* Make sure the IOMMU PC resource is available */
  	if (!amd_iommu_pc_present || iommu == NULL)
  		return -ENODEV;
  
  	return iommu_pc_get_set_reg_val(iommu, bank, cntr, fxn,
  					value, is_write);
  }