mirror of https://gitee.com/openkylin/linux.git
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: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Tested-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20201103093015.1063-9-tzimmermann@suse.de
This commit is contained in:
parent
a745fb1c26
commit
a859555689
|
@ -235,7 +235,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
|
|||
{
|
||||
struct drm_device *dev = buffer->client->dev;
|
||||
|
||||
drm_gem_vunmap(buffer->gem, buffer->vaddr);
|
||||
drm_gem_vunmap(buffer->gem, &buffer->map);
|
||||
|
||||
if (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
|
|||
/**
|
||||
* drm_client_buffer_vmap - Map DRM client buffer into address space
|
||||
* @buffer: DRM client buffer
|
||||
* @map_copy: Returns the mapped memory's address
|
||||
*
|
||||
* 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
|
||||
* drm_client_buffer_vmap() should be followed by a call to
|
||||
* drm_client_buffer_vunmap(); or the client buffer should be mapped
|
||||
* 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:
|
||||
* 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;
|
||||
|
||||
if (buffer->vaddr)
|
||||
return buffer->vaddr;
|
||||
if (dma_buf_map_is_set(map))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* 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)
|
|||
* fd_install step out of the driver backend hooks, to make that
|
||||
* final step optional for internal users.
|
||||
*/
|
||||
ret = drm_gem_vmap(buffer->gem, &map);
|
||||
ret = drm_gem_vmap(buffer->gem, map);
|
||||
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);
|
||||
|
||||
|
@ -339,10 +346,9 @@ EXPORT_SYMBOL(drm_client_buffer_vmap);
|
|||
*/
|
||||
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);
|
||||
buffer->vaddr = NULL;
|
||||
drm_gem_vunmap(buffer->gem, map);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_buffer_vunmap);
|
||||
|
||||
|
|
|
@ -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];
|
||||
size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp;
|
||||
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;
|
||||
unsigned int y;
|
||||
|
||||
|
@ -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_copy;
|
||||
unsigned long flags;
|
||||
void *vaddr;
|
||||
struct dma_buf_map map;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&helper->dirty_lock, flags);
|
||||
clip_copy = *clip;
|
||||
|
@ -413,8 +414,8 @@ static void drm_fb_helper_dirty_work(struct work_struct *work)
|
|||
|
||||
/* Generic fbdev uses a shadow buffer */
|
||||
if (helper->buffer) {
|
||||
vaddr = drm_client_buffer_vmap(helper->buffer);
|
||||
if (IS_ERR(vaddr))
|
||||
ret = drm_client_buffer_vmap(helper->buffer, &map);
|
||||
if (ret)
|
||||
return;
|
||||
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,
|
|||
struct drm_framebuffer *fb;
|
||||
struct fb_info *fbi;
|
||||
u32 format;
|
||||
void *vaddr;
|
||||
struct dma_buf_map map;
|
||||
int ret;
|
||||
|
||||
drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
|
||||
sizes->surface_width, sizes->surface_height,
|
||||
|
@ -2096,14 +2098,22 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
|
|||
fb_deferred_io_init(fbi);
|
||||
} else {
|
||||
/* buffer is mapped for HW framebuffer */
|
||||
vaddr = drm_client_buffer_vmap(fb_helper->buffer);
|
||||
if (IS_ERR(vaddr))
|
||||
return PTR_ERR(vaddr);
|
||||
ret = drm_client_buffer_vmap(fb_helper->buffer, &map);
|
||||
if (ret)
|
||||
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 (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 =
|
||||
page_to_phys(virt_to_page(fbi->screen_buffer));
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#ifndef _DRM_CLIENT_H_
|
||||
#define _DRM_CLIENT_H_
|
||||
|
||||
#include <linux/dma-buf-map.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -141,9 +142,9 @@ struct drm_client_buffer {
|
|||
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
|
||||
|
@ -155,7 +156,7 @@ struct drm_client_buffer *
|
|||
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);
|
||||
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);
|
||||
|
||||
int drm_client_modeset_create(struct drm_client_dev *client);
|
||||
|
|
Loading…
Reference in New Issue