Commit a8595556 authored by Thomas Zimmermann's avatar Thomas Zimmermann

drm/gem: Store client buffer mappings as struct dma_buf_map

Kernel DRM clients now store their framebuffer address in an instance
of struct dma_buf_map. Depending on the buffer's location, the address
refers to system or I/O memory.

Callers of drm_client_buffer_vmap() receive a copy of the value in
the call's supplied arguments. It can be accessed and modified with
dma_buf_map interfaces.

v6:
	* don't call page_to_phys() on framebuffers in I/O memory;
	  warn instead (Daniel)
Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: default avatarSam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20201103093015.1063-9-tzimmermann@suse.de
parent a745fb1c
...@@ -235,7 +235,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) ...@@ -235,7 +235,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
{ {
struct drm_device *dev = buffer->client->dev; struct drm_device *dev = buffer->client->dev;
drm_gem_vunmap(buffer->gem, buffer->vaddr); drm_gem_vunmap(buffer->gem, &buffer->map);
if (buffer->gem) if (buffer->gem)
drm_gem_object_put(buffer->gem); drm_gem_object_put(buffer->gem);
...@@ -291,25 +291,31 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u ...@@ -291,25 +291,31 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
/** /**
* drm_client_buffer_vmap - Map DRM client buffer into address space * drm_client_buffer_vmap - Map DRM client buffer into address space
* @buffer: DRM client buffer * @buffer: DRM client buffer
* @map_copy: Returns the mapped memory's address
* *
* This function maps a client buffer into kernel address space. If the * This function maps a client buffer into kernel address space. If the
* buffer is already mapped, it returns the mapping's address. * buffer is already mapped, it returns the existing mapping's address.
* *
* Client buffer mappings are not ref'counted. Each call to * Client buffer mappings are not ref'counted. Each call to
* drm_client_buffer_vmap() should be followed by a call to * drm_client_buffer_vmap() should be followed by a call to
* drm_client_buffer_vunmap(); or the client buffer should be mapped * drm_client_buffer_vunmap(); or the client buffer should be mapped
* throughout its lifetime. * throughout its lifetime.
* *
* The returned address is a copy of the internal value. In contrast to
* other vmap interfaces, you don't need it for the client's vunmap
* function. So you can modify it at will during blit and draw operations.
*
* Returns: * Returns:
* The mapped memory's address * 0 on success, or a negative errno code otherwise.
*/ */
void *drm_client_buffer_vmap(struct drm_client_buffer *buffer) int
drm_client_buffer_vmap(struct drm_client_buffer *buffer, struct dma_buf_map *map_copy)
{ {
struct dma_buf_map map; struct dma_buf_map *map = &buffer->map;
int ret; int ret;
if (buffer->vaddr) if (dma_buf_map_is_set(map))
return buffer->vaddr; goto out;
/* /*
* FIXME: The dependency on GEM here isn't required, we could * FIXME: The dependency on GEM here isn't required, we could
...@@ -319,13 +325,14 @@ void *drm_client_buffer_vmap(struct drm_client_buffer *buffer) ...@@ -319,13 +325,14 @@ void *drm_client_buffer_vmap(struct drm_client_buffer *buffer)
* fd_install step out of the driver backend hooks, to make that * fd_install step out of the driver backend hooks, to make that
* final step optional for internal users. * final step optional for internal users.
*/ */
ret = drm_gem_vmap(buffer->gem, &map); ret = drm_gem_vmap(buffer->gem, map);
if (ret) if (ret)
return ERR_PTR(ret); return ret;
buffer->vaddr = map.vaddr; out:
*map_copy = *map;
return map.vaddr; return 0;
} }
EXPORT_SYMBOL(drm_client_buffer_vmap); EXPORT_SYMBOL(drm_client_buffer_vmap);
...@@ -339,10 +346,9 @@ EXPORT_SYMBOL(drm_client_buffer_vmap); ...@@ -339,10 +346,9 @@ EXPORT_SYMBOL(drm_client_buffer_vmap);
*/ */
void drm_client_buffer_vunmap(struct drm_client_buffer *buffer) void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
{ {
struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(buffer->vaddr); struct dma_buf_map *map = &buffer->map;
drm_gem_vunmap(buffer->gem, &map); drm_gem_vunmap(buffer->gem, map);
buffer->vaddr = NULL;
} }
EXPORT_SYMBOL(drm_client_buffer_vunmap); EXPORT_SYMBOL(drm_client_buffer_vunmap);
......
...@@ -378,7 +378,7 @@ static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper, ...@@ -378,7 +378,7 @@ static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper,
unsigned int cpp = fb->format->cpp[0]; unsigned int cpp = fb->format->cpp[0];
size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp; size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp;
void *src = fb_helper->fbdev->screen_buffer + offset; void *src = fb_helper->fbdev->screen_buffer + offset;
void *dst = fb_helper->buffer->vaddr + offset; void *dst = fb_helper->buffer->map.vaddr + offset;
size_t len = (clip->x2 - clip->x1) * cpp; size_t len = (clip->x2 - clip->x1) * cpp;
unsigned int y; unsigned int y;
...@@ -400,7 +400,8 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) ...@@ -400,7 +400,8 @@ static void drm_fb_helper_dirty_work(struct work_struct *work)
struct drm_clip_rect *clip = &helper->dirty_clip; struct drm_clip_rect *clip = &helper->dirty_clip;
struct drm_clip_rect clip_copy; struct drm_clip_rect clip_copy;
unsigned long flags; unsigned long flags;
void *vaddr; struct dma_buf_map map;
int ret;
spin_lock_irqsave(&helper->dirty_lock, flags); spin_lock_irqsave(&helper->dirty_lock, flags);
clip_copy = *clip; clip_copy = *clip;
...@@ -413,8 +414,8 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) ...@@ -413,8 +414,8 @@ static void drm_fb_helper_dirty_work(struct work_struct *work)
/* Generic fbdev uses a shadow buffer */ /* Generic fbdev uses a shadow buffer */
if (helper->buffer) { if (helper->buffer) {
vaddr = drm_client_buffer_vmap(helper->buffer); ret = drm_client_buffer_vmap(helper->buffer, &map);
if (IS_ERR(vaddr)) if (ret)
return; return;
drm_fb_helper_dirty_blit_real(helper, &clip_copy); drm_fb_helper_dirty_blit_real(helper, &clip_copy);
} }
...@@ -2060,7 +2061,8 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, ...@@ -2060,7 +2061,8 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct fb_info *fbi; struct fb_info *fbi;
u32 format; u32 format;
void *vaddr; struct dma_buf_map map;
int ret;
drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n", drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
sizes->surface_width, sizes->surface_height, sizes->surface_width, sizes->surface_height,
...@@ -2096,14 +2098,22 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, ...@@ -2096,14 +2098,22 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
fb_deferred_io_init(fbi); fb_deferred_io_init(fbi);
} else { } else {
/* buffer is mapped for HW framebuffer */ /* buffer is mapped for HW framebuffer */
vaddr = drm_client_buffer_vmap(fb_helper->buffer); ret = drm_client_buffer_vmap(fb_helper->buffer, &map);
if (IS_ERR(vaddr)) if (ret)
return PTR_ERR(vaddr); return ret;
if (map.is_iomem)
fbi->screen_base = map.vaddr_iomem;
else
fbi->screen_buffer = map.vaddr;
fbi->screen_buffer = vaddr; /*
/* Shamelessly leak the physical address to user-space */ * Shamelessly leak the physical address to user-space. As
* page_to_phys() is undefined for I/O memory, warn in this
* case.
*/
#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM) #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
if (drm_leak_fbdev_smem && fbi->fix.smem_start == 0) if (drm_leak_fbdev_smem && fbi->fix.smem_start == 0 &&
!drm_WARN_ON_ONCE(dev, map.is_iomem))
fbi->fix.smem_start = fbi->fix.smem_start =
page_to_phys(virt_to_page(fbi->screen_buffer)); page_to_phys(virt_to_page(fbi->screen_buffer));
#endif #endif
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#ifndef _DRM_CLIENT_H_ #ifndef _DRM_CLIENT_H_
#define _DRM_CLIENT_H_ #define _DRM_CLIENT_H_
#include <linux/dma-buf-map.h>
#include <linux/lockdep.h> #include <linux/lockdep.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -141,9 +142,9 @@ struct drm_client_buffer { ...@@ -141,9 +142,9 @@ struct drm_client_buffer {
struct drm_gem_object *gem; struct drm_gem_object *gem;
/** /**
* @vaddr: Virtual address for the buffer * @map: Virtual address for the buffer
*/ */
void *vaddr; struct dma_buf_map map;
/** /**
* @fb: DRM framebuffer * @fb: DRM framebuffer
...@@ -155,7 +156,7 @@ struct drm_client_buffer * ...@@ -155,7 +156,7 @@ struct drm_client_buffer *
drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format);
void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect); int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect);
void *drm_client_buffer_vmap(struct drm_client_buffer *buffer); int drm_client_buffer_vmap(struct drm_client_buffer *buffer, struct dma_buf_map *map);
void drm_client_buffer_vunmap(struct drm_client_buffer *buffer); void drm_client_buffer_vunmap(struct drm_client_buffer *buffer);
int drm_client_modeset_create(struct drm_client_dev *client); int drm_client_modeset_create(struct drm_client_dev *client);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment