diff options
author | Joerg Roedel <jroedel@suse.de> | 2016-07-07 12:01:10 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-07-13 06:46:05 -0400 |
commit | 81cd07b9c92ad446fcde18db7de961def0dbcfd3 (patch) | |
tree | a216c8634fa4034fb214ba9692eb5e4b7360874e /drivers/iommu/amd_iommu.c | |
parent | 307d5851ef74c6c06a68f50302bf19809966d345 (diff) |
iommu/amd: Create a list of reserved iova addresses
Put the MSI-range, the HT-range and the MMIO ranges of PCI
devices into that range, so that these addresses are not
allocated for DMA.
Copy this address list into every created dma_ops_domain.
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu/amd_iommu.c')
-rw-r--r-- | drivers/iommu/amd_iommu.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index e7825b25c62f..1bb59ae2d586 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
@@ -63,6 +63,12 @@ | |||
63 | #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) | 63 | #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) |
64 | #define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32)) | 64 | #define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32)) |
65 | 65 | ||
66 | /* Reserved IOVA ranges */ | ||
67 | #define MSI_RANGE_START (0xfee00000) | ||
68 | #define MSI_RANGE_END (0xfeefffff) | ||
69 | #define HT_RANGE_START (0xfd00000000ULL) | ||
70 | #define HT_RANGE_END (0xffffffffffULL) | ||
71 | |||
66 | /* | 72 | /* |
67 | * This bitmap is used to advertise the page sizes our hardware support | 73 | * This bitmap is used to advertise the page sizes our hardware support |
68 | * to the IOMMU core, which will then use this information to split | 74 | * to the IOMMU core, which will then use this information to split |
@@ -169,6 +175,9 @@ struct dma_ops_domain { | |||
169 | struct iova_domain iovad; | 175 | struct iova_domain iovad; |
170 | }; | 176 | }; |
171 | 177 | ||
178 | static struct iova_domain reserved_iova_ranges; | ||
179 | static struct lock_class_key reserved_rbtree_key; | ||
180 | |||
172 | /**************************************************************************** | 181 | /**************************************************************************** |
173 | * | 182 | * |
174 | * Helper functions | 183 | * Helper functions |
@@ -2058,6 +2067,9 @@ static struct dma_ops_domain *dma_ops_domain_alloc(void) | |||
2058 | init_iova_domain(&dma_dom->iovad, PAGE_SIZE, | 2067 | init_iova_domain(&dma_dom->iovad, PAGE_SIZE, |
2059 | IOVA_START_PFN, DMA_32BIT_PFN); | 2068 | IOVA_START_PFN, DMA_32BIT_PFN); |
2060 | 2069 | ||
2070 | /* Initialize reserved ranges */ | ||
2071 | copy_reserved_iova(&reserved_iova_ranges, &dma_dom->iovad); | ||
2072 | |||
2061 | return dma_dom; | 2073 | return dma_dom; |
2062 | 2074 | ||
2063 | free_dma_dom: | 2075 | free_dma_dom: |
@@ -2963,6 +2975,59 @@ static struct dma_map_ops amd_iommu_dma_ops = { | |||
2963 | .set_dma_mask = set_dma_mask, | 2975 | .set_dma_mask = set_dma_mask, |
2964 | }; | 2976 | }; |
2965 | 2977 | ||
2978 | static int init_reserved_iova_ranges(void) | ||
2979 | { | ||
2980 | struct pci_dev *pdev = NULL; | ||
2981 | struct iova *val; | ||
2982 | |||
2983 | init_iova_domain(&reserved_iova_ranges, PAGE_SIZE, | ||
2984 | IOVA_START_PFN, DMA_32BIT_PFN); | ||
2985 | |||
2986 | lockdep_set_class(&reserved_iova_ranges.iova_rbtree_lock, | ||
2987 | &reserved_rbtree_key); | ||
2988 | |||
2989 | /* MSI memory range */ | ||
2990 | val = reserve_iova(&reserved_iova_ranges, | ||
2991 | IOVA_PFN(MSI_RANGE_START), IOVA_PFN(MSI_RANGE_END)); | ||
2992 | if (!val) { | ||
2993 | pr_err("Reserving MSI range failed\n"); | ||
2994 | return -ENOMEM; | ||
2995 | } | ||
2996 | |||
2997 | /* HT memory range */ | ||
2998 | val = reserve_iova(&reserved_iova_ranges, | ||
2999 | IOVA_PFN(HT_RANGE_START), IOVA_PFN(HT_RANGE_END)); | ||
3000 | if (!val) { | ||
3001 | pr_err("Reserving HT range failed\n"); | ||
3002 | return -ENOMEM; | ||
3003 | } | ||
3004 | |||
3005 | /* | ||
3006 | * Memory used for PCI resources | ||
3007 | * FIXME: Check whether we can reserve the PCI-hole completly | ||
3008 | */ | ||
3009 | for_each_pci_dev(pdev) { | ||
3010 | int i; | ||
3011 | |||
3012 | for (i = 0; i < PCI_NUM_RESOURCES; ++i) { | ||
3013 | struct resource *r = &pdev->resource[i]; | ||
3014 | |||
3015 | if (!(r->flags & IORESOURCE_MEM)) | ||
3016 | continue; | ||
3017 | |||
3018 | val = reserve_iova(&reserved_iova_ranges, | ||
3019 | IOVA_PFN(r->start), | ||
3020 | IOVA_PFN(r->end)); | ||
3021 | if (!val) { | ||
3022 | pr_err("Reserve pci-resource range failed\n"); | ||
3023 | return -ENOMEM; | ||
3024 | } | ||
3025 | } | ||
3026 | } | ||
3027 | |||
3028 | return 0; | ||
3029 | } | ||
3030 | |||
2966 | int __init amd_iommu_init_api(void) | 3031 | int __init amd_iommu_init_api(void) |
2967 | { | 3032 | { |
2968 | int ret, err = 0; | 3033 | int ret, err = 0; |
@@ -2971,6 +3036,10 @@ int __init amd_iommu_init_api(void) | |||
2971 | if (ret) | 3036 | if (ret) |
2972 | return ret; | 3037 | return ret; |
2973 | 3038 | ||
3039 | ret = init_reserved_iova_ranges(); | ||
3040 | if (ret) | ||
3041 | return ret; | ||
3042 | |||
2974 | err = bus_set_iommu(&pci_bus_type, &amd_iommu_ops); | 3043 | err = bus_set_iommu(&pci_bus_type, &amd_iommu_ops); |
2975 | if (err) | 3044 | if (err) |
2976 | return err; | 3045 | return err; |