On Tue, Oct 20, 2020 at 02:20:44PM +0200, Thomas Zimmermann wrote:
> 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.
> 
> Signed-off-by: Thomas Zimmermann <tzimmerm...@suse.de>
> Reviewed-by: Daniel Vetter <daniel.vet...@ffwll.ch>
> Tested-by: Sam Ravnborg <s...@ravnborg.org>
> ---
>  drivers/gpu/drm/drm_client.c    | 34 +++++++++++++++++++--------------
>  drivers/gpu/drm/drm_fb_helper.c | 23 +++++++++++++---------
>  include/drm/drm_client.h        |  7 ++++---
>  3 files changed, 38 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> index ac0082bed966..fe573acf1067 100644
> --- a/drivers/gpu/drm/drm_client.c
> +++ b/drivers/gpu/drm/drm_client.c
> @@ -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);
>  
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index c2f72bb6afb1..6212cd7cde1d 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -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,11 +2098,14 @@ 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 */
>  #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
>               if (drm_leak_fbdev_smem && fbi->fix.smem_start == 0)

Just noticed a tiny thing here: I think this needs to be patched to only
set smem_start when the map is _not_ iomem. Since virt_to_page isn't
defined on iomem at all.

I guess it'd be neat if we can set this for iomem too, but I have no idea
how to convert an iomem pointer back to a bus_addr_t ...

Cheers, Daniel

> diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
> index 7aaea665bfc2..f07f2fb02e75 100644
> --- a/include/drm/drm_client.h
> +++ b/include/drm/drm_client.h
> @@ -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);
> -- 
> 2.28.0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

Reply via email to