aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/amd_iommu_v2.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-13 16:00:36 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-13 16:00:36 -0500
commit78a45c6f067824cf5d0a9fedea7339ac2e28603c (patch)
treeb4f78c8b6b9059ddace0a18c11629b8d2045f793 /drivers/iommu/amd_iommu_v2.c
parentf96fe225677b3efb74346ebd56fafe3997b02afa (diff)
parent29d293b6007b91a4463f05bc8d0b26e0e65c5816 (diff)
Merge branch 'akpm' (second patch-bomb from Andrew)
Merge second patchbomb from Andrew Morton: - the rest of MM - misc fs fixes - add execveat() syscall - new ratelimit feature for fault-injection - decompressor updates - ipc/ updates - fallocate feature creep - fsnotify cleanups - a few other misc things * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (99 commits) cgroups: Documentation: fix trivial typos and wrong paragraph numberings parisc: percpu: update comments referring to __get_cpu_var percpu: update local_ops.txt to reflect this_cpu operations percpu: remove __get_cpu_var and __raw_get_cpu_var macros fsnotify: remove destroy_list from fsnotify_mark fsnotify: unify inode and mount marks handling fallocate: create FAN_MODIFY and IN_MODIFY events mm/cma: make kmemleak ignore CMA regions slub: fix cpuset check in get_any_partial slab: fix cpuset check in fallback_alloc shmdt: use i_size_read() instead of ->i_size ipc/shm.c: fix overly aggressive shmdt() when calls span multiple segments ipc/msg: increase MSGMNI, remove scaling ipc/sem.c: increase SEMMSL, SEMMNI, SEMOPM ipc/sem.c: change memory barrier in sem_lock() to smp_rmb() lib/decompress.c: consistency of compress formats for kernel image decompress_bunzip2: off by one in get_next_block() usr/Kconfig: make initrd compression algorithm selection not expert fault-inject: add ratelimit option ratelimit: add initialization macro ...
Diffstat (limited to 'drivers/iommu/amd_iommu_v2.c')
-rw-r--r--drivers/iommu/amd_iommu_v2.c84
1 files changed, 53 insertions, 31 deletions
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c
index a2d87a60c27f..bea878f8e7d3 100644
--- a/drivers/iommu/amd_iommu_v2.c
+++ b/drivers/iommu/amd_iommu_v2.c
@@ -509,45 +509,67 @@ static void finish_pri_tag(struct device_state *dev_state,
509 spin_unlock_irqrestore(&pasid_state->lock, flags); 509 spin_unlock_irqrestore(&pasid_state->lock, flags);
510} 510}
511 511
512static void handle_fault_error(struct fault *fault)
513{
514 int status;
515
516 if (!fault->dev_state->inv_ppr_cb) {
517 set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
518 return;
519 }
520
521 status = fault->dev_state->inv_ppr_cb(fault->dev_state->pdev,
522 fault->pasid,
523 fault->address,
524 fault->flags);
525 switch (status) {
526 case AMD_IOMMU_INV_PRI_RSP_SUCCESS:
527 set_pri_tag_status(fault->state, fault->tag, PPR_SUCCESS);
528 break;
529 case AMD_IOMMU_INV_PRI_RSP_INVALID:
530 set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
531 break;
532 case AMD_IOMMU_INV_PRI_RSP_FAIL:
533 set_pri_tag_status(fault->state, fault->tag, PPR_FAILURE);
534 break;
535 default:
536 BUG();
537 }
538}
539
512static void do_fault(struct work_struct *work) 540static void do_fault(struct work_struct *work)
513{ 541{
514 struct fault *fault = container_of(work, struct fault, work); 542 struct fault *fault = container_of(work, struct fault, work);
515 int npages, write; 543 struct mm_struct *mm;
516 struct page *page; 544 struct vm_area_struct *vma;
545 u64 address;
546 int ret, write;
517 547
518 write = !!(fault->flags & PPR_FAULT_WRITE); 548 write = !!(fault->flags & PPR_FAULT_WRITE);
519 549
520 down_read(&fault->state->mm->mmap_sem); 550 mm = fault->state->mm;
521 npages = get_user_pages(NULL, fault->state->mm, 551 address = fault->address;
522 fault->address, 1, write, 0, &page, NULL); 552
523 up_read(&fault->state->mm->mmap_sem); 553 down_read(&mm->mmap_sem);
524 554 vma = find_extend_vma(mm, address);
525 if (npages == 1) { 555 if (!vma || address < vma->vm_start) {
526 put_page(page); 556 /* failed to get a vma in the right range */
527 } else if (fault->dev_state->inv_ppr_cb) { 557 up_read(&mm->mmap_sem);
528 int status; 558 handle_fault_error(fault);
529 559 goto out;
530 status = fault->dev_state->inv_ppr_cb(fault->dev_state->pdev, 560 }
531 fault->pasid, 561
532 fault->address, 562 ret = handle_mm_fault(mm, vma, address, write);
533 fault->flags); 563 if (ret & VM_FAULT_ERROR) {
534 switch (status) { 564 /* failed to service fault */
535 case AMD_IOMMU_INV_PRI_RSP_SUCCESS: 565 up_read(&mm->mmap_sem);
536 set_pri_tag_status(fault->state, fault->tag, PPR_SUCCESS); 566 handle_fault_error(fault);
537 break; 567 goto out;
538 case AMD_IOMMU_INV_PRI_RSP_INVALID:
539 set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
540 break;
541 case AMD_IOMMU_INV_PRI_RSP_FAIL:
542 set_pri_tag_status(fault->state, fault->tag, PPR_FAILURE);
543 break;
544 default:
545 BUG();
546 }
547 } else {
548 set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
549 } 568 }
550 569
570 up_read(&mm->mmap_sem);
571
572out:
551 finish_pri_tag(fault->dev_state, fault->state, fault->tag); 573 finish_pri_tag(fault->dev_state, fault->state, fault->tag);
552 574
553 put_pasid_state(fault->state); 575 put_pasid_state(fault->state);