Blame view

drivers/iommu/amd_iommu_init.c 67.2 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>
ebcfa2843   Lucas Stach   iommu/amd: Tell k...
31
  #include <linux/kmemleak.h>
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
32
  #include <asm/pci-direct.h>
46a7fa270   FUJITA Tomonori   x86: make only GA...
33
  #include <asm/iommu.h>
1d9b16d16   Joerg Roedel   x86: move GART sp...
34
  #include <asm/gart.h>
ea1b0d394   FUJITA Tomonori   x86: amd_iommu: C...
35
  #include <asm/x86_init.h>
22e6daf41   Konrad Rzeszutek Wilk   x86, GART/AMD-VI:...
36
  #include <asm/iommu_table.h>
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
37
  #include <asm/io_apic.h>
6b474b822   Joerg Roedel   iommu/amd: Add in...
38
  #include <asm/irq_remapping.h>
403f81d8e   Joerg Roedel   iommu/amd: Move m...
39
40
41
  
  #include "amd_iommu_proto.h"
  #include "amd_iommu_types.h"
05152a049   Joerg Roedel   iommu/amd: Add sl...
42
  #include "irq_remapping.h"
403f81d8e   Joerg Roedel   iommu/amd: Move m...
43

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

8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
49
  #define ACPI_IVHD_TYPE_MAX_SUPPORTED	0x40
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
50
51
52
53
54
55
56
57
58
59
60
61
  #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...
62
  #define IVHD_DEV_SPECIAL		0x48
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
63
  #define IVHD_DEV_ACPI_HID		0xf0
6efed63be   Joerg Roedel   iommu/amd: Keep t...
64

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

6da7342ff   Joerg Roedel   amd-iommu: fix io...
71
72
73
74
  #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...
75
76
77
78
79
80
81
82
83
84
85
86
  
  #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...
87
  #define LOOP_TIMEOUT	100000
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
88
89
90
91
92
93
94
95
96
97
98
  /*
   * 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...
99
100
101
102
103
104
105
106
107
  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...
108
109
110
111
112
  	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...
113
  } __attribute__((packed));
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
114
115
116
117
  /*
   * A device entry describing which devices a specific IOMMU translates and
   * which requestor ids they use.
   */
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
118
119
120
121
122
  struct ivhd_entry {
  	u8 type;
  	u16 devid;
  	u8 flags;
  	u32 ext;
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
123
124
125
126
127
  	u32 hidh;
  	u64 cid;
  	u8 uidf;
  	u8 uidl;
  	u8 uid;
f6e2e6b6f   Joerg Roedel   x86, AMD IOMMU: a...
128
  } __attribute__((packed));
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
129
130
131
132
  /*
   * 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...
133
134
135
136
137
138
139
140
141
142
  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...
143
  bool amd_iommu_dump;
05152a049   Joerg Roedel   iommu/amd: Add sl...
144
  bool amd_iommu_irq_remap __read_mostly;
fefda117d   Joerg Roedel   amd-iommu: add am...
145

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

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

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

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

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

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

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

5abcdba4f   Joerg Roedel   iommu/amd: Put IO...
173
  bool amd_iommu_force_isolation __read_mostly;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
174
  /*
aeb26f553   Joerg Roedel   x86/amd-iommu: Im...
175
176
177
178
179
180
   * 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...
181
182
183
184
185
   * 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...
186
  struct dev_table_entry *amd_iommu_dev_table;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
187
188
189
190
191
192
  
  /*
   * 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...
193
  u16 *amd_iommu_alias_table;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
194
195
196
197
198
  
  /*
   * 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...
199
  struct amd_iommu **amd_iommu_rlookup_table;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
200
201
  
  /*
0ea2c422b   Joerg Roedel   iommu/amd: Alloca...
202
203
204
205
206
207
   * 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...
208
   * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
209
210
   * to know which ones are already in use.
   */
928abd254   Joerg Roedel   x86, AMD IOMMU: a...
211
  unsigned long *amd_iommu_pd_alloc_bitmap;
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
212
213
214
  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...
215

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
216
217
218
219
220
221
222
223
224
225
226
227
  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...
228
229
230
231
  /* 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...
232
  static struct acpihid_map_entry __initdata early_acpihid_map[EARLY_MAP_SIZE];
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
233
234
  static int __initdata early_ioapic_map_size;
  static int __initdata early_hpet_map_size;
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
235
  static int __initdata early_acpihid_map_size;
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
236
  static bool __initdata cmdline_maps;
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
237

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

38e45d02e   Suravee Suthikulpanit   iommu/amd: Fix bo...
243
244
245
  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...
246
247
248
249
250
  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...
251
252
253
  static inline unsigned long tbl_size(int entry_size)
  {
  	unsigned shift = PAGE_SHIFT +
421f909c8   Neil Turton   amd-iommu: fix an...
254
  			 get_order(((int)amd_iommu_last_bdf + 1) * entry_size);
c571484e5   Joerg Roedel   x86, AMD IOMMU: r...
255
256
257
  
  	return 1UL << shift;
  }
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
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
289
  /* 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...
290
291
292
293
294
295
296
297
  /****************************************************************************
   *
   * 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...
298

b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
299
300
301
302
  /*
   * 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...
303
  static void iommu_set_exclusion_range(struct amd_iommu *iommu)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  {
  	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...
320
  /* Programs the physical address of the device table into the IOMMU hardware */
6b7f000eb   Jan Beulich   x86/amd: iommu_se...
321
  static void iommu_set_device_table(struct amd_iommu *iommu)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
322
  {
f609891f4   Andreas Herrmann   amd_iommu: fix na...
323
  	u64 entry;
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
324
325
326
327
328
329
330
331
  
  	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...
332
  /* Generic functions to enable/disable certain features of the IOMMU. */
05f92db9f   Joerg Roedel   amd_iommu: un __i...
333
  static void iommu_feature_enable(struct amd_iommu *iommu, u8 bit)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
334
335
336
337
338
339
340
  {
  	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...
341
  static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
342
343
  {
  	u32 ctrl;
199d0d501   Joerg Roedel   AMD IOMMU: remove...
344
  	ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
345
346
347
  	ctrl &= ~(1 << bit);
  	writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET);
  }
1456e9d2c   Joerg Roedel   iommu/amd: Set IO...
348
349
350
351
352
353
354
355
356
  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...
357
  /* Function to enable the hardware */
05f92db9f   Joerg Roedel   amd_iommu: un __i...
358
  static void iommu_enable(struct amd_iommu *iommu)
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
359
  {
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
360
  	iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
b2026aa2d   Joerg Roedel   x86, AMD IOMMU: a...
361
  }
92ac4320a   Joerg Roedel   amd-iommu: add fu...
362
  static void iommu_disable(struct amd_iommu *iommu)
126c52be4   Joerg Roedel   AMD IOMMU: enable...
363
  {
a8c485bb6   Chris Wright   amd-iommu: disabl...
364
365
366
367
368
369
  	/* 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...
370
371
372
  	/* Disable IOMMU GA_LOG */
  	iommu_feature_disable(iommu, CONTROL_GALOG_EN);
  	iommu_feature_disable(iommu, CONTROL_GAINT_EN);
a8c485bb6   Chris Wright   amd-iommu: disabl...
373
  	/* Disable IOMMU hardware itself */
92ac4320a   Joerg Roedel   amd-iommu: add fu...
374
  	iommu_feature_disable(iommu, CONTROL_IOMMU_EN);
126c52be4   Joerg Roedel   AMD IOMMU: enable...
375
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
376
377
378
379
  /*
   * 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...
380
  static u8 __iomem * __init iommu_map_mmio_space(u64 address, u64 end)
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
381
  {
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
382
383
384
385
  	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...
386
387
  		pr_err("AMD-Vi: This is a BIOS bug. Please contact your hardware vendor
  ");
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
388
  		return NULL;
e82752d8b   Joerg Roedel   x86/amd-iommu: Fi...
389
  	}
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
390

30861ddc9   Steven L Kinney   perf/x86/amd: Add...
391
  	return (u8 __iomem *)ioremap_nocache(address, end);
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
392
393
394
395
396
397
  }
  
  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...
398
  	release_mem_region(iommu->mmio_phys, iommu->mmio_phys_end);
6c56747b4   Joerg Roedel   x86, AMD IOMMU: a...
399
  }
ac7ccf676   Suravee Suthikulpanit   iommu/amd: Modify...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
  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...
415
416
417
418
419
420
421
422
423
424
  /****************************************************************************
   *
   * 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...
425
426
427
428
   * 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...
429
430
431
432
433
434
435
436
437
  	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...
438
439
440
  }
  
  /*
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
441
442
443
   * 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...
444
445
446
447
  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...
448
449
450
451
452
453
454
455
456
  	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...
457
  	end += h->length;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
458
459
460
  	while (p < end) {
  		dev = (struct ivhd_entry *)p;
  		switch (dev->type) {
d12594169   Joerg Roedel   iommu/amd: Initia...
461
462
463
464
  		case IVHD_DEV_ALL:
  			/* Use maximum BDF value for DEV_ALL */
  			update_last_devid(0xffff);
  			break;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
465
466
467
468
  		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...
469
  			/* all the above subfield types refer to device ids */
208ec8c94   Joerg Roedel   x86, AMD IOMMU: r...
470
  			update_last_devid(dev->devid);
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
471
472
473
474
  			break;
  		default:
  			break;
  		}
b514e5556   Joerg Roedel   AMD IOMMU: calcul...
475
  		p += ivhd_entry_length(p);
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
476
477
478
479
480
481
  	}
  
  	WARN_ON(p != end);
  
  	return 0;
  }
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  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...
498
499
500
501
502
  /*
   * 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...
503
504
  static int __init find_last_devid_acpi(struct acpi_table_header *table)
  {
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
505
  	u8 *p = (u8 *)table, *end = (u8 *)table;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
506
  	struct ivhd_header *h;
3e8064ba5   Joerg Roedel   x86, AMD IOMMU: a...
507
508
509
510
511
  	p += IVRS_HEADER_LENGTH;
  
  	end += table->length;
  	while (p < end) {
  		h = (struct ivhd_header *)p;
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
512
513
514
515
516
  		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...
517
518
519
520
521
522
523
  		}
  		p += h->length;
  	}
  	WARN_ON(p != end);
  
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
524
525
  /****************************************************************************
   *
df805abb2   Frank Arnold   iommu/amd: Fix so...
526
   * The following functions belong to the code path which parses the ACPI table
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
527
528
529
530
531
532
533
534
535
536
537
   * 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...
538
  static int __init alloc_command_buffer(struct amd_iommu *iommu)
b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
539
  {
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
540
541
  	iommu->cmd_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
  						  get_order(CMD_BUFFER_SIZE));
b36ca91e1   Joerg Roedel   x86, AMD IOMMU: a...
542

f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
543
  	return iommu->cmd_buf ? 0 : -ENOMEM;
58492e128   Joerg Roedel   amd-iommu: consol...
544
545
546
  }
  
  /*
93f1cc67c   Joerg Roedel   x86/amd-iommu: Ad...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
   * 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...
561
562
563
564
565
566
567
568
569
570
   * 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...
571
  	entry |= MMIO_CMD_SIZE_512;
58492e128   Joerg Roedel   amd-iommu: consol...
572

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

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

f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
589
  	return iommu->evt_buf ? 0 : -ENOMEM;
58492e128   Joerg Roedel   amd-iommu: consol...
590
591
592
593
594
595
596
  }
  
  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...
597
  	entry = (u64)virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK;
58492e128   Joerg Roedel   amd-iommu: consol...
598

335503e57   Joerg Roedel   AMD IOMMU: add ev...
599
600
  	memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
  		    &entry, sizeof(entry));
09067207f   Joerg Roedel   amd-iommu: set ev...
601
602
603
  	/* 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...
604
  	iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
335503e57   Joerg Roedel   AMD IOMMU: add ev...
605
606
607
608
609
610
  }
  
  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 ...
611
  /* allocates the memory where the IOMMU will log its events to */
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
612
  static int __init alloc_ppr_log(struct amd_iommu *iommu)
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
613
  {
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
614
615
  	iommu->ppr_log = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
  						  get_order(PPR_LOG_SIZE));
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
616

f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
617
  	return iommu->ppr_log ? 0 : -ENOMEM;
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
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
646
  }
  
  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...
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
738
  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...
739
740
741
742
743
744
745
  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...
746
  /* sets a specific bit in the device table entry. */
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
747
748
  static void set_dev_entry_bit(u16 devid, u8 bit)
  {
ee6c28684   Joerg Roedel   iommu/amd: Conver...
749
750
  	int i = (bit >> 6) & 0x03;
  	int _bit = bit & 0x3f;
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
751

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

ee6c28684   Joerg Roedel   iommu/amd: Conver...
759
  	return (amd_iommu_dev_table[devid].data[i] & (1UL << _bit)) >> _bit;
c5cca146a   Joerg Roedel   x86/amd-iommu: Wo...
760
761
762
763
764
765
766
767
768
769
770
771
772
  }
  
  
  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...
773
774
775
776
777
  /* 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...
778
779
780
781
  /*
   * 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...
782
783
  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...
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
  {
  	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...
799

c5cca146a   Joerg Roedel   x86/amd-iommu: Wo...
800
  	amd_iommu_apply_erratum_63(devid);
5ff4789d0   Joerg Roedel   AMD IOMMU: set io...
801
  	set_iommu_for_device(iommu, devid);
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
802
  }
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
803
  static int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line)
6efed63be   Joerg Roedel   iommu/amd: Keep t...
804
805
806
  {
  	struct devid_map *entry;
  	struct list_head *list;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
807
808
809
810
811
  	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...
812
  		return -EINVAL;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
813
814
815
816
817
818
819
  	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...
820
  		*devid = entry->devid;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
821
822
  		return 0;
  	}
6efed63be   Joerg Roedel   iommu/amd: Keep t...
823
824
825
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  	if (!entry)
  		return -ENOMEM;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
826
  	entry->id	= id;
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
827
  	entry->devid	= *devid;
31cff67f6   Joerg Roedel   iommu/amd: Extend...
828
  	entry->cmd_line	= cmd_line;
6efed63be   Joerg Roedel   iommu/amd: Keep t...
829
830
831
832
833
  
  	list_add_tail(&entry->list, list);
  
  	return 0;
  }
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
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
870
  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...
871
872
873
874
875
876
877
  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...
878
  					 &early_ioapic_map[i].devid,
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
879
880
881
882
883
884
885
886
  					 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...
887
  					 &early_hpet_map[i].devid,
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
888
889
890
891
  					 early_hpet_map[i].cmd_line);
  		if (ret)
  			return ret;
  	}
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
892
893
894
895
896
897
898
899
  	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...
900
901
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
902
  /*
df805abb2   Frank Arnold   iommu/amd: Fix so...
903
   * Reads the device exclusion range from ACPI and initializes the IOMMU with
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
904
905
   * it
   */
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
906
907
908
909
910
911
912
913
  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...
914
915
916
917
918
  		/*
  		 * 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...
919
  		set_dev_entry_bit(devid, DEV_ENTRY_EX);
3566b7786   Joerg Roedel   x86, AMD IOMMU: a...
920
921
922
923
  		iommu->exclusion_start = m->range_start;
  		iommu->exclusion_length = m->range_length;
  	}
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
924
  /*
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
925
926
927
   * 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...
928
  static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
929
930
931
932
  					struct ivhd_header *h)
  {
  	u8 *p = (u8 *)h;
  	u8 *end = p, flags = 0;
0de66d5b3   Joerg Roedel   x86/amd-iommu: Fi...
933
934
  	u16 devid = 0, devid_start = 0, devid_to = 0;
  	u32 dev_i, ext_flags = 0;
58a3bee56   Joerg Roedel   x86, AMD IOMMU: u...
935
  	bool alias = false;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
936
  	struct ivhd_entry *e;
ac7ccf676   Suravee Suthikulpanit   iommu/amd: Modify...
937
  	u32 ivhd_size;
235dacbc7   Joerg Roedel   iommu/amd: Add ea...
938
939
940
941
942
943
  	int ret;
  
  
  	ret = add_early_maps();
  	if (ret)
  		return ret;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
944
945
  
  	/*
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
946
  	 * First save the recommended feature enable bits from ACPI
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
947
  	 */
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
948
  	iommu->acpi_flags = h->flags;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
949
950
951
952
  
  	/*
  	 * Done. Now parse the device entries
  	 */
ac7ccf676   Suravee Suthikulpanit   iommu/amd: Modify...
953
954
955
956
957
958
959
960
  	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...
961
  	end += h->length;
42a698f40   Joerg Roedel   amd-iommu: print ...
962

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

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

226e889b2   Joerg Roedel   iommu/amd: Remove...
971
972
  			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...
973
974
  			break;
  		case IVHD_DEV_SELECT:
42a698f40   Joerg Roedel   amd-iommu: print ...
975
976
977
978
  
  			DUMP_printk("  DEV_SELECT\t\t\t devid: %02x:%02x.%x "
  				    "flags: %02x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
979
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
980
981
982
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
983
  			devid = e->devid;
5ff4789d0   Joerg Roedel   AMD IOMMU: set io...
984
  			set_dev_entry_from_acpi(iommu, devid, e->flags, 0);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
985
986
  			break;
  		case IVHD_DEV_SELECT_RANGE_START:
42a698f40   Joerg Roedel   amd-iommu: print ...
987
988
989
990
  
  			DUMP_printk("  DEV_SELECT_RANGE_START\t "
  				    "devid: %02x:%02x.%x flags: %02x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
991
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
992
993
994
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
995
996
997
  			devid_start = e->devid;
  			flags = e->flags;
  			ext_flags = 0;
58a3bee56   Joerg Roedel   x86, AMD IOMMU: u...
998
  			alias = false;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
999
1000
  			break;
  		case IVHD_DEV_ALIAS:
42a698f40   Joerg Roedel   amd-iommu: print ...
1001
1002
1003
1004
  
  			DUMP_printk("  DEV_ALIAS\t\t\t devid: %02x:%02x.%x "
  				    "flags: %02x devid_to: %02x:%02x.%x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1005
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1006
1007
1008
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags,
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1009
  				    PCI_BUS_NUM(e->ext >> 8),
42a698f40   Joerg Roedel   amd-iommu: print ...
1010
1011
  				    PCI_SLOT(e->ext >> 8),
  				    PCI_FUNC(e->ext >> 8));
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1012
1013
  			devid = e->devid;
  			devid_to = e->ext >> 8;
7a6a3a086   Joerg Roedel   amd-iommu: handle...
1014
  			set_dev_entry_from_acpi(iommu, devid   , e->flags, 0);
7455aab1f   Neil Turton   amd-iommu: fix th...
1015
  			set_dev_entry_from_acpi(iommu, devid_to, e->flags, 0);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1016
1017
1018
  			amd_iommu_alias_table[devid] = devid_to;
  			break;
  		case IVHD_DEV_ALIAS_RANGE:
42a698f40   Joerg Roedel   amd-iommu: print ...
1019
1020
1021
1022
1023
  
  			DUMP_printk("  DEV_ALIAS_RANGE\t\t "
  				    "devid: %02x:%02x.%x flags: %02x "
  				    "devid_to: %02x:%02x.%x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1024
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1025
1026
1027
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags,
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1028
  				    PCI_BUS_NUM(e->ext >> 8),
42a698f40   Joerg Roedel   amd-iommu: print ...
1029
1030
  				    PCI_SLOT(e->ext >> 8),
  				    PCI_FUNC(e->ext >> 8));
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1031
1032
1033
1034
  			devid_start = e->devid;
  			flags = e->flags;
  			devid_to = e->ext >> 8;
  			ext_flags = 0;
58a3bee56   Joerg Roedel   x86, AMD IOMMU: u...
1035
  			alias = true;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1036
1037
  			break;
  		case IVHD_DEV_EXT_SELECT:
42a698f40   Joerg Roedel   amd-iommu: print ...
1038
1039
1040
1041
  
  			DUMP_printk("  DEV_EXT_SELECT\t\t devid: %02x:%02x.%x "
  				    "flags: %02x ext: %08x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1042
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1043
1044
1045
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags, e->ext);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1046
  			devid = e->devid;
5ff4789d0   Joerg Roedel   AMD IOMMU: set io...
1047
1048
  			set_dev_entry_from_acpi(iommu, devid, e->flags,
  						e->ext);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1049
1050
  			break;
  		case IVHD_DEV_EXT_SELECT_RANGE:
42a698f40   Joerg Roedel   amd-iommu: print ...
1051
1052
1053
1054
  
  			DUMP_printk("  DEV_EXT_SELECT_RANGE\t devid: "
  				    "%02x:%02x.%x flags: %02x ext: %08x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1055
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1056
1057
1058
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid),
  				    e->flags, e->ext);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1059
1060
1061
  			devid_start = e->devid;
  			flags = e->flags;
  			ext_flags = e->ext;
58a3bee56   Joerg Roedel   x86, AMD IOMMU: u...
1062
  			alias = false;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1063
1064
  			break;
  		case IVHD_DEV_RANGE_END:
42a698f40   Joerg Roedel   amd-iommu: print ...
1065
1066
1067
  
  			DUMP_printk("  DEV_RANGE_END\t\t devid: %02x:%02x.%x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1068
  				    PCI_BUS_NUM(e->devid),
42a698f40   Joerg Roedel   amd-iommu: print ...
1069
1070
  				    PCI_SLOT(e->devid),
  				    PCI_FUNC(e->devid));
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1071
1072
  			devid = e->devid;
  			for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
7a6a3a086   Joerg Roedel   amd-iommu: handle...
1073
  				if (alias) {
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1074
  					amd_iommu_alias_table[dev_i] = devid_to;
7a6a3a086   Joerg Roedel   amd-iommu: handle...
1075
1076
1077
1078
1079
  					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...
1080
1081
  			}
  			break;
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
  		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...
1102
  				    PCI_BUS_NUM(devid),
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1103
1104
  				    PCI_SLOT(devid),
  				    PCI_FUNC(devid));
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
1105
  			ret = add_special_device(type, handle, &devid, false);
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1106
1107
  			if (ret)
  				return ret;
c50e3247a   Joerg Roedel   iommu/amd: Fix de...
1108
1109
1110
1111
1112
1113
1114
  
  			/*
  			 * 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...
1115
1116
  			break;
  		}
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
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
1160
  		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...
1161
  			devid = e->devid;
2a0cb4e2d   Wan Zongshun   iommu/amd: Add ne...
1162
1163
1164
1165
1166
1167
  			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...
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
  			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...
1183
1184
1185
  		default:
  			break;
  		}
b514e5556   Joerg Roedel   AMD IOMMU: calcul...
1186
  		p += ivhd_entry_length(p);
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1187
  	}
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1188
1189
  
  	return 0;
5d0c8e49f   Joerg Roedel   x86, AMD IOMMU: a...
1190
  }
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1191
1192
1193
  static void __init free_iommu_one(struct amd_iommu *iommu)
  {
  	free_command_buffer(iommu);
335503e57   Joerg Roedel   AMD IOMMU: add ev...
1194
  	free_event_buffer(iommu);
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
1195
  	free_ppr_log(iommu);
8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
1196
  	free_ga_log(iommu);
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1197
1198
1199
1200
1201
1202
  	iommu_unmap_mmio_space(iommu);
  }
  
  static void __init free_iommu_all(void)
  {
  	struct amd_iommu *iommu, *next;
3bd221724   Joerg Roedel   amd-iommu: introd...
1203
  	for_each_iommu_safe(iommu, next) {
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1204
1205
1206
1207
1208
  		list_del(&iommu->list);
  		free_iommu_one(iommu);
  		kfree(iommu);
  	}
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1209
  /*
318fe7825   Suravee Suthikulpanit   IOMMU, AMD Family...
1210
1211
1212
1213
1214
   * 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...
1215
  static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
318fe7825   Suravee Suthikulpanit   IOMMU, AMD Family...
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
1242
  {
  	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 ...
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
1271
   * 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...
1272
1273
1274
1275
   * 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...
1276
1277
  static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
  {
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1278
  	int ret;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1279
  	spin_lock_init(&iommu->lock);
bb52777ec   Joerg Roedel   x86/amd-iommu: Ad...
1280
1281
  
  	/* Add IOMMU to internal data structures */
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1282
  	list_add_tail(&iommu->list, &amd_iommu_list);
bb52777ec   Joerg Roedel   x86/amd-iommu: Ad...
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
  	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...
1293
1294
1295
1296
  
  	/*
  	 * Copy data from ACPI table entry to the iommu struct
  	 */
23c742db2   Joerg Roedel   iommu/amd: Split ...
1297
  	iommu->devid   = h->devid;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1298
  	iommu->cap_ptr = h->cap_ptr;
ee893c24e   Joerg Roedel   AMD IOMMU: save p...
1299
  	iommu->pci_seg = h->pci_seg;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1300
  	iommu->mmio_phys = h->mmio_phys;
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1301

7d7d38afb   Suravee Suthikulpanit   iommu/amd: Adding...
1302
1303
1304
1305
1306
1307
1308
1309
1310
  	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...
1311
1312
  		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...
1313
1314
1315
1316
1317
1318
1319
  		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...
1320
1321
  		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...
1322
1323
1324
  		break;
  	default:
  		return -EINVAL;
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1325
1326
1327
1328
  	}
  
  	iommu->mmio_base = iommu_map_mmio_space(iommu->mmio_phys,
  						iommu->mmio_phys_end);
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1329
1330
  	if (!iommu->mmio_base)
  		return -ENOMEM;
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
1331
  	if (alloc_command_buffer(iommu))
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1332
  		return -ENOMEM;
f2c2db53b   Joerg Roedel   iommu/amd: Cleanu...
1333
  	if (alloc_event_buffer(iommu))
335503e57   Joerg Roedel   AMD IOMMU: add ev...
1334
  		return -ENOMEM;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1335
  	iommu->int_enabled = false;
6efed63be   Joerg Roedel   iommu/amd: Keep t...
1336
1337
1338
  	ret = init_iommu_from_acpi(iommu, h);
  	if (ret)
  		return ret;
f6fec00a9   Joerg Roedel   iommu/amd: Make s...
1339

7c71d306c   Jiang Liu   irq_remapping/amd...
1340
1341
1342
  	ret = amd_iommu_create_irq_domain(iommu);
  	if (ret)
  		return ret;
f6fec00a9   Joerg Roedel   iommu/amd: Make s...
1343
1344
1345
1346
1347
  	/*
  	 * 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 ...
1348
  	return 0;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1349
  }
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
  /**
   * 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...
1375
1376
1377
1378
  /*
   * 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...
1379
1380
1381
1382
1383
1384
  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...
1385
1386
1387
1388
1389
  	end += table->length;
  	p += IVRS_HEADER_LENGTH;
  
  	while (p < end) {
  		h = (struct ivhd_header *)p;
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
1390
  		if (*p == amd_iommu_target_ivhd_type) {
9c72041f7   Joerg Roedel   amd-iommu: add du...
1391

ae908c22a   Joerg Roedel   x86/amd-iommu: Re...
1392
  			DUMP_printk("device: %02x:%02x.%01x cap: %04x "
9c72041f7   Joerg Roedel   amd-iommu: add du...
1393
1394
  				    "seg: %d flags: %01x info %04x
  ",
c5081cd7a   Shuah Khan   iommu/amd: Remove...
1395
  				    PCI_BUS_NUM(h->devid), PCI_SLOT(h->devid),
9c72041f7   Joerg Roedel   amd-iommu: add du...
1396
1397
1398
1399
1400
  				    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...
1401
  			iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL);
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
1402
1403
  			if (iommu == NULL)
  				return -ENOMEM;
3551a708f   Joerg Roedel   x86/amd-iommu: Re...
1404

e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1405
  			ret = init_iommu_one(iommu, h);
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
1406
1407
  			if (ret)
  				return ret;
e47d402d2   Joerg Roedel   x86, AMD IOMMU: a...
1408
1409
1410
1411
1412
1413
1414
1415
  		}
  		p += h->length;
  
  	}
  	WARN_ON(p != end);
  
  	return 0;
  }
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
  
  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...
1427
1428
  	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...
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
  	    (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...
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
1477
  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...
1478

23c742db2   Joerg Roedel   iommu/amd: Split ...
1479
1480
1481
1482
  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...
1483
  	int ret;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1484

c5081cd7a   Shuah Khan   iommu/amd: Remove...
1485
  	iommu->dev = pci_get_bus_and_slot(PCI_BUS_NUM(iommu->devid),
23c742db2   Joerg Roedel   iommu/amd: Split ...
1486
1487
1488
  					  iommu->devid & 0xff);
  	if (!iommu->dev)
  		return -ENODEV;
cbbc00be2   Jiang Liu   iommu/amd: Preven...
1489
1490
  	/* Prevent binding other PCI device drivers to IOMMU devices */
  	iommu->dev->match_driver = false;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1491
1492
1493
1494
1495
1496
  	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 ...
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  	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...
1508
1509
  		u32 max_pasid;
  		u64 pasmax;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1510

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

a919a018c   Suravee Suthikulpanit   iommu/amd: Fix lo...
1515
1516
1517
  		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 ...
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
  
  		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...
1533
1534
  	if (iommu_feature(iommu, FEATURE_PPR) && alloc_ppr_log(iommu))
  		return -ENOMEM;
23c742db2   Joerg Roedel   iommu/amd: Split ...
1535

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

23c742db2   Joerg Roedel   iommu/amd: Split ...
1540
1541
  	if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE))
  		amd_iommu_np_cache = true;
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1542
  	init_iommu_perf_ctr(iommu);
23c742db2   Joerg Roedel   iommu/amd: Split ...
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
1568
  	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...
1569
  	amd_iommu_erratum_746_workaround(iommu);
358875fd5   Jay Cornwall   iommu/amd: Apply ...
1570
  	amd_iommu_ats_write_check_workaround(iommu);
318fe7825   Suravee Suthikulpanit   IOMMU, AMD Family...
1571

066f2e98d   Alex Williamson   iommu/amd: Add sy...
1572
1573
1574
  	iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
  					       amd_iommu_groups, "ivhd%d",
  					       iommu->index);
23c742db2   Joerg Roedel   iommu/amd: Split ...
1575
1576
  	return pci_enable_device(iommu->dev);
  }
4d121c325   Joerg Roedel   iommu/amd: Move i...
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
  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...
1593
1594
1595
  			pr_info("AMD-Vi: Extended features (%#llx):
  ",
  				iommu->features);
2bd5ed002   Joerg Roedel   iommu/amd: Fix wr...
1596
  			for (i = 0; i < ARRAY_SIZE(feat_str); ++i) {
4d121c325   Joerg Roedel   iommu/amd: Move i...
1597
1598
1599
  				if (iommu_feature(iommu, (1ULL << i)))
  					pr_cont(" %s", feat_str[i]);
  			}
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1600
1601
1602
  
  			if (iommu->features & FEATURE_GAM_VAPIC)
  				pr_cont(" GA_vAPIC");
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
1603
1604
  			pr_cont("
  ");
500c25edd   Borislav Petkov   iommu/amd: Fix fe...
1605
  		}
4d121c325   Joerg Roedel   iommu/amd: Move i...
1606
  	}
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1607
  	if (irq_remapping_enabled) {
ebe60bbfd   Joerg Roedel   iommu/amd: Print ...
1608
1609
  		pr_info("AMD-Vi: Interrupt remapping enabled
  ");
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1610
1611
1612
1613
  		if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))
  			pr_info("AMD-Vi: virtual APIC enabled
  ");
  	}
4d121c325   Joerg Roedel   iommu/amd: Move i...
1614
  }
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
1615
  static int __init amd_iommu_init_pci(void)
23c742db2   Joerg Roedel   iommu/amd: Split ...
1616
1617
1618
1619
1620
1621
1622
1623
1624
  {
  	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...
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
  	/*
  	 * 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...
1636
1637
1638
1639
  	init_device_table_dma();
  
  	for_each_iommu(iommu)
  		iommu_flush_all_caches(iommu);
3a18404cd   Joerg Roedel   iommu/amd: Propag...
1640
1641
  	if (!ret)
  		print_iommu_info();
4d121c325   Joerg Roedel   iommu/amd: Move i...
1642

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

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

72fe00f01   Joerg Roedel   x86/amd-iommu: Us...
1661
1662
1663
1664
  	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...
1665
  				 iommu);
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1666
1667
1668
  
  	if (r) {
  		pci_disable_msi(iommu->dev);
9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1669
  		return r;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1670
  	}
fab6afa30   Joerg Roedel   amd-iommu: drop p...
1671
  	iommu->int_enabled = true;
1a29ac014   Joerg Roedel   iommu/amd: Setup ...
1672

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

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

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

9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1692
1693
  	if (iommu->ppr_log != NULL)
  		iommu_feature_enable(iommu, CONTROL_PPFINT_EN);
8bda0cfbd   Suravee Suthikulpanit   iommu/amd: Detect...
1694
  	iommu_ga_log_enable(iommu);
9ddd592a1   Joerg Roedel   iommu/amd: Make s...
1695
  	return 0;
a80dc3e0e   Joerg Roedel   AMD IOMMU: add MS...
1696
1697
1698
1699
  }
  
  /****************************************************************************
   *
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1700
1701
   * 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...
1702
   * gathered (like exclusion and unity mapping ranges).
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1703
1704
   *
   ****************************************************************************/
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1705
1706
1707
1708
1709
1710
1711
1712
1713
  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...
1714
  /* called when we find an exclusion range definition in ACPI */
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1715
1716
1717
1718
1719
1720
1721
1722
1723
  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...
1724
  		for (i = 0; i <= amd_iommu_last_bdf; ++i)
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
  			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...
1737
  /* called for unity map ACPI definition */
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1738
1739
  static int __init init_unity_map_range(struct ivmd_header *m)
  {
98f1ad258   Joerg Roedel   iommu/amd: Fix sp...
1740
  	struct unity_map_entry *e = NULL;
02acc43a2   Joerg Roedel   amd-iommu: print ...
1741
  	char *s;
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1742
1743
1744
1745
1746
1747
1748
  
  	e = kzalloc(sizeof(*e), GFP_KERNEL);
  	if (e == NULL)
  		return -ENOMEM;
  
  	switch (m->type) {
  	default:
0bc252f43   Joerg Roedel   amd-iommu: make s...
1749
1750
  		kfree(e);
  		return 0;
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1751
  	case ACPI_IVMD_TYPE:
02acc43a2   Joerg Roedel   amd-iommu: print ...
1752
  		s = "IVMD_TYPEi\t\t\t";
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1753
1754
1755
  		e->devid_start = e->devid_end = m->devid;
  		break;
  	case ACPI_IVMD_TYPE_ALL:
02acc43a2   Joerg Roedel   amd-iommu: print ...
1756
  		s = "IVMD_TYPE_ALL\t\t";
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1757
1758
1759
1760
  		e->devid_start = 0;
  		e->devid_end = amd_iommu_last_bdf;
  		break;
  	case ACPI_IVMD_TYPE_RANGE:
02acc43a2   Joerg Roedel   amd-iommu: print ...
1761
  		s = "IVMD_TYPE_RANGE\t\t";
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1762
1763
1764
1765
1766
1767
1768
  		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 ...
1769
1770
1771
  	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...
1772
1773
  		    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 ...
1774
1775
  		    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...
1776
1777
1778
1779
  	list_add_tail(&e->list, &amd_iommu_unity_map);
  
  	return 0;
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1780
  /* iterates over all memory definitions we find in the ACPI table */
be2a022c0   Joerg Roedel   x86, AMD IOMMU: a...
1781
1782
1783
1784
  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...
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
  	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...
1800
  /*
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1801
1802
1803
   * Init the device table to not allow DMA access for devices and
   * suppress all page faults
   */
33f28c59e   Joerg Roedel   iommu/amd: Split ...
1804
  static void init_device_table_dma(void)
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1805
  {
0de66d5b3   Joerg Roedel   x86/amd-iommu: Fi...
1806
  	u32 devid;
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1807
1808
1809
1810
  
  	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...
1811
1812
  	}
  }
d04e0ba34   Joerg Roedel   iommu/amd: Make s...
1813
1814
1815
1816
1817
1818
1819
1820
1821
  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 ...
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
  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...
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
  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...
1854
1855
1856
  
  	/* Set IOTLB invalidation timeout to 1s */
  	iommu_set_inv_tlb_timeout(iommu, CTRL_INV_TO_1S);
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
1857
  }
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1858
  static void iommu_apply_resume_quirks(struct amd_iommu *iommu)
4c894f47b   Joerg Roedel   x86/amd-iommu: Wo...
1859
  {
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1860
1861
  	int i, j;
  	u32 ioc_feature_control;
c1bf94ec1   Joerg Roedel   iommu/amd: Cache ...
1862
  	struct pci_dev *pdev = iommu->root_pdev;
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1863
1864
  
  	/* RD890 BIOSes may not have completely reconfigured the iommu */
c1bf94ec1   Joerg Roedel   iommu/amd: Cache ...
1865
  	if (!is_rd890_iommu(iommu->dev) || !pdev)
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1866
1867
1868
1869
1870
1871
  		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...
1872
1873
1874
1875
1876
1877
1878
1879
  
  	/* 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...
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
  	/* 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...
1898
  }
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1899
1900
1901
1902
1903
1904
1905
1906
1907
  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...
1908
  		iommu->irte_ops = &irte_128_ops;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1909
1910
  		break;
  	default:
77bdab46f   Suravee Suthikulpanit   iommu/amd: Add su...
1911
  		iommu->irte_ops = &irte_32_ops;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1912
1913
1914
1915
  		break;
  	}
  #endif
  }
9f5f5fb35   Joerg Roedel   x86, AMD IOMMU: i...
1916
  /*
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
1917
1918
1919
   * This function finally enables all IOMMUs found in the system after
   * they have been initialized
   */
11ee5ac47   Joerg Roedel   iommu/amd: Split ...
1920
  static void early_enable_iommus(void)
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1921
1922
  {
  	struct amd_iommu *iommu;
3bd221724   Joerg Roedel   amd-iommu: introd...
1923
  	for_each_iommu(iommu) {
a8c485bb6   Chris Wright   amd-iommu: disabl...
1924
  		iommu_disable(iommu);
e9bf51971   Joerg Roedel   x86/amd-iommu: Se...
1925
  		iommu_init_flags(iommu);
58492e128   Joerg Roedel   amd-iommu: consol...
1926
1927
1928
  		iommu_set_device_table(iommu);
  		iommu_enable_command_buffer(iommu);
  		iommu_enable_event_buffer(iommu);
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1929
  		iommu_set_exclusion_range(iommu);
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
1930
  		iommu_enable_ga(iommu);
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1931
  		iommu_enable(iommu);
7d0c5cc5b   Joerg Roedel   x86/amd-iommu: Fl...
1932
  		iommu_flush_all_caches(iommu);
8736197ba   Joerg Roedel   x86, AMD IOMMU: i...
1933
  	}
d98de49a5   Suravee Suthikulpanit   iommu/amd: Enable...
1934
1935
1936
1937
1938
  
  #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...
1939
  }
11ee5ac47   Joerg Roedel   iommu/amd: Split ...
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
  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...
1956
1957
1958
1959
1960
1961
  static void disable_iommus(void)
  {
  	struct amd_iommu *iommu;
  
  	for_each_iommu(iommu)
  		iommu_disable(iommu);
d98de49a5   Suravee Suthikulpanit   iommu/amd: Enable...
1962
1963
1964
1965
1966
  
  #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...
1967
  }
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1968
1969
1970
1971
  /*
   * Suspend/Resume support
   * disable suspend until real resume implemented
   */
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
1972
  static void amd_iommu_resume(void)
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1973
  {
5bcd757f9   Matthew Garrett   x86/amd-iommu: Re...
1974
1975
1976
1977
  	struct amd_iommu *iommu;
  
  	for_each_iommu(iommu)
  		iommu_apply_resume_quirks(iommu);
736501ee0   Joerg Roedel   amd-iommu: implem...
1978
1979
  	/* re-load the hardware */
  	enable_iommus();
3d9761e7a   Joerg Roedel   iommu/amd: Move i...
1980
1981
  
  	amd_iommu_enable_interrupts();
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1982
  }
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
1983
  static int amd_iommu_suspend(void)
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1984
  {
736501ee0   Joerg Roedel   amd-iommu: implem...
1985
1986
1987
1988
  	/* disable IOMMUs to go out of the way for BIOS */
  	disable_iommus();
  
  	return 0;
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1989
  }
f3c6ea1b0   Rafael J. Wysocki   x86: Use syscore_...
1990
  static struct syscore_ops amd_iommu_syscore_ops = {
7441e9cb1   Joerg Roedel   x86, AMD IOMMU: d...
1991
1992
1993
  	.suspend = amd_iommu_suspend,
  	.resume = amd_iommu_resume,
  };
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
1994
1995
  static void __init free_on_init_error(void)
  {
ebcfa2843   Lucas Stach   iommu/amd: Tell k...
1996
  	kmemleak_free(irq_lookup_table);
0ea2c422b   Joerg Roedel   iommu/amd: Alloca...
1997
1998
  	free_pages((unsigned long)irq_lookup_table,
  		   get_order(rlookup_table_size));
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
1999

a591989a7   Julia Lawall   iommu/amd: Drop n...
2000
2001
  	kmem_cache_destroy(amd_iommu_irq_cache);
  	amd_iommu_irq_cache = NULL;
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
  
  	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 ...
2013
2014
2015
2016
2017
2018
2019
2020
2021
  #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...
2022
2023
  /* 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 ...
2024
2025
  static bool __init check_ioapic_information(void)
  {
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2026
  	const char *fw_bug = FW_BUG;
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2027
  	bool ret, has_sb_ioapic;
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2028
  	int idx;
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2029
2030
  	has_sb_ioapic = false;
  	ret           = false;
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2031

dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2032
2033
2034
2035
2036
2037
2038
  	/*
  	 * 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...
2039
2040
2041
2042
2043
  	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 ...
2044
2045
2046
  			pr_err("%sAMD-Vi: IOAPIC[%d] not in IVRS table
  ",
  				fw_bug, id);
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2047
2048
2049
2050
  			ret = false;
  		} else if (devid == IOAPIC_SB_DEVID) {
  			has_sb_ioapic = true;
  			ret           = true;
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2051
2052
  		}
  	}
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2053
2054
2055
2056
2057
2058
2059
2060
2061
  	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 ...
2062
2063
  		pr_err("%sAMD-Vi: No southbridge IOAPIC found
  ", fw_bug);
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2064
2065
2066
  	}
  
  	if (!ret)
dfbb6d476   Joerg Roedel   iommu/amd: Don't ...
2067
2068
  		pr_err("AMD-Vi: Disabling interrupt remapping
  ");
c2ff5cf52   Joerg Roedel   iommu/amd: Work a...
2069
2070
  
  	return ret;
eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2071
  }
d04e0ba34   Joerg Roedel   iommu/amd: Make s...
2072
2073
  static void __init free_dma_resources(void)
  {
d04e0ba34   Joerg Roedel   iommu/amd: Make s...
2074
2075
2076
2077
2078
  	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...
2079
  /*
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2080
2081
2082
   * 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...
2083
2084
   *
   * This function basically parses the ACPI table for AMD IOMMU (IVRS)
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2085
   * four times:
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2086
   *
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2087
2088
2089
   *	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...
2090
2091
2092
   *		Upon this information the size of the data structures is
   *		determined that needs to be allocated.
   *
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2093
   *	3 pass) Initialize the data structures just allocated with the
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2094
2095
2096
2097
   *		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...
2098
   *	4 pass) After the basic data structures are allocated and
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2099
2100
2101
2102
   *		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 ...
2103
2104
   * 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...
2105
   */
643511b37   Joerg Roedel   iommu/amd: Introd...
2106
  static int __init early_amd_iommu_init(void)
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2107
  {
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2108
  	struct acpi_table_header *ivrs_base;
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2109
  	acpi_status status;
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
2110
  	int i, remap_cache_sz, ret = 0;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2111

643511b37   Joerg Roedel   iommu/amd: Introd...
2112
  	if (!amd_iommu_detected)
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2113
  		return -ENODEV;
6b11d1d67   Lv Zheng   ACPI / osl: Remov...
2114
  	status = acpi_get_table("IVRS", 0, &ivrs_base);
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2115
2116
2117
2118
2119
2120
2121
2122
  	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...
2123
  	/*
8c7142f56   Suravee Suthikulpanit   iommu/amd: Use th...
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
  	 * 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...
2136
2137
2138
2139
  	 * 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...
2140
2141
  	ret = find_last_devid_acpi(ivrs_base);
  	if (ret)
3551a708f   Joerg Roedel   x86/amd-iommu: Re...
2142
  		goto out;
c571484e5   Joerg Roedel   x86, AMD IOMMU: r...
2143
2144
2145
  	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...
2146

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

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

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

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

eb1eb7ae6   Joerg Roedel   iommu/amd: Check ...
2227
2228
  	/* init the device table */
  	init_device_table();
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2229
  out:
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2230
  	/* Don't leak any ACPI memory */
6b11d1d67   Lv Zheng   ACPI / osl: Remov...
2231
  	acpi_put_table(ivrs_base);
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2232
  	ivrs_base = NULL;
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2233
  	return ret;
643511b37   Joerg Roedel   iommu/amd: Introd...
2234
  }
ae295142d   Gerard Snitselaar   iommu/amd: Fix se...
2235
  static int amd_iommu_enable_interrupts(void)
3d9761e7a   Joerg Roedel   iommu/amd: Move i...
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
  {
  	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...
2249
2250
2251
  static bool detect_ivrs(void)
  {
  	struct acpi_table_header *ivrs_base;
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2252
  	acpi_status status;
6b11d1d67   Lv Zheng   ACPI / osl: Remov...
2253
  	status = acpi_get_table("IVRS", 0, &ivrs_base);
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2254
2255
2256
2257
2258
2259
2260
2261
  	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;
  	}
6b11d1d67   Lv Zheng   ACPI / osl: Remov...
2262
  	acpi_put_table(ivrs_base);
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2263

1adb7d31b   Joerg Roedel   iommu/amd: Fix pc...
2264
2265
  	/* Make sure ACS will be enabled during PCI probe */
  	pci_request_acs();
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2266
2267
  	return true;
  }
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2268
  /****************************************************************************
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2269
   *
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2270
2271
2272
2273
2274
   * AMD IOMMU Initialization State Machine
   *
   ****************************************************************************/
  
  static int __init state_next(void)
8704a1ba4   Joerg Roedel   iommu/amd: Split ...
2275
2276
  {
  	int ret = 0;
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
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
2305
  	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...
2306
  		ret = amd_iommu_init_dma_ops();
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
  		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...
2324

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

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

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2332
2333
2334
2335
2336
2337
  	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...
2338

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

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

3f4cb7c06   Thomas Gleixner   iommu/amd: Fix ir...
2348
2349
2350
2351
  	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...
2352
  }
d7f077697   Joerg Roedel   x86/amd-iommu: Fa...
2353

6b474b822   Joerg Roedel   iommu/amd: Add in...
2354
2355
2356
2357
2358
2359
2360
  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...
2361

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

6b474b822   Joerg Roedel   iommu/amd: Add in...
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
  	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...
2378

6b474b822   Joerg Roedel   iommu/amd: Add in...
2379
2380
2381
2382
2383
2384
  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...
2385

2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
  /*
   * 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...
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
  		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...
2408
2409
2410
  	}
  
  	return ret;
fe74c9cf3   Joerg Roedel   x86, AMD IOMMU: c...
2411
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2412
2413
2414
2415
2416
2417
2418
  /****************************************************************************
   *
   * 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 ...
2419
  int __init amd_iommu_detect(void)
ae7877de9   Joerg Roedel   x86, AMD IOMMU: a...
2420
  {
2c0ae1720   Joerg Roedel   iommu/amd: Conver...
2421
  	int ret;
02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2422

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

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

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

02f3b3f54   Joerg Roedel   iommu/amd: Use ac...
2433
2434
2435
  	amd_iommu_detected = true;
  	iommu_detected = 1;
  	x86_init.iommu.iommu_init = amd_iommu_init;
4781bc427   Jérôme Glisse   iommu/amd: Return...
2436
  	return 1;
ae7877de9   Joerg Roedel   x86, AMD IOMMU: a...
2437
  }
b65233a9c   Joerg Roedel   x86, AMD IOMMU: a...
2438
2439
2440
2441
2442
2443
  /****************************************************************************
   *
   * Parsing functions for the AMD IOMMU specific kernel command line
   * options.
   *
   ****************************************************************************/
fefda117d   Joerg Roedel   amd-iommu: add am...
2444
2445
2446
2447
2448
2449
  static int __init parse_amd_iommu_dump(char *str)
  {
  	amd_iommu_dump = true;
  
  	return 1;
  }
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
  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...
2464
2465
2466
  static int __init parse_amd_iommu_options(char *str)
  {
  	for (; *str; ++str) {
695b5676c   Joerg Roedel   AMD IOMMU: fix fu...
2467
  		if (strncmp(str, "fullflush", 9) == 0)
afa9fdc2f   FUJITA Tomonori   iommu: remove ful...
2468
  			amd_iommu_unmap_flush = true;
a52357259   Joerg Roedel   x86/amd-iommu: Ad...
2469
2470
  		if (strncmp(str, "off", 3) == 0)
  			amd_iommu_disabled = true;
5abcdba4f   Joerg Roedel   iommu/amd: Put IO...
2471
2472
  		if (strncmp(str, "force_isolation", 15) == 0)
  			amd_iommu_force_isolation = true;
918ad6c54   Joerg Roedel   x86, AMD IOMMU: a...
2473
2474
2475
2476
  	}
  
  	return 1;
  }
440e89980   Joerg Roedel   iommu/amd: Add io...
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
  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 ...
2499
  	cmdline_maps			= true;
440e89980   Joerg Roedel   iommu/amd: Add io...
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
2529
  	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 ...
2530
  	cmdline_maps			= true;
440e89980   Joerg Roedel   iommu/amd: Add io...
2531
2532
2533
2534
2535
2536
2537
  	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...
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
2570
  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...
2571
2572
  __setup("amd_iommu_dump",	parse_amd_iommu_dump);
  __setup("amd_iommu=",		parse_amd_iommu_options);
3928aa3f5   Suravee Suthikulpanit   iommu/amd: Detect...
2573
  __setup("amd_iommu_intr=",	parse_amd_iommu_intr);
440e89980   Joerg Roedel   iommu/amd: Add io...
2574
2575
  __setup("ivrs_ioapic",		parse_ivrs_ioapic);
  __setup("ivrs_hpet",		parse_ivrs_hpet);
ca3bf5d47   Suravee Suthikulpanit   iommu/amd: Introd...
2576
  __setup("ivrs_acpihid",		parse_ivrs_acpihid);
22e6daf41   Konrad Rzeszutek Wilk   x86, GART/AMD-VI:...
2577
2578
2579
  
  IOMMU_INIT_FINISH(amd_iommu_detect,
  		  gart_iommu_hole_init,
98f1ad258   Joerg Roedel   iommu/amd: Fix sp...
2580
2581
  		  NULL,
  		  NULL);
400a28a05   Joerg Roedel   iommu/amd: Add io...
2582
2583
2584
2585
2586
2587
  
  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...
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
2628
  
  /****************************************************************************
   *
   * 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...
2629
2630
  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...
2631
2632
  				    u64 *value, bool is_write)
  {
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
2633
2634
  	u32 offset;
  	u32 max_offset_lim;
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
2635
  	/* Check for valid iommu and pc register indexing */
38e45d02e   Suravee Suthikulpanit   iommu/amd: Fix bo...
2636
  	if (WARN_ON((fxn > 0x28) || (fxn & 7)))
30861ddc9   Steven L Kinney   perf/x86/amd: Add...
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
  		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...
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
  
  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);
  }