Blame view

drivers/iommu/amd_iommu_v2.c 22.3 KB
e3c495c74   Joerg Roedel   iommu/amd: Add dr...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * Copyright (C) 2010-2012 Advanced Micro Devices, Inc.
   * Author: Joerg Roedel <joerg.roedel@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
   */
8736b2c33   Joerg Roedel   iommu/amd: Implem...
18
  #include <linux/mmu_notifier.h>
ed96f228b   Joerg Roedel   iommu/amd: Implem...
19
20
  #include <linux/amd-iommu.h>
  #include <linux/mm_types.h>
8736b2c33   Joerg Roedel   iommu/amd: Implem...
21
  #include <linux/profile.h>
e3c495c74   Joerg Roedel   iommu/amd: Add dr...
22
  #include <linux/module.h>
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
23
  #include <linux/sched.h>
ed96f228b   Joerg Roedel   iommu/amd: Implem...
24
  #include <linux/iommu.h>
028eeacc4   Joerg Roedel   iommu/amd: Implem...
25
  #include <linux/wait.h>
ed96f228b   Joerg Roedel   iommu/amd: Implem...
26
27
  #include <linux/pci.h>
  #include <linux/gfp.h>
028eeacc4   Joerg Roedel   iommu/amd: Implem...
28
  #include "amd_iommu_types.h"
ed96f228b   Joerg Roedel   iommu/amd: Implem...
29
  #include "amd_iommu_proto.h"
e3c495c74   Joerg Roedel   iommu/amd: Add dr...
30
31
32
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Joerg Roedel <joerg.roedel@amd.com>");
ed96f228b   Joerg Roedel   iommu/amd: Implem...
33
34
35
36
37
38
  #define MAX_DEVICES		0x10000
  #define PRI_QUEUE_SIZE		512
  
  struct pri_queue {
  	atomic_t inflight;
  	bool finish;
028eeacc4   Joerg Roedel   iommu/amd: Implem...
39
  	int status;
ed96f228b   Joerg Roedel   iommu/amd: Implem...
40
41
42
43
44
45
46
  };
  
  struct pasid_state {
  	struct list_head list;			/* For global state-list */
  	atomic_t count;				/* Reference count */
  	struct task_struct *task;		/* Task bound to this PASID */
  	struct mm_struct *mm;			/* mm_struct for the faults */
8736b2c33   Joerg Roedel   iommu/amd: Implem...
47
  	struct mmu_notifier mn;                 /* mmu_otifier handle */
ed96f228b   Joerg Roedel   iommu/amd: Implem...
48
49
50
  	struct pri_queue pri[PRI_QUEUE_SIZE];	/* PRI tag states */
  	struct device_state *device_state;	/* Link to our device_state */
  	int pasid;				/* PASID index */
028eeacc4   Joerg Roedel   iommu/amd: Implem...
51
52
  	spinlock_t lock;			/* Protect pri_queues */
  	wait_queue_head_t wq;			/* To wait for count == 0 */
ed96f228b   Joerg Roedel   iommu/amd: Implem...
53
54
55
56
57
58
59
60
61
  };
  
  struct device_state {
  	atomic_t count;
  	struct pci_dev *pdev;
  	struct pasid_state **states;
  	struct iommu_domain *domain;
  	int pasid_levels;
  	int max_pasids;
175d61467   Joerg Roedel   iommu/amd: Add in...
62
  	amd_iommu_invalid_ppr_cb inv_ppr_cb;
bc21662f7   Joerg Roedel   iommu/amd: Add in...
63
  	amd_iommu_invalidate_ctx inv_ctx_cb;
ed96f228b   Joerg Roedel   iommu/amd: Implem...
64
  	spinlock_t lock;
028eeacc4   Joerg Roedel   iommu/amd: Implem...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  	wait_queue_head_t wq;
  };
  
  struct fault {
  	struct work_struct work;
  	struct device_state *dev_state;
  	struct pasid_state *state;
  	struct mm_struct *mm;
  	u64 address;
  	u16 devid;
  	u16 pasid;
  	u16 tag;
  	u16 finish;
  	u16 flags;
ed96f228b   Joerg Roedel   iommu/amd: Implem...
79
80
81
82
83
84
85
  };
  
  struct device_state **state_table;
  static spinlock_t state_lock;
  
  /* List and lock for all pasid_states */
  static LIST_HEAD(pasid_state_list);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
86
  static DEFINE_SPINLOCK(ps_lock);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
87
  static struct workqueue_struct *iommu_wq;
8736b2c33   Joerg Roedel   iommu/amd: Implem...
88
89
90
91
92
93
  /*
   * Empty page table - Used between
   * mmu_notifier_invalidate_range_start and
   * mmu_notifier_invalidate_range_end
   */
  static u64 *empty_page_table;
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
94
95
  static void free_pasid_states(struct device_state *dev_state);
  static void unbind_pasid(struct device_state *dev_state, int pasid);
8736b2c33   Joerg Roedel   iommu/amd: Implem...
96
  static int task_exit(struct notifier_block *nb, unsigned long e, void *data);
ed96f228b   Joerg Roedel   iommu/amd: Implem...
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  
  static u16 device_id(struct pci_dev *pdev)
  {
  	u16 devid;
  
  	devid = pdev->bus->number;
  	devid = (devid << 8) | pdev->devfn;
  
  	return devid;
  }
  
  static struct device_state *get_device_state(u16 devid)
  {
  	struct device_state *dev_state;
  	unsigned long flags;
  
  	spin_lock_irqsave(&state_lock, flags);
  	dev_state = state_table[devid];
  	if (dev_state != NULL)
  		atomic_inc(&dev_state->count);
  	spin_unlock_irqrestore(&state_lock, flags);
  
  	return dev_state;
  }
  
  static void free_device_state(struct device_state *dev_state)
  {
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
124
125
126
127
  	/*
  	 * First detach device from domain - No more PRI requests will arrive
  	 * from that device after it is unbound from the IOMMUv2 domain.
  	 */
ed96f228b   Joerg Roedel   iommu/amd: Implem...
128
  	iommu_detach_device(dev_state->domain, &dev_state->pdev->dev);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
129
130
  
  	/* Everything is down now, free the IOMMUv2 domain */
ed96f228b   Joerg Roedel   iommu/amd: Implem...
131
  	iommu_domain_free(dev_state->domain);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
132
133
  
  	/* Finally get rid of the device-state */
ed96f228b   Joerg Roedel   iommu/amd: Implem...
134
135
136
137
138
139
  	kfree(dev_state);
  }
  
  static void put_device_state(struct device_state *dev_state)
  {
  	if (atomic_dec_and_test(&dev_state->count))
028eeacc4   Joerg Roedel   iommu/amd: Implem...
140
  		wake_up(&dev_state->wq);
ed96f228b   Joerg Roedel   iommu/amd: Implem...
141
  }
028eeacc4   Joerg Roedel   iommu/amd: Implem...
142
143
144
145
146
147
148
149
150
151
152
  static void put_device_state_wait(struct device_state *dev_state)
  {
  	DEFINE_WAIT(wait);
  
  	prepare_to_wait(&dev_state->wq, &wait, TASK_UNINTERRUPTIBLE);
  	if (!atomic_dec_and_test(&dev_state->count))
  		schedule();
  	finish_wait(&dev_state->wq, &wait);
  
  	free_device_state(dev_state);
  }
8736b2c33   Joerg Roedel   iommu/amd: Implem...
153
154
155
156
  
  static struct notifier_block profile_nb = {
  	.notifier_call = task_exit,
  };
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  static void link_pasid_state(struct pasid_state *pasid_state)
  {
  	spin_lock(&ps_lock);
  	list_add_tail(&pasid_state->list, &pasid_state_list);
  	spin_unlock(&ps_lock);
  }
  
  static void __unlink_pasid_state(struct pasid_state *pasid_state)
  {
  	list_del(&pasid_state->list);
  }
  
  static void unlink_pasid_state(struct pasid_state *pasid_state)
  {
  	spin_lock(&ps_lock);
  	__unlink_pasid_state(pasid_state);
  	spin_unlock(&ps_lock);
  }
  
  /* Must be called under dev_state->lock */
  static struct pasid_state **__get_pasid_state_ptr(struct device_state *dev_state,
  						  int pasid, bool alloc)
  {
  	struct pasid_state **root, **ptr;
  	int level, index;
  
  	level = dev_state->pasid_levels;
  	root  = dev_state->states;
  
  	while (true) {
  
  		index = (pasid >> (9 * level)) & 0x1ff;
  		ptr   = &root[index];
  
  		if (level == 0)
  			break;
  
  		if (*ptr == NULL) {
  			if (!alloc)
  				return NULL;
  
  			*ptr = (void *)get_zeroed_page(GFP_ATOMIC);
  			if (*ptr == NULL)
  				return NULL;
  		}
  
  		root   = (struct pasid_state **)*ptr;
  		level -= 1;
  	}
  
  	return ptr;
  }
  
  static int set_pasid_state(struct device_state *dev_state,
  			   struct pasid_state *pasid_state,
  			   int pasid)
  {
  	struct pasid_state **ptr;
  	unsigned long flags;
  	int ret;
  
  	spin_lock_irqsave(&dev_state->lock, flags);
  	ptr = __get_pasid_state_ptr(dev_state, pasid, true);
  
  	ret = -ENOMEM;
  	if (ptr == NULL)
  		goto out_unlock;
  
  	ret = -ENOMEM;
  	if (*ptr != NULL)
  		goto out_unlock;
  
  	*ptr = pasid_state;
  
  	ret = 0;
  
  out_unlock:
  	spin_unlock_irqrestore(&dev_state->lock, flags);
  
  	return ret;
  }
  
  static void clear_pasid_state(struct device_state *dev_state, int pasid)
  {
  	struct pasid_state **ptr;
  	unsigned long flags;
  
  	spin_lock_irqsave(&dev_state->lock, flags);
  	ptr = __get_pasid_state_ptr(dev_state, pasid, true);
  
  	if (ptr == NULL)
  		goto out_unlock;
  
  	*ptr = NULL;
  
  out_unlock:
  	spin_unlock_irqrestore(&dev_state->lock, flags);
  }
  
  static struct pasid_state *get_pasid_state(struct device_state *dev_state,
  					   int pasid)
  {
  	struct pasid_state **ptr, *ret = NULL;
  	unsigned long flags;
  
  	spin_lock_irqsave(&dev_state->lock, flags);
  	ptr = __get_pasid_state_ptr(dev_state, pasid, false);
  
  	if (ptr == NULL)
  		goto out_unlock;
  
  	ret = *ptr;
  	if (ret)
  		atomic_inc(&ret->count);
  
  out_unlock:
  	spin_unlock_irqrestore(&dev_state->lock, flags);
  
  	return ret;
  }
  
  static void free_pasid_state(struct pasid_state *pasid_state)
  {
  	kfree(pasid_state);
  }
  
  static void put_pasid_state(struct pasid_state *pasid_state)
  {
  	if (atomic_dec_and_test(&pasid_state->count)) {
  		put_device_state(pasid_state->device_state);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
287
  		wake_up(&pasid_state->wq);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
288
289
  	}
  }
028eeacc4   Joerg Roedel   iommu/amd: Implem...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  static void put_pasid_state_wait(struct pasid_state *pasid_state)
  {
  	DEFINE_WAIT(wait);
  
  	prepare_to_wait(&pasid_state->wq, &wait, TASK_UNINTERRUPTIBLE);
  
  	if (atomic_dec_and_test(&pasid_state->count))
  		put_device_state(pasid_state->device_state);
  	else
  		schedule();
  
  	finish_wait(&pasid_state->wq, &wait);
  	mmput(pasid_state->mm);
  	free_pasid_state(pasid_state);
  }
8736b2c33   Joerg Roedel   iommu/amd: Implem...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  static void __unbind_pasid(struct pasid_state *pasid_state)
  {
  	struct iommu_domain *domain;
  
  	domain = pasid_state->device_state->domain;
  
  	amd_iommu_domain_clear_gcr3(domain, pasid_state->pasid);
  	clear_pasid_state(pasid_state->device_state, pasid_state->pasid);
  
  	/* Make sure no more pending faults are in the queue */
  	flush_workqueue(iommu_wq);
  
  	mmu_notifier_unregister(&pasid_state->mn, pasid_state->mm);
  
  	put_pasid_state(pasid_state); /* Reference taken in bind() function */
  }
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
321
322
323
324
325
326
327
328
329
  static void unbind_pasid(struct device_state *dev_state, int pasid)
  {
  	struct pasid_state *pasid_state;
  
  	pasid_state = get_pasid_state(dev_state, pasid);
  	if (pasid_state == NULL)
  		return;
  
  	unlink_pasid_state(pasid_state);
8736b2c33   Joerg Roedel   iommu/amd: Implem...
330
331
  	__unbind_pasid(pasid_state);
  	put_pasid_state_wait(pasid_state); /* Reference taken in this function */
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  }
  
  static void free_pasid_states_level1(struct pasid_state **tbl)
  {
  	int i;
  
  	for (i = 0; i < 512; ++i) {
  		if (tbl[i] == NULL)
  			continue;
  
  		free_page((unsigned long)tbl[i]);
  	}
  }
  
  static void free_pasid_states_level2(struct pasid_state **tbl)
  {
  	struct pasid_state **ptr;
  	int i;
  
  	for (i = 0; i < 512; ++i) {
  		if (tbl[i] == NULL)
  			continue;
  
  		ptr = (struct pasid_state **)tbl[i];
  		free_pasid_states_level1(ptr);
  	}
  }
  
  static void free_pasid_states(struct device_state *dev_state)
  {
  	struct pasid_state *pasid_state;
  	int i;
  
  	for (i = 0; i < dev_state->max_pasids; ++i) {
  		pasid_state = get_pasid_state(dev_state, i);
  		if (pasid_state == NULL)
  			continue;
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
369
  		put_pasid_state(pasid_state);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
370
  		unbind_pasid(dev_state, i);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
371
372
373
374
375
376
377
378
379
380
381
  	}
  
  	if (dev_state->pasid_levels == 2)
  		free_pasid_states_level2(dev_state->states);
  	else if (dev_state->pasid_levels == 1)
  		free_pasid_states_level1(dev_state->states);
  	else if (dev_state->pasid_levels != 0)
  		BUG();
  
  	free_page((unsigned long)dev_state->states);
  }
8736b2c33   Joerg Roedel   iommu/amd: Implem...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  static struct pasid_state *mn_to_state(struct mmu_notifier *mn)
  {
  	return container_of(mn, struct pasid_state, mn);
  }
  
  static void __mn_flush_page(struct mmu_notifier *mn,
  			    unsigned long address)
  {
  	struct pasid_state *pasid_state;
  	struct device_state *dev_state;
  
  	pasid_state = mn_to_state(mn);
  	dev_state   = pasid_state->device_state;
  
  	amd_iommu_flush_page(dev_state->domain, pasid_state->pasid, address);
  }
  
  static int mn_clear_flush_young(struct mmu_notifier *mn,
  				struct mm_struct *mm,
  				unsigned long address)
  {
  	__mn_flush_page(mn, address);
  
  	return 0;
  }
  
  static void mn_change_pte(struct mmu_notifier *mn,
  			  struct mm_struct *mm,
  			  unsigned long address,
  			  pte_t pte)
  {
  	__mn_flush_page(mn, address);
  }
  
  static void mn_invalidate_page(struct mmu_notifier *mn,
  			       struct mm_struct *mm,
  			       unsigned long address)
  {
  	__mn_flush_page(mn, address);
  }
  
  static void mn_invalidate_range_start(struct mmu_notifier *mn,
  				      struct mm_struct *mm,
  				      unsigned long start, unsigned long end)
  {
  	struct pasid_state *pasid_state;
  	struct device_state *dev_state;
  
  	pasid_state = mn_to_state(mn);
  	dev_state   = pasid_state->device_state;
  
  	amd_iommu_domain_set_gcr3(dev_state->domain, pasid_state->pasid,
  				  __pa(empty_page_table));
  }
  
  static void mn_invalidate_range_end(struct mmu_notifier *mn,
  				    struct mm_struct *mm,
  				    unsigned long start, unsigned long end)
  {
  	struct pasid_state *pasid_state;
  	struct device_state *dev_state;
  
  	pasid_state = mn_to_state(mn);
  	dev_state   = pasid_state->device_state;
  
  	amd_iommu_domain_set_gcr3(dev_state->domain, pasid_state->pasid,
  				  __pa(pasid_state->mm->pgd));
  }
  
  static struct mmu_notifier_ops iommu_mn = {
  	.clear_flush_young      = mn_clear_flush_young,
  	.change_pte             = mn_change_pte,
  	.invalidate_page        = mn_invalidate_page,
  	.invalidate_range_start = mn_invalidate_range_start,
  	.invalidate_range_end   = mn_invalidate_range_end,
  };
028eeacc4   Joerg Roedel   iommu/amd: Implem...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
  static void set_pri_tag_status(struct pasid_state *pasid_state,
  			       u16 tag, int status)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&pasid_state->lock, flags);
  	pasid_state->pri[tag].status = status;
  	spin_unlock_irqrestore(&pasid_state->lock, flags);
  }
  
  static void finish_pri_tag(struct device_state *dev_state,
  			   struct pasid_state *pasid_state,
  			   u16 tag)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&pasid_state->lock, flags);
  	if (atomic_dec_and_test(&pasid_state->pri[tag].inflight) &&
  	    pasid_state->pri[tag].finish) {
  		amd_iommu_complete_ppr(dev_state->pdev, pasid_state->pasid,
  				       pasid_state->pri[tag].status, tag);
  		pasid_state->pri[tag].finish = false;
  		pasid_state->pri[tag].status = PPR_SUCCESS;
  	}
  	spin_unlock_irqrestore(&pasid_state->lock, flags);
  }
  
  static void do_fault(struct work_struct *work)
  {
  	struct fault *fault = container_of(work, struct fault, work);
  	int npages, write;
  	struct page *page;
  
  	write = !!(fault->flags & PPR_FAULT_WRITE);
  
  	npages = get_user_pages(fault->state->task, fault->state->mm,
  				fault->address, 1, write, 0, &page, NULL);
175d61467   Joerg Roedel   iommu/amd: Add in...
495
  	if (npages == 1) {
028eeacc4   Joerg Roedel   iommu/amd: Implem...
496
  		put_page(page);
175d61467   Joerg Roedel   iommu/amd: Add in...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  	} else if (fault->dev_state->inv_ppr_cb) {
  		int status;
  
  		status = fault->dev_state->inv_ppr_cb(fault->dev_state->pdev,
  						      fault->pasid,
  						      fault->address,
  						      fault->flags);
  		switch (status) {
  		case AMD_IOMMU_INV_PRI_RSP_SUCCESS:
  			set_pri_tag_status(fault->state, fault->tag, PPR_SUCCESS);
  			break;
  		case AMD_IOMMU_INV_PRI_RSP_INVALID:
  			set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
  			break;
  		case AMD_IOMMU_INV_PRI_RSP_FAIL:
  			set_pri_tag_status(fault->state, fault->tag, PPR_FAILURE);
  			break;
  		default:
  			BUG();
  		}
  	} else {
028eeacc4   Joerg Roedel   iommu/amd: Implem...
518
  		set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
175d61467   Joerg Roedel   iommu/amd: Add in...
519
  	}
028eeacc4   Joerg Roedel   iommu/amd: Implem...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
  
  	finish_pri_tag(fault->dev_state, fault->state, fault->tag);
  
  	put_pasid_state(fault->state);
  
  	kfree(fault);
  }
  
  static int ppr_notifier(struct notifier_block *nb, unsigned long e, void *data)
  {
  	struct amd_iommu_fault *iommu_fault;
  	struct pasid_state *pasid_state;
  	struct device_state *dev_state;
  	unsigned long flags;
  	struct fault *fault;
  	bool finish;
  	u16 tag;
  	int ret;
  
  	iommu_fault = data;
  	tag         = iommu_fault->tag & 0x1ff;
  	finish      = (iommu_fault->tag >> 9) & 1;
  
  	ret = NOTIFY_DONE;
  	dev_state = get_device_state(iommu_fault->device_id);
  	if (dev_state == NULL)
  		goto out;
  
  	pasid_state = get_pasid_state(dev_state, iommu_fault->pasid);
  	if (pasid_state == NULL) {
  		/* We know the device but not the PASID -> send INVALID */
  		amd_iommu_complete_ppr(dev_state->pdev, iommu_fault->pasid,
  				       PPR_INVALID, tag);
  		goto out_drop_state;
  	}
  
  	spin_lock_irqsave(&pasid_state->lock, flags);
  	atomic_inc(&pasid_state->pri[tag].inflight);
  	if (finish)
  		pasid_state->pri[tag].finish = true;
  	spin_unlock_irqrestore(&pasid_state->lock, flags);
  
  	fault = kzalloc(sizeof(*fault), GFP_ATOMIC);
  	if (fault == NULL) {
  		/* We are OOM - send success and let the device re-fault */
  		finish_pri_tag(dev_state, pasid_state, tag);
  		goto out_drop_state;
  	}
  
  	fault->dev_state = dev_state;
  	fault->address   = iommu_fault->address;
  	fault->state     = pasid_state;
  	fault->tag       = tag;
  	fault->finish    = finish;
  	fault->flags     = iommu_fault->flags;
  	INIT_WORK(&fault->work, do_fault);
  
  	queue_work(iommu_wq, &fault->work);
  
  	ret = NOTIFY_OK;
  
  out_drop_state:
  	put_device_state(dev_state);
  
  out:
  	return ret;
  }
  
  static struct notifier_block ppr_nb = {
  	.notifier_call = ppr_notifier,
  };
8736b2c33   Joerg Roedel   iommu/amd: Implem...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  static int task_exit(struct notifier_block *nb, unsigned long e, void *data)
  {
  	struct pasid_state *pasid_state;
  	struct task_struct *task;
  
  	task = data;
  
  	/*
  	 * Using this notifier is a hack - but there is no other choice
  	 * at the moment. What I really want is a sleeping notifier that
  	 * is called when an MM goes down. But such a notifier doesn't
  	 * exist yet. The notifier needs to sleep because it has to make
  	 * sure that the device does not use the PASID and the address
  	 * space anymore before it is destroyed. This includes waiting
  	 * for pending PRI requests to pass the workqueue. The
  	 * MMU-Notifiers would be a good fit, but they use RCU and so
  	 * they are not allowed to sleep. Lets see how we can solve this
  	 * in a more intelligent way in the future.
  	 */
  again:
  	spin_lock(&ps_lock);
  	list_for_each_entry(pasid_state, &pasid_state_list, list) {
  		struct device_state *dev_state;
  		int pasid;
  
  		if (pasid_state->task != task)
  			continue;
  
  		/* Drop Lock and unbind */
  		spin_unlock(&ps_lock);
  
  		dev_state = pasid_state->device_state;
  		pasid     = pasid_state->pasid;
bc21662f7   Joerg Roedel   iommu/amd: Add in...
624
625
  		if (pasid_state->device_state->inv_ctx_cb)
  			dev_state->inv_ctx_cb(dev_state->pdev, pasid);
8736b2c33   Joerg Roedel   iommu/amd: Implem...
626
627
628
629
630
631
632
633
634
  		unbind_pasid(dev_state, pasid);
  
  		/* Task may be in the list multiple times */
  		goto again;
  	}
  	spin_unlock(&ps_lock);
  
  	return NOTIFY_OK;
  }
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
  int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid,
  			 struct task_struct *task)
  {
  	struct pasid_state *pasid_state;
  	struct device_state *dev_state;
  	u16 devid;
  	int ret;
  
  	might_sleep();
  
  	if (!amd_iommu_v2_supported())
  		return -ENODEV;
  
  	devid     = device_id(pdev);
  	dev_state = get_device_state(devid);
  
  	if (dev_state == NULL)
  		return -EINVAL;
  
  	ret = -EINVAL;
  	if (pasid < 0 || pasid >= dev_state->max_pasids)
  		goto out;
  
  	ret = -ENOMEM;
  	pasid_state = kzalloc(sizeof(*pasid_state), GFP_KERNEL);
  	if (pasid_state == NULL)
  		goto out;
  
  	atomic_set(&pasid_state->count, 1);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
664
  	init_waitqueue_head(&pasid_state->wq);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
665
666
667
668
  	pasid_state->task         = task;
  	pasid_state->mm           = get_task_mm(task);
  	pasid_state->device_state = dev_state;
  	pasid_state->pasid        = pasid;
8736b2c33   Joerg Roedel   iommu/amd: Implem...
669
  	pasid_state->mn.ops       = &iommu_mn;
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
670
671
672
  
  	if (pasid_state->mm == NULL)
  		goto out_free;
8736b2c33   Joerg Roedel   iommu/amd: Implem...
673
  	mmu_notifier_register(&pasid_state->mn, pasid_state->mm);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
674
675
  	ret = set_pasid_state(dev_state, pasid_state, pasid);
  	if (ret)
8736b2c33   Joerg Roedel   iommu/amd: Implem...
676
  		goto out_unregister;
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
677
678
679
680
681
682
683
684
685
686
687
688
  
  	ret = amd_iommu_domain_set_gcr3(dev_state->domain, pasid,
  					__pa(pasid_state->mm->pgd));
  	if (ret)
  		goto out_clear_state;
  
  	link_pasid_state(pasid_state);
  
  	return 0;
  
  out_clear_state:
  	clear_pasid_state(dev_state, pasid);
8736b2c33   Joerg Roedel   iommu/amd: Implem...
689
690
  out_unregister:
  	mmu_notifier_unregister(&pasid_state->mn, pasid_state->mm);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
691
  out_free:
028eeacc4   Joerg Roedel   iommu/amd: Implem...
692
  	free_pasid_state(pasid_state);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
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
  
  out:
  	put_device_state(dev_state);
  
  	return ret;
  }
  EXPORT_SYMBOL(amd_iommu_bind_pasid);
  
  void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid)
  {
  	struct device_state *dev_state;
  	u16 devid;
  
  	might_sleep();
  
  	if (!amd_iommu_v2_supported())
  		return;
  
  	devid = device_id(pdev);
  	dev_state = get_device_state(devid);
  	if (dev_state == NULL)
  		return;
  
  	if (pasid < 0 || pasid >= dev_state->max_pasids)
  		goto out;
  
  	unbind_pasid(dev_state, pasid);
  
  out:
  	put_device_state(dev_state);
  }
  EXPORT_SYMBOL(amd_iommu_unbind_pasid);
ed96f228b   Joerg Roedel   iommu/amd: Implem...
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
  int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
  {
  	struct device_state *dev_state;
  	unsigned long flags;
  	int ret, tmp;
  	u16 devid;
  
  	might_sleep();
  
  	if (!amd_iommu_v2_supported())
  		return -ENODEV;
  
  	if (pasids <= 0 || pasids > (PASID_MASK + 1))
  		return -EINVAL;
  
  	devid = device_id(pdev);
  
  	dev_state = kzalloc(sizeof(*dev_state), GFP_KERNEL);
  	if (dev_state == NULL)
  		return -ENOMEM;
  
  	spin_lock_init(&dev_state->lock);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
747
  	init_waitqueue_head(&dev_state->wq);
ed96f228b   Joerg Roedel   iommu/amd: Implem...
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
  	dev_state->pdev = pdev;
  
  	tmp = pasids;
  	for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9)
  		dev_state->pasid_levels += 1;
  
  	atomic_set(&dev_state->count, 1);
  	dev_state->max_pasids = pasids;
  
  	ret = -ENOMEM;
  	dev_state->states = (void *)get_zeroed_page(GFP_KERNEL);
  	if (dev_state->states == NULL)
  		goto out_free_dev_state;
  
  	dev_state->domain = iommu_domain_alloc(&pci_bus_type);
  	if (dev_state->domain == NULL)
  		goto out_free_states;
  
  	amd_iommu_domain_direct_map(dev_state->domain);
  
  	ret = amd_iommu_domain_enable_v2(dev_state->domain, pasids);
  	if (ret)
  		goto out_free_domain;
  
  	ret = iommu_attach_device(dev_state->domain, &pdev->dev);
  	if (ret != 0)
  		goto out_free_domain;
  
  	spin_lock_irqsave(&state_lock, flags);
  
  	if (state_table[devid] != NULL) {
  		spin_unlock_irqrestore(&state_lock, flags);
  		ret = -EBUSY;
  		goto out_free_domain;
  	}
  
  	state_table[devid] = dev_state;
  
  	spin_unlock_irqrestore(&state_lock, flags);
  
  	return 0;
  
  out_free_domain:
  	iommu_domain_free(dev_state->domain);
  
  out_free_states:
  	free_page((unsigned long)dev_state->states);
  
  out_free_dev_state:
  	kfree(dev_state);
  
  	return ret;
  }
  EXPORT_SYMBOL(amd_iommu_init_device);
  
  void amd_iommu_free_device(struct pci_dev *pdev)
  {
  	struct device_state *dev_state;
  	unsigned long flags;
  	u16 devid;
  
  	if (!amd_iommu_v2_supported())
  		return;
  
  	devid = device_id(pdev);
  
  	spin_lock_irqsave(&state_lock, flags);
  
  	dev_state = state_table[devid];
  	if (dev_state == NULL) {
  		spin_unlock_irqrestore(&state_lock, flags);
  		return;
  	}
  
  	state_table[devid] = NULL;
  
  	spin_unlock_irqrestore(&state_lock, flags);
2d5503b62   Joerg Roedel   iommu/amd: Add ro...
825
826
  	/* Get rid of any remaining pasid states */
  	free_pasid_states(dev_state);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
827
  	put_device_state_wait(dev_state);
ed96f228b   Joerg Roedel   iommu/amd: Implem...
828
829
  }
  EXPORT_SYMBOL(amd_iommu_free_device);
175d61467   Joerg Roedel   iommu/amd: Add in...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
  int amd_iommu_set_invalid_ppr_cb(struct pci_dev *pdev,
  				 amd_iommu_invalid_ppr_cb cb)
  {
  	struct device_state *dev_state;
  	unsigned long flags;
  	u16 devid;
  	int ret;
  
  	if (!amd_iommu_v2_supported())
  		return -ENODEV;
  
  	devid = device_id(pdev);
  
  	spin_lock_irqsave(&state_lock, flags);
  
  	ret = -EINVAL;
  	dev_state = state_table[devid];
  	if (dev_state == NULL)
  		goto out_unlock;
  
  	dev_state->inv_ppr_cb = cb;
  
  	ret = 0;
  
  out_unlock:
  	spin_unlock_irqrestore(&state_lock, flags);
  
  	return ret;
  }
  EXPORT_SYMBOL(amd_iommu_set_invalid_ppr_cb);
bc21662f7   Joerg Roedel   iommu/amd: Add in...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
  int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev,
  				    amd_iommu_invalidate_ctx cb)
  {
  	struct device_state *dev_state;
  	unsigned long flags;
  	u16 devid;
  	int ret;
  
  	if (!amd_iommu_v2_supported())
  		return -ENODEV;
  
  	devid = device_id(pdev);
  
  	spin_lock_irqsave(&state_lock, flags);
  
  	ret = -EINVAL;
  	dev_state = state_table[devid];
  	if (dev_state == NULL)
  		goto out_unlock;
  
  	dev_state->inv_ctx_cb = cb;
  
  	ret = 0;
  
  out_unlock:
  	spin_unlock_irqrestore(&state_lock, flags);
  
  	return ret;
  }
  EXPORT_SYMBOL(amd_iommu_set_invalidate_ctx_cb);
e3c495c74   Joerg Roedel   iommu/amd: Add dr...
890
891
  static int __init amd_iommu_v2_init(void)
  {
ed96f228b   Joerg Roedel   iommu/amd: Implem...
892
  	size_t state_table_size;
028eeacc4   Joerg Roedel   iommu/amd: Implem...
893
  	int ret;
ed96f228b   Joerg Roedel   iommu/amd: Implem...
894

e3c495c74   Joerg Roedel   iommu/amd: Add dr...
895
  	pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>");
ed96f228b   Joerg Roedel   iommu/amd: Implem...
896
897
898
899
900
901
902
  	spin_lock_init(&state_lock);
  
  	state_table_size = MAX_DEVICES * sizeof(struct device_state *);
  	state_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
  					       get_order(state_table_size));
  	if (state_table == NULL)
  		return -ENOMEM;
028eeacc4   Joerg Roedel   iommu/amd: Implem...
903
904
  	ret = -ENOMEM;
  	iommu_wq = create_workqueue("amd_iommu_v2");
8736b2c33   Joerg Roedel   iommu/amd: Implem...
905
  	if (iommu_wq == NULL)
028eeacc4   Joerg Roedel   iommu/amd: Implem...
906
  		goto out_free;
8736b2c33   Joerg Roedel   iommu/amd: Implem...
907
908
909
910
911
  
  	ret = -ENOMEM;
  	empty_page_table = (u64 *)get_zeroed_page(GFP_KERNEL);
  	if (empty_page_table == NULL)
  		goto out_destroy_wq;
028eeacc4   Joerg Roedel   iommu/amd: Implem...
912
913
  
  	amd_iommu_register_ppr_notifier(&ppr_nb);
8736b2c33   Joerg Roedel   iommu/amd: Implem...
914
  	profile_event_register(PROFILE_TASK_EXIT, &profile_nb);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
915

e3c495c74   Joerg Roedel   iommu/amd: Add dr...
916
  	return 0;
028eeacc4   Joerg Roedel   iommu/amd: Implem...
917

8736b2c33   Joerg Roedel   iommu/amd: Implem...
918
919
  out_destroy_wq:
  	destroy_workqueue(iommu_wq);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
920
921
922
923
  out_free:
  	free_pages((unsigned long)state_table, get_order(state_table_size));
  
  	return ret;
e3c495c74   Joerg Roedel   iommu/amd: Add dr...
924
925
926
927
  }
  
  static void __exit amd_iommu_v2_exit(void)
  {
ed96f228b   Joerg Roedel   iommu/amd: Implem...
928
929
930
  	struct device_state *dev_state;
  	size_t state_table_size;
  	int i;
8736b2c33   Joerg Roedel   iommu/amd: Implem...
931
  	profile_event_unregister(PROFILE_TASK_EXIT, &profile_nb);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
932
933
934
935
936
937
938
939
  	amd_iommu_unregister_ppr_notifier(&ppr_nb);
  
  	flush_workqueue(iommu_wq);
  
  	/*
  	 * The loop below might call flush_workqueue(), so call
  	 * destroy_workqueue() after it
  	 */
ed96f228b   Joerg Roedel   iommu/amd: Implem...
940
941
942
943
944
945
946
  	for (i = 0; i < MAX_DEVICES; ++i) {
  		dev_state = get_device_state(i);
  
  		if (dev_state == NULL)
  			continue;
  
  		WARN_ON_ONCE(1);
ed96f228b   Joerg Roedel   iommu/amd: Implem...
947
  		put_device_state(dev_state);
028eeacc4   Joerg Roedel   iommu/amd: Implem...
948
  		amd_iommu_free_device(dev_state->pdev);
ed96f228b   Joerg Roedel   iommu/amd: Implem...
949
  	}
028eeacc4   Joerg Roedel   iommu/amd: Implem...
950
  	destroy_workqueue(iommu_wq);
ed96f228b   Joerg Roedel   iommu/amd: Implem...
951
952
  	state_table_size = MAX_DEVICES * sizeof(struct device_state *);
  	free_pages((unsigned long)state_table, get_order(state_table_size));
8736b2c33   Joerg Roedel   iommu/amd: Implem...
953
954
  
  	free_page((unsigned long)empty_page_table);
e3c495c74   Joerg Roedel   iommu/amd: Add dr...
955
956
957
958
  }
  
  module_init(amd_iommu_v2_init);
  module_exit(amd_iommu_v2_exit);