aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2014-12-12 19:55:30 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-13 15:42:47 -0500
commit9dc00f4c4fdd1fab12a4da9a966e535b4284b0a4 (patch)
tree6e6871cebe9412215e85709ce37181a1dea6e07d /drivers/iommu
parente1d6d01ab491bee6cfa02f2c10db50f31de85e79 (diff)
iommu/amd: use handle_mm_fault directly
This could be useful for debug in the future if we want to track major/minor faults more closely, and also avoids the put_page trick we used with gup. In order to do this, we also track the task struct in the PASID state structure. This lets us update the appropriate task stats after the fault has been handled, and may aid with debug in the future as well. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Tested-by: Oded Gabbay <oded.gabbay@amd.com> Cc: Joerg Roedel <jroedel@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/iommu')
-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 90d734bbf467..9c0d6e290097 100644
--- a/drivers/iommu/amd_iommu_v2.c
+++ b/drivers/iommu/amd_iommu_v2.c
@@ -513,45 +513,67 @@ static void finish_pri_tag(struct device_state *dev_state,
513 spin_unlock_irqrestore(&pasid_state->lock, flags); 513 spin_unlock_irqrestore(&pasid_state->lock, flags);
514} 514}
515 515
516static void handle_fault_error(struct fault *fault)
517{
518 int status;
519
520 if (!fault->dev_state->inv_ppr_cb) {
521 set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
522 return;
523 }
524
525 status = fault->dev_state->inv_ppr_cb(fault->dev_state->pdev,
526 fault->pasid,
527 fault->address,
528 fault->flags);
529 switch (status) {
530 case AMD_IOMMU_INV_PRI_RSP_SUCCESS:
531 set_pri_tag_status(fault->state, fault->tag, PPR_SUCCESS);
532 break;
533 case AMD_IOMMU_INV_PRI_RSP_INVALID:
534 set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
535 break;
536 case AMD_IOMMU_INV_PRI_RSP_FAIL:
537 set_pri_tag_status(fault->state, fault->tag, PPR_FAILURE);
538 break;
539 default:
540 BUG();
541 }
542}
543
516static void do_fault(struct work_struct *work) 544static void do_fault(struct work_struct *work)
517{ 545{
518 struct fault *fault = container_of(work, struct fault, work); 546 struct fault *fault = container_of(work, struct fault, work);
519 int npages, write; 547 struct mm_struct *mm;
520 struct page *page; 548 struct vm_area_struct *vma;
549 u64 address;
550 int ret, write;
521 551
522 write = !!(fault->flags & PPR_FAULT_WRITE); 552 write = !!(fault->flags & PPR_FAULT_WRITE);
523 553
524 down_read(&fault->state->mm->mmap_sem); 554 mm = fault->state->mm;
525 npages = get_user_pages(NULL, fault->state->mm, 555 address = fault->address;
526 fault->address, 1, write, 0, &page, NULL); 556
527 up_read(&fault->state->mm->mmap_sem); 557 down_read(&mm->mmap_sem);
528 558 vma = find_extend_vma(mm, address);
529 if (npages == 1) { 559 if (!vma || address < vma->vm_start) {
530 put_page(page); 560 /* failed to get a vma in the right range */
531 } else if (fault->dev_state->inv_ppr_cb) { 561 up_read(&mm->mmap_sem);
532 int status; 562 handle_fault_error(fault);
533 563 goto out;
534 status = fault->dev_state->inv_ppr_cb(fault->dev_state->pdev, 564 }
535 fault->pasid, 565
536 fault->address, 566 ret = handle_mm_fault(mm, vma, address, write);
537 fault->flags); 567 if (ret & VM_FAULT_ERROR) {
538 switch (status) { 568 /* failed to service fault */
539 case AMD_IOMMU_INV_PRI_RSP_SUCCESS: 569 up_read(&mm->mmap_sem);
540 set_pri_tag_status(fault->state, fault->tag, PPR_SUCCESS); 570 handle_fault_error(fault);
541 break; 571 goto out;
542 case AMD_IOMMU_INV_PRI_RSP_INVALID:
543 set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
544 break;
545 case AMD_IOMMU_INV_PRI_RSP_FAIL:
546 set_pri_tag_status(fault->state, fault->tag, PPR_FAILURE);
547 break;
548 default:
549 BUG();
550 }
551 } else {
552 set_pri_tag_status(fault->state, fault->tag, PPR_INVALID);
553 } 572 }
554 573
574 up_read(&mm->mmap_sem);
575
576out:
555 finish_pri_tag(fault->dev_state, fault->state, fault->tag); 577 finish_pri_tag(fault->dev_state, fault->state, fault->tag);
556 578
557 put_pasid_state(fault->state); 579 put_pasid_state(fault->state);