diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 17:34:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 17:34:25 -0400 |
commit | 7474043eff6f7c20141b2f49f774d0aab6542220 (patch) | |
tree | f143f787c7ff3ee6c8fede1bd2fd60c36b328243 | |
parent | b9f2b21a32906a47c220b5167b88869f2c90f1c4 (diff) | |
parent | 68efd7d2fb32c2606f1da318b6a851d933813f27 (diff) |
Merge branch 'for-3.15' of git://git.linaro.org/people/mszyprowski/linux-dma-mapping
Pull DMA-mapping updates from Marek Szyprowski:
"This contains extension for more efficient handling of io address
space for dma-mapping subsystem for ARM architecture"
* 'for-3.15' of git://git.linaro.org/people/mszyprowski/linux-dma-mapping:
arm: dma-mapping: remove order parameter from arm_iommu_create_mapping()
arm: dma-mapping: Add support to extend DMA IOMMU mappings
-rw-r--r-- | arch/arm/include/asm/dma-iommu.h | 12 | ||||
-rw-r--r-- | arch/arm/mm/dma-mapping.c | 144 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_iommu.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_iommu.h | 1 | ||||
-rw-r--r-- | drivers/iommu/shmobile-iommu.c | 2 |
6 files changed, 124 insertions, 43 deletions
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h index a8c56acc8c98..eec0a12c5c1d 100644 --- a/arch/arm/include/asm/dma-iommu.h +++ b/arch/arm/include/asm/dma-iommu.h | |||
@@ -13,9 +13,12 @@ struct dma_iommu_mapping { | |||
13 | /* iommu specific data */ | 13 | /* iommu specific data */ |
14 | struct iommu_domain *domain; | 14 | struct iommu_domain *domain; |
15 | 15 | ||
16 | void *bitmap; | 16 | unsigned long **bitmaps; /* array of bitmaps */ |
17 | size_t bits; | 17 | unsigned int nr_bitmaps; /* nr of elements in array */ |
18 | unsigned int order; | 18 | unsigned int extensions; |
19 | size_t bitmap_size; /* size of a single bitmap */ | ||
20 | size_t bits; /* per bitmap */ | ||
21 | unsigned int size; /* per bitmap */ | ||
19 | dma_addr_t base; | 22 | dma_addr_t base; |
20 | 23 | ||
21 | spinlock_t lock; | 24 | spinlock_t lock; |
@@ -23,8 +26,7 @@ struct dma_iommu_mapping { | |||
23 | }; | 26 | }; |
24 | 27 | ||
25 | struct dma_iommu_mapping * | 28 | struct dma_iommu_mapping * |
26 | arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size, | 29 | arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size); |
27 | int order); | ||
28 | 30 | ||
29 | void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping); | 31 | void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping); |
30 | 32 | ||
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 11b3914660d2..4fe42ce720d2 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c | |||
@@ -1069,6 +1069,8 @@ fs_initcall(dma_debug_do_init); | |||
1069 | 1069 | ||
1070 | /* IOMMU */ | 1070 | /* IOMMU */ |
1071 | 1071 | ||
1072 | static int extend_iommu_mapping(struct dma_iommu_mapping *mapping); | ||
1073 | |||
1072 | static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, | 1074 | static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, |
1073 | size_t size) | 1075 | size_t size) |
1074 | { | 1076 | { |
@@ -1076,41 +1078,87 @@ static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, | |||
1076 | unsigned int align = 0; | 1078 | unsigned int align = 0; |
1077 | unsigned int count, start; | 1079 | unsigned int count, start; |
1078 | unsigned long flags; | 1080 | unsigned long flags; |
1081 | dma_addr_t iova; | ||
1082 | int i; | ||
1079 | 1083 | ||
1080 | if (order > CONFIG_ARM_DMA_IOMMU_ALIGNMENT) | 1084 | if (order > CONFIG_ARM_DMA_IOMMU_ALIGNMENT) |
1081 | order = CONFIG_ARM_DMA_IOMMU_ALIGNMENT; | 1085 | order = CONFIG_ARM_DMA_IOMMU_ALIGNMENT; |
1082 | 1086 | ||
1083 | count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) + | 1087 | count = PAGE_ALIGN(size) >> PAGE_SHIFT; |
1084 | (1 << mapping->order) - 1) >> mapping->order; | 1088 | align = (1 << order) - 1; |
1085 | |||
1086 | if (order > mapping->order) | ||
1087 | align = (1 << (order - mapping->order)) - 1; | ||
1088 | 1089 | ||
1089 | spin_lock_irqsave(&mapping->lock, flags); | 1090 | spin_lock_irqsave(&mapping->lock, flags); |
1090 | start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0, | 1091 | for (i = 0; i < mapping->nr_bitmaps; i++) { |
1091 | count, align); | 1092 | start = bitmap_find_next_zero_area(mapping->bitmaps[i], |
1092 | if (start > mapping->bits) { | 1093 | mapping->bits, 0, count, align); |
1093 | spin_unlock_irqrestore(&mapping->lock, flags); | 1094 | |
1094 | return DMA_ERROR_CODE; | 1095 | if (start > mapping->bits) |
1096 | continue; | ||
1097 | |||
1098 | bitmap_set(mapping->bitmaps[i], start, count); | ||
1099 | break; | ||
1095 | } | 1100 | } |
1096 | 1101 | ||
1097 | bitmap_set(mapping->bitmap, start, count); | 1102 | /* |
1103 | * No unused range found. Try to extend the existing mapping | ||
1104 | * and perform a second attempt to reserve an IO virtual | ||
1105 | * address range of size bytes. | ||
1106 | */ | ||
1107 | if (i == mapping->nr_bitmaps) { | ||
1108 | if (extend_iommu_mapping(mapping)) { | ||
1109 | spin_unlock_irqrestore(&mapping->lock, flags); | ||
1110 | return DMA_ERROR_CODE; | ||
1111 | } | ||
1112 | |||
1113 | start = bitmap_find_next_zero_area(mapping->bitmaps[i], | ||
1114 | mapping->bits, 0, count, align); | ||
1115 | |||
1116 | if (start > mapping->bits) { | ||
1117 | spin_unlock_irqrestore(&mapping->lock, flags); | ||
1118 | return DMA_ERROR_CODE; | ||
1119 | } | ||
1120 | |||
1121 | bitmap_set(mapping->bitmaps[i], start, count); | ||
1122 | } | ||
1098 | spin_unlock_irqrestore(&mapping->lock, flags); | 1123 | spin_unlock_irqrestore(&mapping->lock, flags); |
1099 | 1124 | ||
1100 | return mapping->base + (start << (mapping->order + PAGE_SHIFT)); | 1125 | iova = mapping->base + (mapping->size * i); |
1126 | iova += start << PAGE_SHIFT; | ||
1127 | |||
1128 | return iova; | ||
1101 | } | 1129 | } |
1102 | 1130 | ||
1103 | static inline void __free_iova(struct dma_iommu_mapping *mapping, | 1131 | static inline void __free_iova(struct dma_iommu_mapping *mapping, |
1104 | dma_addr_t addr, size_t size) | 1132 | dma_addr_t addr, size_t size) |
1105 | { | 1133 | { |
1106 | unsigned int start = (addr - mapping->base) >> | 1134 | unsigned int start, count; |
1107 | (mapping->order + PAGE_SHIFT); | ||
1108 | unsigned int count = ((size >> PAGE_SHIFT) + | ||
1109 | (1 << mapping->order) - 1) >> mapping->order; | ||
1110 | unsigned long flags; | 1135 | unsigned long flags; |
1136 | dma_addr_t bitmap_base; | ||
1137 | u32 bitmap_index; | ||
1138 | |||
1139 | if (!size) | ||
1140 | return; | ||
1141 | |||
1142 | bitmap_index = (u32) (addr - mapping->base) / (u32) mapping->size; | ||
1143 | BUG_ON(addr < mapping->base || bitmap_index > mapping->extensions); | ||
1144 | |||
1145 | bitmap_base = mapping->base + mapping->size * bitmap_index; | ||
1146 | |||
1147 | start = (addr - bitmap_base) >> PAGE_SHIFT; | ||
1148 | |||
1149 | if (addr + size > bitmap_base + mapping->size) { | ||
1150 | /* | ||
1151 | * The address range to be freed reaches into the iova | ||
1152 | * range of the next bitmap. This should not happen as | ||
1153 | * we don't allow this in __alloc_iova (at the | ||
1154 | * moment). | ||
1155 | */ | ||
1156 | BUG(); | ||
1157 | } else | ||
1158 | count = size >> PAGE_SHIFT; | ||
1111 | 1159 | ||
1112 | spin_lock_irqsave(&mapping->lock, flags); | 1160 | spin_lock_irqsave(&mapping->lock, flags); |
1113 | bitmap_clear(mapping->bitmap, start, count); | 1161 | bitmap_clear(mapping->bitmaps[bitmap_index], start, count); |
1114 | spin_unlock_irqrestore(&mapping->lock, flags); | 1162 | spin_unlock_irqrestore(&mapping->lock, flags); |
1115 | } | 1163 | } |
1116 | 1164 | ||
@@ -1875,8 +1923,7 @@ struct dma_map_ops iommu_coherent_ops = { | |||
1875 | * arm_iommu_create_mapping | 1923 | * arm_iommu_create_mapping |
1876 | * @bus: pointer to the bus holding the client device (for IOMMU calls) | 1924 | * @bus: pointer to the bus holding the client device (for IOMMU calls) |
1877 | * @base: start address of the valid IO address space | 1925 | * @base: start address of the valid IO address space |
1878 | * @size: size of the valid IO address space | 1926 | * @size: maximum size of the valid IO address space |
1879 | * @order: accuracy of the IO addresses allocations | ||
1880 | * | 1927 | * |
1881 | * Creates a mapping structure which holds information about used/unused | 1928 | * Creates a mapping structure which holds information about used/unused |
1882 | * IO address ranges, which is required to perform memory allocation and | 1929 | * IO address ranges, which is required to perform memory allocation and |
@@ -1886,38 +1933,54 @@ struct dma_map_ops iommu_coherent_ops = { | |||
1886 | * arm_iommu_attach_device function. | 1933 | * arm_iommu_attach_device function. |
1887 | */ | 1934 | */ |
1888 | struct dma_iommu_mapping * | 1935 | struct dma_iommu_mapping * |
1889 | arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size, | 1936 | arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size) |
1890 | int order) | ||
1891 | { | 1937 | { |
1892 | unsigned int count = size >> (PAGE_SHIFT + order); | 1938 | unsigned int bits = size >> PAGE_SHIFT; |
1893 | unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long); | 1939 | unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long); |
1894 | struct dma_iommu_mapping *mapping; | 1940 | struct dma_iommu_mapping *mapping; |
1941 | int extensions = 1; | ||
1895 | int err = -ENOMEM; | 1942 | int err = -ENOMEM; |
1896 | 1943 | ||
1897 | if (!count) | 1944 | if (!bitmap_size) |
1898 | return ERR_PTR(-EINVAL); | 1945 | return ERR_PTR(-EINVAL); |
1899 | 1946 | ||
1947 | if (bitmap_size > PAGE_SIZE) { | ||
1948 | extensions = bitmap_size / PAGE_SIZE; | ||
1949 | bitmap_size = PAGE_SIZE; | ||
1950 | } | ||
1951 | |||
1900 | mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL); | 1952 | mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL); |
1901 | if (!mapping) | 1953 | if (!mapping) |
1902 | goto err; | 1954 | goto err; |
1903 | 1955 | ||
1904 | mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | 1956 | mapping->bitmap_size = bitmap_size; |
1905 | if (!mapping->bitmap) | 1957 | mapping->bitmaps = kzalloc(extensions * sizeof(unsigned long *), |
1958 | GFP_KERNEL); | ||
1959 | if (!mapping->bitmaps) | ||
1906 | goto err2; | 1960 | goto err2; |
1907 | 1961 | ||
1962 | mapping->bitmaps[0] = kzalloc(bitmap_size, GFP_KERNEL); | ||
1963 | if (!mapping->bitmaps[0]) | ||
1964 | goto err3; | ||
1965 | |||
1966 | mapping->nr_bitmaps = 1; | ||
1967 | mapping->extensions = extensions; | ||
1908 | mapping->base = base; | 1968 | mapping->base = base; |
1969 | mapping->size = bitmap_size << PAGE_SHIFT; | ||
1909 | mapping->bits = BITS_PER_BYTE * bitmap_size; | 1970 | mapping->bits = BITS_PER_BYTE * bitmap_size; |
1910 | mapping->order = order; | 1971 | |
1911 | spin_lock_init(&mapping->lock); | 1972 | spin_lock_init(&mapping->lock); |
1912 | 1973 | ||
1913 | mapping->domain = iommu_domain_alloc(bus); | 1974 | mapping->domain = iommu_domain_alloc(bus); |
1914 | if (!mapping->domain) | 1975 | if (!mapping->domain) |
1915 | goto err3; | 1976 | goto err4; |
1916 | 1977 | ||
1917 | kref_init(&mapping->kref); | 1978 | kref_init(&mapping->kref); |
1918 | return mapping; | 1979 | return mapping; |
1980 | err4: | ||
1981 | kfree(mapping->bitmaps[0]); | ||
1919 | err3: | 1982 | err3: |
1920 | kfree(mapping->bitmap); | 1983 | kfree(mapping->bitmaps); |
1921 | err2: | 1984 | err2: |
1922 | kfree(mapping); | 1985 | kfree(mapping); |
1923 | err: | 1986 | err: |
@@ -1927,14 +1990,35 @@ EXPORT_SYMBOL_GPL(arm_iommu_create_mapping); | |||
1927 | 1990 | ||
1928 | static void release_iommu_mapping(struct kref *kref) | 1991 | static void release_iommu_mapping(struct kref *kref) |
1929 | { | 1992 | { |
1993 | int i; | ||
1930 | struct dma_iommu_mapping *mapping = | 1994 | struct dma_iommu_mapping *mapping = |
1931 | container_of(kref, struct dma_iommu_mapping, kref); | 1995 | container_of(kref, struct dma_iommu_mapping, kref); |
1932 | 1996 | ||
1933 | iommu_domain_free(mapping->domain); | 1997 | iommu_domain_free(mapping->domain); |
1934 | kfree(mapping->bitmap); | 1998 | for (i = 0; i < mapping->nr_bitmaps; i++) |
1999 | kfree(mapping->bitmaps[i]); | ||
2000 | kfree(mapping->bitmaps); | ||
1935 | kfree(mapping); | 2001 | kfree(mapping); |
1936 | } | 2002 | } |
1937 | 2003 | ||
2004 | static int extend_iommu_mapping(struct dma_iommu_mapping *mapping) | ||
2005 | { | ||
2006 | int next_bitmap; | ||
2007 | |||
2008 | if (mapping->nr_bitmaps > mapping->extensions) | ||
2009 | return -EINVAL; | ||
2010 | |||
2011 | next_bitmap = mapping->nr_bitmaps; | ||
2012 | mapping->bitmaps[next_bitmap] = kzalloc(mapping->bitmap_size, | ||
2013 | GFP_ATOMIC); | ||
2014 | if (!mapping->bitmaps[next_bitmap]) | ||
2015 | return -ENOMEM; | ||
2016 | |||
2017 | mapping->nr_bitmaps++; | ||
2018 | |||
2019 | return 0; | ||
2020 | } | ||
2021 | |||
1938 | void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping) | 2022 | void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping) |
1939 | { | 2023 | { |
1940 | if (mapping) | 2024 | if (mapping) |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 0eaf5a27e120..a8f9dba2a816 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
@@ -237,7 +237,6 @@ struct drm_exynos_file_private { | |||
237 | * otherwise default one. | 237 | * otherwise default one. |
238 | * @da_space_size: size of device address space. | 238 | * @da_space_size: size of device address space. |
239 | * if 0 then default value is used for it. | 239 | * if 0 then default value is used for it. |
240 | * @da_space_order: order to device address space. | ||
241 | */ | 240 | */ |
242 | struct exynos_drm_private { | 241 | struct exynos_drm_private { |
243 | struct drm_fb_helper *fb_helper; | 242 | struct drm_fb_helper *fb_helper; |
@@ -255,7 +254,6 @@ struct exynos_drm_private { | |||
255 | 254 | ||
256 | unsigned long da_start; | 255 | unsigned long da_start; |
257 | unsigned long da_space_size; | 256 | unsigned long da_space_size; |
258 | unsigned long da_space_order; | ||
259 | }; | 257 | }; |
260 | 258 | ||
261 | /* | 259 | /* |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index fb8db0378274..b32b291f88ff 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c | |||
@@ -36,12 +36,10 @@ int drm_create_iommu_mapping(struct drm_device *drm_dev) | |||
36 | priv->da_start = EXYNOS_DEV_ADDR_START; | 36 | priv->da_start = EXYNOS_DEV_ADDR_START; |
37 | if (!priv->da_space_size) | 37 | if (!priv->da_space_size) |
38 | priv->da_space_size = EXYNOS_DEV_ADDR_SIZE; | 38 | priv->da_space_size = EXYNOS_DEV_ADDR_SIZE; |
39 | if (!priv->da_space_order) | ||
40 | priv->da_space_order = EXYNOS_DEV_ADDR_ORDER; | ||
41 | 39 | ||
42 | mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start, | 40 | mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start, |
43 | priv->da_space_size, | 41 | priv->da_space_size); |
44 | priv->da_space_order); | 42 | |
45 | if (IS_ERR(mapping)) | 43 | if (IS_ERR(mapping)) |
46 | return PTR_ERR(mapping); | 44 | return PTR_ERR(mapping); |
47 | 45 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h index 598e60f57d4b..72376d41c512 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h | |||
@@ -14,7 +14,6 @@ | |||
14 | 14 | ||
15 | #define EXYNOS_DEV_ADDR_START 0x20000000 | 15 | #define EXYNOS_DEV_ADDR_START 0x20000000 |
16 | #define EXYNOS_DEV_ADDR_SIZE 0x40000000 | 16 | #define EXYNOS_DEV_ADDR_SIZE 0x40000000 |
17 | #define EXYNOS_DEV_ADDR_ORDER 0x0 | ||
18 | 17 | ||
19 | #ifdef CONFIG_DRM_EXYNOS_IOMMU | 18 | #ifdef CONFIG_DRM_EXYNOS_IOMMU |
20 | 19 | ||
diff --git a/drivers/iommu/shmobile-iommu.c b/drivers/iommu/shmobile-iommu.c index 7a3b928fad1c..464acda0bbc4 100644 --- a/drivers/iommu/shmobile-iommu.c +++ b/drivers/iommu/shmobile-iommu.c | |||
@@ -343,7 +343,7 @@ static int shmobile_iommu_add_device(struct device *dev) | |||
343 | mapping = archdata->iommu_mapping; | 343 | mapping = archdata->iommu_mapping; |
344 | if (!mapping) { | 344 | if (!mapping) { |
345 | mapping = arm_iommu_create_mapping(&platform_bus_type, 0, | 345 | mapping = arm_iommu_create_mapping(&platform_bus_type, 0, |
346 | L1_LEN << 20, 0); | 346 | L1_LEN << 20); |
347 | if (IS_ERR(mapping)) | 347 | if (IS_ERR(mapping)) |
348 | return PTR_ERR(mapping); | 348 | return PTR_ERR(mapping); |
349 | archdata->iommu_mapping = mapping; | 349 | archdata->iommu_mapping = mapping; |