diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2009-05-10 14:58:49 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-05-10 14:58:49 -0400 |
commit | 1f0ef2aa18802a8ce7eb5a5164aaaf4d59073801 (patch) | |
tree | 953fd29f1853b0773e9dcd72ab1ecb3231c6b457 | |
parent | 4c25a2c1b90bf785fc2e2f0f0c74a80b3e070d39 (diff) |
intel-iommu: Clean up handling of "caching mode" vs. IOTLB flushing.
As we just did for context cache flushing, clean up the logic around
whether we need to flush the iotlb or just the write-buffer, depending
on caching mode.
Fix the same bug in qi_flush_iotlb() that qi_flush_context() had -- it
isn't supposed to be returning an error; it's supposed to be returning a
flag which triggers a write-buffer flush.
Remove some superfluous conditional write-buffer flushes which could
never have happened because they weren't for non-present-to-present
mapping changes anyway.
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r-- | drivers/pci/dmar.c | 14 | ||||
-rw-r--r-- | drivers/pci/intel-iommu.c | 78 | ||||
-rw-r--r-- | include/linux/intel-iommu.h | 9 |
3 files changed, 37 insertions, 64 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 10a071ba3232..df6af0d4ec03 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -735,22 +735,14 @@ void qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm, | |||
735 | qi_submit_sync(&desc, iommu); | 735 | qi_submit_sync(&desc, iommu); |
736 | } | 736 | } |
737 | 737 | ||
738 | int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, | 738 | void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, |
739 | unsigned int size_order, u64 type, | 739 | unsigned int size_order, u64 type) |
740 | int non_present_entry_flush) | ||
741 | { | 740 | { |
742 | u8 dw = 0, dr = 0; | 741 | u8 dw = 0, dr = 0; |
743 | 742 | ||
744 | struct qi_desc desc; | 743 | struct qi_desc desc; |
745 | int ih = 0; | 744 | int ih = 0; |
746 | 745 | ||
747 | if (non_present_entry_flush) { | ||
748 | if (!cap_caching_mode(iommu->cap)) | ||
749 | return 1; | ||
750 | else | ||
751 | did = 0; | ||
752 | } | ||
753 | |||
754 | if (cap_write_drain(iommu->cap)) | 746 | if (cap_write_drain(iommu->cap)) |
755 | dw = 1; | 747 | dw = 1; |
756 | 748 | ||
@@ -762,7 +754,7 @@ int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, | |||
762 | desc.high = QI_IOTLB_ADDR(addr) | QI_IOTLB_IH(ih) | 754 | desc.high = QI_IOTLB_ADDR(addr) | QI_IOTLB_IH(ih) |
763 | | QI_IOTLB_AM(size_order); | 755 | | QI_IOTLB_AM(size_order); |
764 | 756 | ||
765 | return qi_submit_sync(&desc, iommu); | 757 | qi_submit_sync(&desc, iommu); |
766 | } | 758 | } |
767 | 759 | ||
768 | /* | 760 | /* |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 9f5d9151edc9..f47d04aced87 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -891,27 +891,13 @@ static void __iommu_flush_context(struct intel_iommu *iommu, | |||
891 | } | 891 | } |
892 | 892 | ||
893 | /* return value determine if we need a write buffer flush */ | 893 | /* return value determine if we need a write buffer flush */ |
894 | static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, | 894 | static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, |
895 | u64 addr, unsigned int size_order, u64 type, | 895 | u64 addr, unsigned int size_order, u64 type) |
896 | int non_present_entry_flush) | ||
897 | { | 896 | { |
898 | int tlb_offset = ecap_iotlb_offset(iommu->ecap); | 897 | int tlb_offset = ecap_iotlb_offset(iommu->ecap); |
899 | u64 val = 0, val_iva = 0; | 898 | u64 val = 0, val_iva = 0; |
900 | unsigned long flag; | 899 | unsigned long flag; |
901 | 900 | ||
902 | /* | ||
903 | * In the non-present entry flush case, if hardware doesn't cache | ||
904 | * non-present entry we do nothing and if hardware cache non-present | ||
905 | * entry, we flush entries of domain 0 (the domain id is used to cache | ||
906 | * any non-present entries) | ||
907 | */ | ||
908 | if (non_present_entry_flush) { | ||
909 | if (!cap_caching_mode(iommu->cap)) | ||
910 | return 1; | ||
911 | else | ||
912 | did = 0; | ||
913 | } | ||
914 | |||
915 | switch (type) { | 901 | switch (type) { |
916 | case DMA_TLB_GLOBAL_FLUSH: | 902 | case DMA_TLB_GLOBAL_FLUSH: |
917 | /* global flush doesn't need set IVA_REG */ | 903 | /* global flush doesn't need set IVA_REG */ |
@@ -959,12 +945,10 @@ static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, | |||
959 | pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n", | 945 | pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n", |
960 | (unsigned long long)DMA_TLB_IIRG(type), | 946 | (unsigned long long)DMA_TLB_IIRG(type), |
961 | (unsigned long long)DMA_TLB_IAIG(val)); | 947 | (unsigned long long)DMA_TLB_IAIG(val)); |
962 | /* flush iotlb entry will implicitly flush write buffer */ | ||
963 | return 0; | ||
964 | } | 948 | } |
965 | 949 | ||
966 | static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, | 950 | static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, |
967 | u64 addr, unsigned int pages, int non_present_entry_flush) | 951 | u64 addr, unsigned int pages) |
968 | { | 952 | { |
969 | unsigned int mask; | 953 | unsigned int mask; |
970 | 954 | ||
@@ -974,8 +958,7 @@ static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, | |||
974 | /* Fallback to domain selective flush if no PSI support */ | 958 | /* Fallback to domain selective flush if no PSI support */ |
975 | if (!cap_pgsel_inv(iommu->cap)) | 959 | if (!cap_pgsel_inv(iommu->cap)) |
976 | return iommu->flush.flush_iotlb(iommu, did, 0, 0, | 960 | return iommu->flush.flush_iotlb(iommu, did, 0, 0, |
977 | DMA_TLB_DSI_FLUSH, | 961 | DMA_TLB_DSI_FLUSH); |
978 | non_present_entry_flush); | ||
979 | 962 | ||
980 | /* | 963 | /* |
981 | * PSI requires page size to be 2 ^ x, and the base address is naturally | 964 | * PSI requires page size to be 2 ^ x, and the base address is naturally |
@@ -985,11 +968,10 @@ static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, | |||
985 | /* Fallback to domain selective flush if size is too big */ | 968 | /* Fallback to domain selective flush if size is too big */ |
986 | if (mask > cap_max_amask_val(iommu->cap)) | 969 | if (mask > cap_max_amask_val(iommu->cap)) |
987 | return iommu->flush.flush_iotlb(iommu, did, 0, 0, | 970 | return iommu->flush.flush_iotlb(iommu, did, 0, 0, |
988 | DMA_TLB_DSI_FLUSH, non_present_entry_flush); | 971 | DMA_TLB_DSI_FLUSH); |
989 | 972 | ||
990 | return iommu->flush.flush_iotlb(iommu, did, addr, mask, | 973 | return iommu->flush.flush_iotlb(iommu, did, addr, mask, |
991 | DMA_TLB_PSI_FLUSH, | 974 | DMA_TLB_PSI_FLUSH); |
992 | non_present_entry_flush); | ||
993 | } | 975 | } |
994 | 976 | ||
995 | static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu) | 977 | static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu) |
@@ -1423,7 +1405,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment, | |||
1423 | (((u16)bus) << 8) | devfn, | 1405 | (((u16)bus) << 8) | devfn, |
1424 | DMA_CCMD_MASK_NOBIT, | 1406 | DMA_CCMD_MASK_NOBIT, |
1425 | DMA_CCMD_DEVICE_INVL); | 1407 | DMA_CCMD_DEVICE_INVL); |
1426 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH, 0); | 1408 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH); |
1427 | } else { | 1409 | } else { |
1428 | iommu_flush_write_buffer(iommu); | 1410 | iommu_flush_write_buffer(iommu); |
1429 | } | 1411 | } |
@@ -1558,8 +1540,7 @@ static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn) | |||
1558 | clear_context_table(iommu, bus, devfn); | 1540 | clear_context_table(iommu, bus, devfn); |
1559 | iommu->flush.flush_context(iommu, 0, 0, 0, | 1541 | iommu->flush.flush_context(iommu, 0, 0, 0, |
1560 | DMA_CCMD_GLOBAL_INVL); | 1542 | DMA_CCMD_GLOBAL_INVL); |
1561 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, | 1543 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); |
1562 | DMA_TLB_GLOBAL_FLUSH, 0); | ||
1563 | } | 1544 | } |
1564 | 1545 | ||
1565 | static void domain_remove_dev_info(struct dmar_domain *domain) | 1546 | static void domain_remove_dev_info(struct dmar_domain *domain) |
@@ -2096,8 +2077,7 @@ static int __init init_dmars(void) | |||
2096 | iommu_set_root_entry(iommu); | 2077 | iommu_set_root_entry(iommu); |
2097 | 2078 | ||
2098 | iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL); | 2079 | iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL); |
2099 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH, | 2080 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); |
2100 | 0); | ||
2101 | iommu_disable_protect_mem_regions(iommu); | 2081 | iommu_disable_protect_mem_regions(iommu); |
2102 | 2082 | ||
2103 | ret = iommu_enable_translation(iommu); | 2083 | ret = iommu_enable_translation(iommu); |
@@ -2244,10 +2224,11 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, | |||
2244 | if (ret) | 2224 | if (ret) |
2245 | goto error; | 2225 | goto error; |
2246 | 2226 | ||
2247 | /* it's a non-present to present mapping */ | 2227 | /* it's a non-present to present mapping. Only flush if caching mode */ |
2248 | ret = iommu_flush_iotlb_psi(iommu, domain->id, | 2228 | if (cap_caching_mode(iommu->cap)) |
2249 | start_paddr, size >> VTD_PAGE_SHIFT, 1); | 2229 | iommu_flush_iotlb_psi(iommu, 0, start_paddr, |
2250 | if (ret) | 2230 | size >> VTD_PAGE_SHIFT); |
2231 | else | ||
2251 | iommu_flush_write_buffer(iommu); | 2232 | iommu_flush_write_buffer(iommu); |
2252 | 2233 | ||
2253 | return start_paddr + ((u64)paddr & (~PAGE_MASK)); | 2234 | return start_paddr + ((u64)paddr & (~PAGE_MASK)); |
@@ -2283,7 +2264,7 @@ static void flush_unmaps(void) | |||
2283 | 2264 | ||
2284 | if (deferred_flush[i].next) { | 2265 | if (deferred_flush[i].next) { |
2285 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, | 2266 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, |
2286 | DMA_TLB_GLOBAL_FLUSH, 0); | 2267 | DMA_TLB_GLOBAL_FLUSH); |
2287 | for (j = 0; j < deferred_flush[i].next; j++) { | 2268 | for (j = 0; j < deferred_flush[i].next; j++) { |
2288 | __free_iova(&deferred_flush[i].domain[j]->iovad, | 2269 | __free_iova(&deferred_flush[i].domain[j]->iovad, |
2289 | deferred_flush[i].iova[j]); | 2270 | deferred_flush[i].iova[j]); |
@@ -2362,9 +2343,8 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, | |||
2362 | /* free page tables */ | 2343 | /* free page tables */ |
2363 | dma_pte_free_pagetable(domain, start_addr, start_addr + size); | 2344 | dma_pte_free_pagetable(domain, start_addr, start_addr + size); |
2364 | if (intel_iommu_strict) { | 2345 | if (intel_iommu_strict) { |
2365 | if (iommu_flush_iotlb_psi(iommu, | 2346 | iommu_flush_iotlb_psi(iommu, domain->id, start_addr, |
2366 | domain->id, start_addr, size >> VTD_PAGE_SHIFT, 0)) | 2347 | size >> VTD_PAGE_SHIFT); |
2367 | iommu_flush_write_buffer(iommu); | ||
2368 | /* free iova */ | 2348 | /* free iova */ |
2369 | __free_iova(&domain->iovad, iova); | 2349 | __free_iova(&domain->iovad, iova); |
2370 | } else { | 2350 | } else { |
@@ -2455,9 +2435,8 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, | |||
2455 | /* free page tables */ | 2435 | /* free page tables */ |
2456 | dma_pte_free_pagetable(domain, start_addr, start_addr + size); | 2436 | dma_pte_free_pagetable(domain, start_addr, start_addr + size); |
2457 | 2437 | ||
2458 | if (iommu_flush_iotlb_psi(iommu, domain->id, start_addr, | 2438 | iommu_flush_iotlb_psi(iommu, domain->id, start_addr, |
2459 | size >> VTD_PAGE_SHIFT, 0)) | 2439 | size >> VTD_PAGE_SHIFT); |
2460 | iommu_flush_write_buffer(iommu); | ||
2461 | 2440 | ||
2462 | /* free iova */ | 2441 | /* free iova */ |
2463 | __free_iova(&domain->iovad, iova); | 2442 | __free_iova(&domain->iovad, iova); |
@@ -2549,10 +2528,13 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne | |||
2549 | offset += size; | 2528 | offset += size; |
2550 | } | 2529 | } |
2551 | 2530 | ||
2552 | /* it's a non-present to present mapping */ | 2531 | /* it's a non-present to present mapping. Only flush if caching mode */ |
2553 | if (iommu_flush_iotlb_psi(iommu, domain->id, | 2532 | if (cap_caching_mode(iommu->cap)) |
2554 | start_addr, offset >> VTD_PAGE_SHIFT, 1)) | 2533 | iommu_flush_iotlb_psi(iommu, 0, start_addr, |
2534 | offset >> VTD_PAGE_SHIFT); | ||
2535 | else | ||
2555 | iommu_flush_write_buffer(iommu); | 2536 | iommu_flush_write_buffer(iommu); |
2537 | |||
2556 | return nelems; | 2538 | return nelems; |
2557 | } | 2539 | } |
2558 | 2540 | ||
@@ -2711,9 +2693,9 @@ static int init_iommu_hw(void) | |||
2711 | iommu_set_root_entry(iommu); | 2693 | iommu_set_root_entry(iommu); |
2712 | 2694 | ||
2713 | iommu->flush.flush_context(iommu, 0, 0, 0, | 2695 | iommu->flush.flush_context(iommu, 0, 0, 0, |
2714 | DMA_CCMD_GLOBAL_INVL); | 2696 | DMA_CCMD_GLOBAL_INVL); |
2715 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, | 2697 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, |
2716 | DMA_TLB_GLOBAL_FLUSH, 0); | 2698 | DMA_TLB_GLOBAL_FLUSH); |
2717 | iommu_disable_protect_mem_regions(iommu); | 2699 | iommu_disable_protect_mem_regions(iommu); |
2718 | iommu_enable_translation(iommu); | 2700 | iommu_enable_translation(iommu); |
2719 | } | 2701 | } |
@@ -2728,9 +2710,9 @@ static void iommu_flush_all(void) | |||
2728 | 2710 | ||
2729 | for_each_active_iommu(iommu, drhd) { | 2711 | for_each_active_iommu(iommu, drhd) { |
2730 | iommu->flush.flush_context(iommu, 0, 0, 0, | 2712 | iommu->flush.flush_context(iommu, 0, 0, 0, |
2731 | DMA_CCMD_GLOBAL_INVL); | 2713 | DMA_CCMD_GLOBAL_INVL); |
2732 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, | 2714 | iommu->flush.flush_iotlb(iommu, 0, 0, 0, |
2733 | DMA_TLB_GLOBAL_FLUSH, 0); | 2715 | DMA_TLB_GLOBAL_FLUSH); |
2734 | } | 2716 | } |
2735 | } | 2717 | } |
2736 | 2718 | ||
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index f2b94dafbf38..29e05a034c09 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h | |||
@@ -283,8 +283,8 @@ struct ir_table { | |||
283 | struct iommu_flush { | 283 | struct iommu_flush { |
284 | void (*flush_context)(struct intel_iommu *iommu, u16 did, u16 sid, | 284 | void (*flush_context)(struct intel_iommu *iommu, u16 did, u16 sid, |
285 | u8 fm, u64 type); | 285 | u8 fm, u64 type); |
286 | int (*flush_iotlb)(struct intel_iommu *iommu, u16 did, u64 addr, | 286 | void (*flush_iotlb)(struct intel_iommu *iommu, u16 did, u64 addr, |
287 | unsigned int size_order, u64 type, int non_present_entry_flush); | 287 | unsigned int size_order, u64 type); |
288 | }; | 288 | }; |
289 | 289 | ||
290 | enum { | 290 | enum { |
@@ -341,9 +341,8 @@ extern void qi_global_iec(struct intel_iommu *iommu); | |||
341 | 341 | ||
342 | extern void qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, | 342 | extern void qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, |
343 | u8 fm, u64 type); | 343 | u8 fm, u64 type); |
344 | extern int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, | 344 | extern void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, |
345 | unsigned int size_order, u64 type, | 345 | unsigned int size_order, u64 type); |
346 | int non_present_entry_flush); | ||
347 | 346 | ||
348 | extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu); | 347 | extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu); |
349 | 348 | ||