longkgsl_ioctl_gpumem_alloc(structkgsl_device_private*dev_priv,unsignedint cmd,void*data){
structkgsl_device*device = dev_priv->device;// ioctl命令参数structkgsl_gpumem_alloc*param = data;// kgsl_mem_entry用于描述用户空间的内存分配[见2.1节]structkgsl_mem_entry*entry;uint64_t flags = param->flags;/*
* On 64 bit kernel, secure memory region is expanded and
* moved to 64 bit address, 32 bit apps can not access it from
* this IOCTL.
*/if((param->flags & KGSL_MEMFLAGS_SECURE)&&is_compat_task()&&test_bit(KGSL_MMU_64BIT,&device->mmu.features))return-EOPNOTSUPP;/* Legacy functions doesn't support these advanced features */
flags &=~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);if(is_compat_task())
flags |= KGSL_MEMFLAGS_FORCE_32BIT;// 创建kgsl_mem_entry[见2.2节]
entry =gpumem_alloc_entry(dev_priv,(uint64_t) param->size, flags);if(IS_ERR(entry))returnPTR_ERR(entry);// 更新参数
param->gpuaddr =(unsignedlong) entry->memdesc.gpuaddr;
param->size =(size_t) entry->memdesc.size;
param->flags =(unsignedint) entry->memdesc.flags;/* Put the extra ref from kgsl_mem_entry_create() */// 减少引用计数, 如果引用计数减为0则通过kgsl_mem_entry_destroy释放kgsl_mem_entrykgsl_mem_entry_put(entry);return0;}
2.1 kgsl_mem_entry
/*
* struct kgsl_mem_entry - a userspace memory allocation
*/structkgsl_mem_entry{
// Currently userspace can only hold a single reference count but the kernel may hold morestructkref refcount;// description of the memory[见2.1.1节]structkgsl_memdesc memdesc;// type-specific data, such as the dma-buf attachment pointervoid*priv_data;// rb_node for the gpu address lookup rb treestructrb_node node;// idr index for this entry, can be used to find memory that does not have a valid GPU addressunsignedint id;// 持有该内存的进程structkgsl_process_private*priv;// if !0, userspace requested that his memory be freed, but there are still references to itint pending_free;// String containing user specified metadata for the entrychar metadata[KGSL_GPUOBJ_ALLOC_METADATA_MAX +1];// used to schedule a kgsl_mem_entry_put in atomic contextsstructwork_struct work;/**
* @map_count: Count how many vmas this object is mapped in - used for
* debugfs accounting
*/// 映射的VMA数量atomic_t map_count;};
2.1.1 kgsl_memdesc
/**
* struct kgsl_memdesc - GPU memory object descriptor
*/structkgsl_memdesc{
// Pointer to the pagetable that the object is mapped instructkgsl_pagetable*pagetable;// Kernel virtual addressvoid*hostptr;// Number of threads using hostptrunsignedint hostptr_count;// GPU virtual addressuint64_t gpuaddr;// Physical address of the memory objectphys_addr_t physaddr;// Size of the memory objectuint64_t size;// Internal flags and settingsunsignedint priv;structsg_table*sgt;// Function hooks for the memdesc memory type[见2.1.2节]conststructkgsl_memdesc_ops*ops;// Flags set from userspaceuint64_t flags;structdevice*dev;// dma attributes for this memoryunsignedlong attrs;// An array of pointers to allocated pagesstructpage**pages;// Total number of pages allocatedunsignedint page_count;/*
* @lock: Spinlock to protect the gpuaddr from being accessed by
* multiple entities trying to map the same SVM region at once
*/spinlock_t lock;/** @shmem_filp: Pointer to the shmem file backing this memdesc */// 共享内存的文件structfile*shmem_filp;/** @ranges: rbtree base for the interval list of vbo ranges */structrb_root_cached ranges;/** @ranges_lock: Mutex to protect the range database */structmutex ranges_lock;/** @gmuaddr: GMU VA if this is mapped in GMU */
u32 gmuaddr;};
2.1.2 kgsl_memdesc_ops
structkgsl_memdesc_ops{
unsignedint vmflags;vm_fault_t(*vmfault)(structkgsl_memdesc*memdesc,structvm_area_struct*vma,structvm_fault*vmf);void(*free)(structkgsl_memdesc*memdesc);int(*map_kernel)(structkgsl_memdesc*memdesc);void(*unmap_kernel)(structkgsl_memdesc*memdesc);/**
* @put_gpuaddr: Put away the GPU address and unmap the memory
* descriptor
*/void(*put_gpuaddr)(structkgsl_memdesc*memdesc);};
2.2 gpumem_alloc_entry
structkgsl_mem_entry*gpumem_alloc_entry(structkgsl_device_private*dev_priv,uint64_t size,uint64_t flags){
int ret;structkgsl_process_private*private = dev_priv->process_priv;structkgsl_mem_entry*entry;structkgsl_device*device = dev_priv->device;
u32 cachemode;/* For 32-bit kernel world nothing to do with this flag */if(BITS_PER_LONG ==32)
flags &=~((uint64_t) KGSL_MEMFLAGS_FORCE_32BIT);if(flags & KGSL_MEMFLAGS_VBO)returngpumem_alloc_vbo_entry(dev_priv, size