Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dma-buf: Add struct dma-buf-map for storing struct dma_buf.vaddr_ptr

The new type struct dma_buf_map represents a mapping of dma-buf memory
into kernel space. It contains a flag, is_iomem, that signals users to
access the mapped memory with I/O operations instead of regular loads
and stores.

It was assumed that DMA buffer memory can be accessed with regular load
and store operations. Some architectures, such as sparc64, require the
use of I/O operations to access dma-map buffers that are located in I/O
memory. Providing struct dma_buf_map allows drivers to implement this.
This was specifically a problem when refreshing the graphics framebuffer
on such systems. [1]

As the first step, struct dma_buf stores an instance of struct dma_buf_map
internally. Afterwards, dma-buf's vmap and vunmap interfaces are be
converted. Finally, affected drivers can be fixed.

v3:
* moved documentation into separate patch
* test for NULL pointers with !<ptr>

[1] https://lore.kernel.org/dri-devel/20200725191012.GA434957@ravnborg.org/

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Acked-by: Sumit Semwal <sumit.semwal@linaro.org>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20200925115601.23955-2-tzimmermann@suse.de

+91 -8
+7 -7
drivers/dma-buf/dma-buf.c
··· 1207 1207 mutex_lock(&dmabuf->lock); 1208 1208 if (dmabuf->vmapping_counter) { 1209 1209 dmabuf->vmapping_counter++; 1210 - BUG_ON(!dmabuf->vmap_ptr); 1211 - ptr = dmabuf->vmap_ptr; 1210 + BUG_ON(dma_buf_map_is_null(&dmabuf->vmap_ptr)); 1211 + ptr = dmabuf->vmap_ptr.vaddr; 1212 1212 goto out_unlock; 1213 1213 } 1214 1214 1215 - BUG_ON(dmabuf->vmap_ptr); 1215 + BUG_ON(dma_buf_map_is_set(&dmabuf->vmap_ptr)); 1216 1216 1217 1217 ptr = dmabuf->ops->vmap(dmabuf); 1218 1218 if (WARN_ON_ONCE(IS_ERR(ptr))) ··· 1220 1220 if (!ptr) 1221 1221 goto out_unlock; 1222 1222 1223 - dmabuf->vmap_ptr = ptr; 1223 + dmabuf->vmap_ptr.vaddr = ptr; 1224 1224 dmabuf->vmapping_counter = 1; 1225 1225 1226 1226 out_unlock: ··· 1239 1239 if (WARN_ON(!dmabuf)) 1240 1240 return; 1241 1241 1242 - BUG_ON(!dmabuf->vmap_ptr); 1242 + BUG_ON(dma_buf_map_is_null(&dmabuf->vmap_ptr)); 1243 1243 BUG_ON(dmabuf->vmapping_counter == 0); 1244 - BUG_ON(dmabuf->vmap_ptr != vaddr); 1244 + BUG_ON(!dma_buf_map_is_vaddr(&dmabuf->vmap_ptr, vaddr)); 1245 1245 1246 1246 mutex_lock(&dmabuf->lock); 1247 1247 if (--dmabuf->vmapping_counter == 0) { 1248 1248 if (dmabuf->ops->vunmap) 1249 1249 dmabuf->ops->vunmap(dmabuf, vaddr); 1250 - dmabuf->vmap_ptr = NULL; 1250 + dma_buf_map_clear(&dmabuf->vmap_ptr); 1251 1251 } 1252 1252 mutex_unlock(&dmabuf->lock); 1253 1253 }
+82
include/linux/dma-buf-map.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Pointer to dma-buf-mapped memory, plus helpers. 4 + */ 5 + 6 + #ifndef __DMA_BUF_MAP_H__ 7 + #define __DMA_BUF_MAP_H__ 8 + 9 + #include <linux/io.h> 10 + 11 + /** 12 + * struct dma_buf_map - Pointer to vmap'ed dma-buf memory. 13 + * @vaddr_iomem: The buffer's address if in I/O memory 14 + * @vaddr: The buffer's address if in system memory 15 + * @is_iomem: True if the dma-buf memory is located in I/O 16 + * memory, or false otherwise. 17 + */ 18 + struct dma_buf_map { 19 + union { 20 + void __iomem *vaddr_iomem; 21 + void *vaddr; 22 + }; 23 + bool is_iomem; 24 + }; 25 + 26 + /* API transition helper */ 27 + static inline bool dma_buf_map_is_vaddr(const struct dma_buf_map *map, const void *vaddr) 28 + { 29 + return !map->is_iomem && (map->vaddr == vaddr); 30 + } 31 + 32 + /** 33 + * dma_buf_map_is_null - Tests for a dma-buf mapping to be NULL 34 + * @map: The dma-buf mapping structure 35 + * 36 + * Depending on the state of struct dma_buf_map.is_iomem, tests if the 37 + * mapping is NULL. 38 + * 39 + * Returns: 40 + * True if the mapping is NULL, or false otherwise. 41 + */ 42 + static inline bool dma_buf_map_is_null(const struct dma_buf_map *map) 43 + { 44 + if (map->is_iomem) 45 + return !map->vaddr_iomem; 46 + return !map->vaddr; 47 + } 48 + 49 + /** 50 + * dma_buf_map_is_set - Tests is the dma-buf mapping has been set 51 + * @map: The dma-buf mapping structure 52 + * 53 + * Depending on the state of struct dma_buf_map.is_iomem, tests if the 54 + * mapping has been set. 55 + * 56 + * Returns: 57 + * True if the mapping is been set, or false otherwise. 58 + */ 59 + static inline bool dma_buf_map_is_set(const struct dma_buf_map *map) 60 + { 61 + return !dma_buf_map_is_null(map); 62 + } 63 + 64 + /** 65 + * dma_buf_map_clear - Clears a dma-buf mapping structure 66 + * @map: The dma-buf mapping structure 67 + * 68 + * Clears all fields to zero; including struct dma_buf_map.is_iomem. So 69 + * mapping structures that were set to point to I/O memory are reset for 70 + * system memory. Pointers are cleared to NULL. This is the default. 71 + */ 72 + static inline void dma_buf_map_clear(struct dma_buf_map *map) 73 + { 74 + if (map->is_iomem) { 75 + map->vaddr_iomem = NULL; 76 + map->is_iomem = false; 77 + } else { 78 + map->vaddr = NULL; 79 + } 80 + } 81 + 82 + #endif /* __DMA_BUF_MAP_H__ */
+2 -1
include/linux/dma-buf.h
··· 13 13 #ifndef __DMA_BUF_H__ 14 14 #define __DMA_BUF_H__ 15 15 16 + #include <linux/dma-buf-map.h> 16 17 #include <linux/file.h> 17 18 #include <linux/err.h> 18 19 #include <linux/scatterlist.h> ··· 310 309 const struct dma_buf_ops *ops; 311 310 struct mutex lock; 312 311 unsigned vmapping_counter; 313 - void *vmap_ptr; 312 + struct dma_buf_map vmap_ptr; 314 313 const char *exp_name; 315 314 const char *name; 316 315 spinlock_t name_lock;