程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

Rockchip RK3399 - DRM gem基础知识

----------------------------------------------------------------------------------------------------------------------------

开发板 :NanoPC-T4开发板
eMMC16GB
LPDDR34GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot2023.04
linux6.3
----------------------------------------------------------------------------------------------------------------------------

GEM主要负责显示buffer的分配和释放,linux内核中使用struct drm_gem_object表示GEM对象,驱动一般需要用私有信息来扩展GEM对象,因此struct drm_gem_object都是嵌入在驱动自定义的GEM结构体内的。
gem object的创建以及初始化步骤如下:

  • 创建一个GEM对象,驱动为自定义GEM对象申请内存;
  • 通过drm_gem_object_init来初始化嵌入在其中的struct drm_gem_object
  • 通过drm_gem_handle_create创建GEM对象handle
  • 分配物理buffer
  • 通过mmap将物理buffer映射到用户空间;这样用户空间就可以直接访问了;

一、GEM数据结构

1.1 struct drm_gem_object

linux内核中使用struct drm_gem_object表示GEM对象,struct drm_gem_object定义在include/drm/drm_gem.h:

/**
 * struct drm_gem_object - GEM buffer object
 *
 * This structure defines the generic parts for GEM buffer objects, which are
 * mostly around handling mmap and userspace handles.
 *
 * Buffer objects are often abbreviated to BO.
 */
struct drm_gem_object {
        /**
         * @refcount:
         *
         * Reference count of this object
         *
         * Please use drm_gem_object_get() to acquire and drm_gem_object_put_locked()
         * or drm_gem_object_put() to release a reference to a GEM
         * buffer object.
         */
        struct kref refcount;

        /**
         * @handle_count:
         *
         * This is the GEM file_priv handle count of this object.
         *
         * Each handle also holds a reference. Note that when the handle_count
         * drops to 0 any global names (e.g. the id in the flink namespace) will
         * be cleared.
         *
         * Protected by &drm_device.object_name_lock.
         */
        unsigned handle_count;
    
        /**
         * @dev: DRM dev this object belongs to.
         */
        struct drm_device *dev;
    
        /**
         * @filp:
         *
         * SHMEM file node used as backing storage for swappable buffer objects.
         * GEM also supports driver private objects with driver-specific backing
         * storage (contiguous DMA memory, special reserved blocks). In this
         * case @filp is NULL.
         */
        struct file *filp;
        /**
         * @vma_node:
         *
         * Mapping info for this object to support mmap. Drivers are supposed to
         * allocate the mmap offset using drm_gem_create_mmap_offset(). The
         * offset itself can be retrieved using drm_vma_node_offset_addr().
         *
         * Memory mapping itself is handled by drm_gem_mmap(), which also checks
         * that userspace is allowed to access the object.
         */
        struct drm_vma_offset_node vma_node;
    
        /**
         * @size:
         *
         * Size of the object, in bytes.  Immutable over the object's
         * lifetime.
         */
        size_t size;
    
        /**
         * @name:
         *
         * Global name for this object, starts at 1. 0 means unnamed.
         * Access is covered by &drm_device.object_name_lock. This is used by
         * the GEM_FLINK and GEM_OPEN ioctls.
         */
        int name;
    
        /**
         * @dma_buf:
         *
         * dma-buf associated with this GEM object.
         *
         * Pointer to the dma-buf associated with this gem object (either
         * through importing or exporting). We break the resulting reference
         * loop when the last gem handle for this object is released.
         *
         * Protected by &drm_device.object_name_lock.
         */
        struct dma_buf *dma_buf;
    
        /**
         * @import_attach:
         *
         * dma-buf attachment backing this object.
         *
         * Any foreign dma_buf imported as a gem object has this set to the
         * attachment point for the device. This is invariant over the lifetime
         * of a gem object.
         *
         * The &drm_gem_object_funcs.free callback is responsible for
         * cleaning up the dma_buf attachment and references acquired at import
         * time.
         *
         * Note that the drm gem/prime core does not depend upon drivers setting
         * this field any more. So for drivers where this doesn't make sense
         * (e.g. virtual devices or a displaylink behind an usb bus) they can
         * simply leave it as NULL.
         */
        struct dma_buf_attachment *import_attach;
    
        /**
         * @resv:
         *
         * Pointer to reservation object associated with the this GEM object.
         *
         * Normally (@resv == &@_resv) except for imported GEM objects.
         */
        struct dma_resv *resv;
    
        /**
         * @_resv:
         *
         * A reservation object for this GEM object.
         *
         * This is unused for imported GEM objects.
         */
        struct dma_resv _resv;
    
        /**
         * @funcs:
         *
         * Optional GEM object functions. If this is set, it will be used instead of the
         * corresponding &drm_driver GEM callbacks.
         *
         * New drivers should use this.
         *
         */
        const struct drm_gem_object_funcs *funcs;
    
        /**
         * @lru_node:
         *
         * List node in a &drm_gem_lru.
         */
        struct list_head lru_node;
    
        /**
         * @lru:
         *
         * The current LRU list that the GEM object is on.
         */
        struct drm_gem_lru *lru;
};

其中:

  • refcount:表示对象引用计数,用于对GEM对象全生命周期的管理;
  • handle_count:表示该对象的句柄计数。每个句柄还持有一个引用,当handle_count降为0时,任何全局名称(例如flink命名空间中的id)都将被清除;
  • dev:该对象所属的DRM设备的指针;
  • filp:用作可互换的缓存对象的后备存储的共享内存文件节点;
  • vma_node:用于支持内存映射的对象的映射信息;
  • size:对象的大小,以字节为单位;
  • name:该对象的全局名称,从1开始。值为0表示无名称;
  • dma_buf:与此GEM对象关联的dma-buf
  • import_attach:支持此对象的dma-buf附件;
  • resv:与此GEM对象关联的保留对象的指针;
  • _resv:此GEM对象的保留对象;
  • funcs:可选的GEM对象函数。如果设置了此字段,则将使用它而不是对应的drm_driver GEM回调函数;
  • lru_node:在drm_gem_lru中的列表节点;
  • lruGEM对象当前所在的LRU列表;

1.2 struct drm_gem_object_funcs

struct drm_gem_object_funcs定义了与GEM对象相关的回调函数,用于管理和操作GEM对象;

struct drm_gem_object_funcs {
    void (*free)(struct drm_gem_object *obj);
    int (*open)(struct drm_gem_object *obj, struct drm_file *file);
    void (*close)(struct drm_gem_object *obj, struct drm_file *file);
    void (*print_info)(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *obj);
    struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
    int (*pin)(struct drm_gem_object *obj);
    void (*unpin)(struct drm_gem_object *obj);
    struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
    int (*vmap)(struct drm_gem_object *obj, struct iosys_map *map);
    void (*vunmap)(struct drm_gem_object *obj, struct iosys_map *map);
    int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
    int (*evict)(struct drm_gem_object *obj);
    enum drm_gem_object_status (*status)(struct drm_gem_object *obj);
    const struct vm_operations_struct *vm_ops;
};

其中:

  • free:用于释放GEM对象及其相关资源的操作,必须实现;
  • open:创建GEM handle时(drm_gem_handle_create),回调该函数,可选;
  • close:释放GEM handle时(drm_gem_handle_delete),回调该函数,可选;
  • get_sg_table:用于获取bufferScatter-Gather表(SG表);
  • vmap:为buffer获取一个虚拟地址,会被drm_gem_dmabuf_vmap helper使用,可选;
  • vunmap: 释放由vmap返回的虚拟地址,会被drm_gem_dmabuf_vunmap helper使用,可选;
  • mmap:用于处理对GEM对象的mmap调用,并相应地设置vmavm_area_struct)结构,可选;
    • 此回调函数被drm_gem_mmap_objdrm_gem_prime_mmap两者使用;
    • 当存在mmap时,不会使用vm_ops,而是必须由mmap回调函数设置vma->vm_ops
  • vm_ops:与mmap一起使用的虚拟内存区域操作结构体,它包含了对应于虚拟内存区域操作的函数指针;对于GEM对象或其他需要通过mmap系统调用映射到用户空间的内核对象,必须实现适当的vm_ops结构体。

二、核心API

2.1 GEM初始化

GEM使用shmem来申请匿名页内存,drm_gem_object_init将会根据传入的size创建一个指定大小的指定大小的shmfs,并将这个shmfs file保存到struct drm_gem_objectfilp字段。

当图形硬件使用系统内存,这些内存就会作为对象的主存储直接使用,否则就会作为后备内存。

驱动负责调用shmem_read_mapping_page_gfp做实际物理页面的申请,初始化GEM对象时驱动可以决定申请页面,或者延迟到需要内存时再申请(需要内存时是指:用户态访问内存发生缺页中断,或是驱动需要启动DMA用到这段内存)。

在某些情况下,匿名可分页内存分配并不理想,特别是当硬件要求物理连续的系统内存时,这在嵌入式设备中经常发生。在这种情况下,驱动程序可以通过调用drm_gem_private_object_init来初始化GEM对象,而不是使用drm_gem_object_init,从而创建没有shmfs支持的私有GEM对象。

drm_gem_object_init函数定义在drivers/gpu/drm/drm_gem.c

/**
 * drm_gem_object_init - initialize an allocated shmem-backed GEM object
 * @dev: drm_device the object should be initialized for
 * @obj: drm_gem_object to initialize
 * @size: object size 对象的大小
 *
 * Initialize an already allocated GEM object of the specified size with
 * shmfs backing store.
 */
int drm_gem_object_init(struct drm_device *dev,
                        struct drm_gem_object *obj, size_t )
{
        struct file *filp;

        drm_gem_private_object_init(dev, obj, size);
 
        filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
        if (IS_ERR(filp))
                return PTR_ERR(filp);

        obj->filp = filp;

        return 0;
}

函数通过调用 drm_gem_private_object_init 进行对象初始化;

/**
 * drm_gem_private_object_init - initialize an allocated private GEM object
 * @dev: drm_device the object should be initialized for
 * @obj: drm_gem_object to initialize
 * @size: object size
 *
 * Initialize an already allocated GEM object of the specified size with
 * no GEM provided backing store. Instead the caller is responsible for
 * backing the object and handling it.
 */
void drm_gem_private_object_init(struct drm_device *dev,
                                 struct drm_gem_object *obj, size_t size)
{
        BUG_ON((size & (PAGE_SIZE - 1)) != 0);

    	// 初始化成员
        obj->dev = dev;
        obj->filp = NULL;

    	// 初始化对象引用计数为1
        kref_init(&obj->refcount);
        obj->handle_count = 0;
        obj->size = size;
        dma_resv_init(&obj->_resv);
        if (!obj->resv)
                obj->resv = &obj->_resv;

        drm_vma_node_reset(&obj->vma_node);
        INIT_LIST_HEAD(&obj->lru_node);
}

然后通过调用 shmem_file_setup 创建一个与该 GEM对象关联的shmem文件,并将文件指针赋值给 obj->filp

2.2 GEM对象命名

用户空间与内核之间的通信使用本地句柄(handle)、全局名称或者文件描述符来引用GEM对象,所有这些都是32bit数。

2.2.1 GEM handle

GEM handle只在特定的DRM文件中有效,应用程序通过驱动程序特定的ioctl获取GEM对象的handle,并可以在其他标准或驱动程序特定的ioctl中使用该handle引用GEM对象,关闭一个DRM文件句柄会释放其中所有的GEM,并解引用相关的GEM对象。

对于GEM handle,函数drm_gem_handle_create用于创建GEM对象的handle,这个函数接收三个参数:

  • file_privDRM file的私有数据;
  • objGEM对象;
  • handlep:将创建的handle返回给调用者的指针handlep

drm_gem_handle_create函数定义在drivers/gpu/drm/drm_gem.c

/**
 * drm_gem_handle_create_tail - internal functions to create a handle
 * @file_priv: drm file-private structure to register the handle for
 * @obj: object to register
 * @handlep: pointer to return the created handle to the caller
 *
 * This expects the &drm_device.object_name_lock to be held already and will
 * drop it before returning. Used to avoid races in establishing new handles
 * when importing an object from either an flink name or a dma-buf.
 *
 * Handles must be release again through drm_gem_handle_delete(). This is done
 * when userspace closes @file_priv for all attached handles, or through the
 * GEM_CLOSE ioctl for individual handles.
 */
int
drm_gem_handle_create_tail(struct drm_file *file_priv,
                           struct drm_gem_object *obj,
                           u32 *handlep)
{
        struct drm_device *dev = obj->dev;
        u32 handle;
        int ret;

        WARN_ON(!mutex_is_locked(&dev->object_name_lock));
        if (obj->handle_count++ == 0)
                drm_gem_object_get(obj);

        /*
         * Get the user-visible handle using idr.  Preload and perform
         * allocation under our spinlock.
         */
        idr_preload(GFP_KERNEL);
		// 获取自旋锁
        spin_lock(&file_priv->table_lock);   

		// 基于基数树分配一个唯一的id
        ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT); 

		// 释放自旋锁
        spin_unlock(&file_priv->table_lock);   
        idr_preload_end();

        mutex_unlock(&dev->object_name_lock);
        if (ret < 0)
                goto err_unref;

        handle = ret;

        ret = drm_vma_node_allow(&obj->vma_node, file_priv);
        if (ret)
                goto err_remove;

        if (obj->funcs->open) {
				// 回调open函数
                ret = obj->funcs->open(obj, file_priv);
                if (ret)
                        goto err_revoke;
        }

        *handlep = handle; // 写回
        return 0;

err_revoke:
        drm_vma_node_revoke(&obj->vma_node, file_priv);
err_remove:
        spin_lock(&file_priv->table_lock);
        idr_remove(&file_priv->object_idr, handle);
        spin_unlock(&file_priv->table_lock);
err_unref:
        drm_gem_object_handle_put_unlocked(obj);
        return ret;
}

/**
 * drm_gem_handle_create - create a gem handle for an object
 * @file_priv: drm file-private structure to register the handle for
 * @obj: object to register
 * @handlep: pointer to return the created handle to the caller
 *
 * Create a handle for this object. This adds a handle reference to the object,
 * which includes a regular reference count. Callers will likely want to
 * dereference the object afterwards.
 *
 * Since this publishes @obj to userspace it must be fully set up by this point,
 * drivers must call this last in their buffer object creation callbacks.
 */
int drm_gem_handle_create(struct drm_file *file_priv,
                          struct drm_gem_object *obj,
                          u32 *handlep)
{
        mutex_lock(&obj->dev->object_name_lock);

        return drm_gem_handle_create_tail(file_priv, obj, handlep);
}

可以由drm_gem_object_lookup检索与handle关联的GEM对象。

handle不再需要时,驱动程序使用drm_gem_handle_delete进行删除。释放句柄并不直接销毁或释放GEM对象本身,它只是解除了句柄与GEM对象之间的关联。

为了避免泄漏GEM对象,驱动程序必须确保适当地丢弃自己所拥有的引用(比如在对象创建时获取的初始引用),而不需要特别考虑handle。例如,在实现dumb_create操作时,驱动程序必须在返回handle之前丢弃对GEM对象的初始引用。

2.2.2 GEM名称

GEM名称类似于句柄,但不仅限于DRM文件。它们可以在进程之间传递,用于全局引用GEM对象。应用程序需要通过ioctl的DRM_IOCTL_GEM_FLINKDRM_IOCTL_GEM_OPEN来将句柄转换为名称,以及将名称转换为句柄。这个转换由DRM core处理,不需要任何驱动程序特定的支持。

2.2.3 文件描述符

GEM也支持通过PRIME dma-buf文件描述符的缓存共享,基于GEM的驱动必须使用提供的辅助函数来实现exoprtingimporting。共享文件描述符比可以被猜测的全局名称更安全,因此是首选的缓存共享机制。通过GEM全局名称进行缓存共享仅在传统用户态支持,更进一步的说,PRIME由于其基于dma-buf,还允许跨设备缓存共享。

2.3 GEM对象的生命周期

所有的GEM对象都由GEM Core进行引用计数管理,在DRM子系统中,可以通过调用函数drm_gem_object_getdrm_gem_object_put来获取和释放对GEM对象的引用。

执行drm_gem_object_get调用者必须持有struct drm_devicestruct_mutex锁,而为了方便也提供了drm_gem_object_put_unlocked也可以不持锁操作。

当最后一个对GEM对象的引用释放时,GEM core调用struct drm_gem_object_funcs中的free操作,这一操作对于使能了GEM的驱动来说是必须,并且必须释放GEM对象和所有相关资源。

struct drm_gem_object_funcs中,void (*free)(struct drm_gem_object *obj)函数指针是用于释放GEM对象及其相关资源的操作。驱动程序需要实现这个函数,并在适当的时候调用drm_gem_object_release释放与GEM对象相关的资源。

2.4 GEM对象内存映射

linux kernel驱动中,实现mmap系统调用离不开两个关键步骤:

  • 物理内存的分配;
  • 建立物理内存到用户空间的映射关系。

这刚好对应了DRM中的dumb_createmmap操作,先说映射关系,在linux驱动中建立映射关系的方法主要有如下两种:

  • 一次性映射:在mmap回调函数中,一次性建立好整块内存的映射关系,通常以remap_pfn_range为代表;
  • Page Fault:在mmap先不建立映射关系,等上层触发缺页异常时,在fault中断处理函数中建立映射关系,缺哪块补哪块,通常以vm_insert_page为代表。

想再进一步学习mmap系统调用的相关知识,推荐大家阅读DRM 驱动mmap详解:(一)预备知识》《认真分析mmap:是什么 为什么 怎么用》

DRM中,GEM更倾向于通过特定于驱动程序的ioctl实现类似读/写的访问buffer,而不是将buffer映射到用户空间。然而,当需要对buffer进行随机访问时(例如执行软件渲染),直接访问对象可能更有效率。

不能直接使用mmap系统调用来映射GEM对象,因为它们没有自己的文件句柄。目前有两种共存的方法将GEM对象映射到用户空间:

(1) 第一种方法使用特定于驱动程序的ioctl来执行映射操作,底层调用do_mmap,这种方法经常被认为不可靠,在新的GEM驱动程序中似乎不被鼓励使用,因此这里不会描述它;

(2) 使用mmap系统调用对DRM文件句柄进行映射;

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)

DRM通过传递一个虚拟偏移量来标识要映射的GEM对象,该偏移量通过mmapoffset参数传递。在映射之前,GEM对象必须与虚拟偏移量关联起来。为此,驱动程序必须在对象上调用drm_gem_create_mmap_offset

分配了虚拟偏移量值后,驱动程序必须以特定于驱动程序的方式将该值传递给应用程序,然后可以将其用作mmapoffset参数。

GEM核心提供了一个辅助方法drm_gem_mmap来处理对象映射。该方法可以直接设置为mmap文件操作处理程序,它将根据偏移值查找GEM对象,并将VMA操作设置为struct drm_driver gem_vm_ops字段。

请注意:drm_gem_mmap不会将内存映射到用户空间,而是依赖于驱动程序提供的fault handler来逐个映射页面。

三、Rockchip gem驱动

这里我们介绍一下Rochchip DRM驱动中与gem object相关的实现,具体实现文件:

  • drivers/gpu/drm/rockchip/rockchip_drm_fb.c
  • drivers/gpu/drm/rockchip/rockchip_drm_gem.c
  • drivers/gpu/drm/rockchip/rockchip_drm_gem.h
  • drivers/gpu/drm/rockchip/rockchip_drm_fb.h

3.1 gem object创建及初始化

gem object的创建以及初始化是由rockchip_gem_dumb_create函数完成的,其定义在rockchip_drm_driver中;

static const struct drm_driver rockchip_drm_driver = {
        .driver_features        = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
        .dumb_create            = rockchip_gem_dumb_create,
		......
};

其中dumb_create配置为rockchip_gem_dumb_create,该函数用于分配物理内存dumb buffer,函数定义在drivers/gpu/drm/rockchip/rockchip_drm_gem.c

/*
 * rockchip_gem_dumb_create - (struct drm_driver)->dumb_create callback
 * function
 *
 * This aligns the pitch and size arguments to the minimum required. wrap
 * this into your own function if you need bigger alignment.
 */
int rockchip_gem_dumb_create(struct drm_file *file_priv,
                             struct drm_device *dev,
                             struct drm_mode_create_dumb *args)
{
        struct rockchip_gem_object *rk_obj;
		
		// 宽度*每像素位数/8
        int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);  

        /*
         * align to 64 bytes since Mali requires it.
         */
        args->pitch = ALIGN(min_pitch, 64);
		
		// 宽*高*每像素位数/8,即得到总大小(单位字节)
        args->size = args->pitch * args->height;  

        rk_obj = rockchip_gem_create_with_handle(file_priv, dev, args->size,
                                                 &args->handle);

        return PTR_ERR_OR_ZERO(rk_obj);
}

这里主要实现函数是rockchip_gem_create_with_handle,定义如下;

/*
 * rockchip_gem_create_with_handle - allocate an object with the given
 * size and create a gem handle on it
 *
 * returns a struct rockchip_gem_object* on success or ERR_PTR values
 * on failure.
 */
static struct rockchip_gem_object *
rockchip_gem_create_with_handle(struct drm_file *file_priv,
                                struct drm_device *drm, unsigned int size,
                                unsigned int *handle)
{
        struct rockchip_gem_object *rk_obj;
        struct drm_gem_object *obj;
        bool is_framebuffer;
        int ret;

        is_framebuffer = drm->fb_helper && file_priv == drm->fb_helper->client.file;

        rk_obj = rockchip_gem_create_object(drm, size, is_framebuffer);
        if (IS_ERR(rk_obj))
                return ERR_CAST(rk_obj);

		// 获取GEM对象
        obj = &rk_obj->base; 

        /*
         * allocate a id of idr table where the obj is registered
         * and handle has the id what user can see.
         */
        ret = drm_gem_handle_create(file_priv, obj, handle); 
        if (ret)
                goto err_handle_create;

        /* drop reference from allocate - handle holds it now. */
        drm_gem_object_put(obj);

        return rk_obj;

err_handle_create:
        rockchip_gem_free_object(obj);

        return ERR_PTR(ret);
}

函数执行流程如下:

  • 调用rockchip_gem_create_object创建并初始化Rockchip驱动自定义的GEM对象struct rockchip_gem_objec;数据结构rockchip_gem_objectRockchip驱动自定义的GEM对象,内部包含struct drm_gem_object,定义在drivers/gpu/drm/rockchip/rockchip_drm_gem.h
  • 调用drm_gem_handle_create创建GEM对象handle
  • 调用drm_gem_object_putGEM对象的引用计数-1;

rockchip_gem_create_with_handle函数调用栈:

rockchip_gem_create_with_handle(file_priv, dev, args->size,&args->handle)
    // #1 创建并初始化Rockchip驱动自定义的GEM对象
    rk_obj = rockchip_gem_create_object(drm, size, is_framebuffer) 
	    // #1.1 创建Rockchip驱动自定义的GEM对象 
    	rk_obj = rockchip_gem_alloc_object(drm, size)          
		    // GEM对象初始化
    		drm_gem_object_init(drm, obj, size)       
	    // #1.2 为Rockchip GEM对象分配DMA缓冲区,或者在IOMMU上分配内存
 	    rockchip_gem_alloc_buf(rk_obj, alloc_kmap)    
			rockchip_gem_alloc_dma(rk_obj, alloc_kmap)   
    			// 分配DMA缓冲区。分配的大小为obj->size字节,属性为rk_obj->dma_attrs
        		rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
                                         &rk_obj->dma_addr, GFP_KERNEL,
                                         rk_obj->dma_attrs);
    // 获取GEM对象 struct drm_gem_object
    obj = &rk_obj->base;
    // #2 创建GEM对象handle
    drm_gem_handle_create(file_priv, obj, handle)    
    // 3# 引用计数-1
    drm_gem_object_put(obj) 

rockchip_gem_alloc_dma函数执行后会创建了一块内存放在了rockchip gem object的对象里。

3.1.1 struct rockchip_gem_object

struct rockchip_gem_objectRockchip驱动扩展的gem object,定义在drivers/gpu/drm/rockchip/rockchip_drm_gem.h

struct rockchip_gem_object {
        struct drm_gem_object base;
        unsigned int flags;

        void *kvaddr;
        dma_addr_t dma_addr;
        /* Used when IOMMU is disabled */
        unsigned long dma_attrs;

        /* Used when IOMMU is enabled */
        struct drm_mm_node mm;
        unsigned long num_pages;
        struct page **pages;
        struct sg_table *sgt;
        size_t size;
};

其中:

  • base:这是内核定义的gem object结构;
  • kvaddr:这个字段是一个指向虚拟地址的指针,它可能指向这个GEM对象在用户空间中的虚拟地址;
  • dma_addr:这个字段是设备内存地址,它可能被用于直接内存访问(DMA)操作;
  • dma_attrs:这个字段可能用于存储与DMA操作相关的属性;
  • num_pages:这个字段表示这个GEM对象占用的页面数量;
  • pages:这是一个指向struct page的指针数组,它可能用于存储这个GEM对象占用的所有页面的信息;
  • size:这个字段表示这个GEM对象的大小;

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(1220)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示