/**
* struct kgsl_driver - main container for global KGSL things
*/structkgsl_driver{// Character device structstructcdev cdev;dev_t major;structclass*class;structdevice virtdev;structkobject*ptkobj;structkobject*prockobj;// Array of pointers to the individual KGSL device structsstructkgsl_device*devp[1];// kgsl_process_private链表structlist_head process_list;// List of open pagetablesstructlist_head pagetable_list;spinlock_t ptlock;structmutex process_mutex;rwlock_t proclist_lock;structmutex devlock;// Struct containing atomic memory statisticsstruct{atomic_long_t vmalloc;atomic_long_t vmalloc_max;atomic_long_t page_alloc;atomic_long_t page_alloc_max;atomic_long_t coherent;atomic_long_t coherent_max;atomic_long_t secure;atomic_long_t secure_max;atomic_long_t mapped;atomic_long_t mapped_max;} stats;unsignedint full_cache_threshold;structworkqueue_struct*workqueue;structworkqueue_struct*mem_workqueue;structkthread_worker worker;structtask_struct*worker_thread;};
2. kgsl_driver初始化
structkgsl_driver kgsl_driver ={.process_mutex =__MUTEX_INITIALIZER(kgsl_driver.process_mutex),.proclist_lock =__RW_LOCK_UNLOCKED(kgsl_driver.proclist_lock),.ptlock =__SPIN_LOCK_UNLOCKED(kgsl_driver.ptlock),.devlock =__MUTEX_INITIALIZER(kgsl_driver.devlock),/*
* Full cache flushes are faster than line by line on at least
* 8064 and 8974 once the region to be flushed is > 16mb.
*/.full_cache_threshold = SZ_16M,.stats.vmalloc =ATOMIC_LONG_INIT(0),.stats.vmalloc_max =ATOMIC_LONG_INIT(0),.stats.page_alloc =ATOMIC_LONG_INIT(0),.stats.page_alloc_max =ATOMIC_LONG_INIT(0),.stats.coherent =ATOMIC_LONG_INIT(0),.stats.coherent_max =ATOMIC_LONG_INIT(0),.stats.secure =ATOMIC_LONG_INIT(0),.stats.secure_max =ATOMIC_LONG_INIT(0),.stats.mapped =ATOMIC_LONG_INIT(0),.stats.mapped_max =ATOMIC_LONG_INIT(0),};
staticintkgsl_open(structinode*inodep,structfile*filep){int result;structkgsl_device_private*dev_priv;structkgsl_device*device;unsignedint minor =iminor(inodep);// kgsl_driver-->kgsl_device
device =kgsl_get_minor(minor);if(device ==NULL){pr_err("kgsl: No device found\n");return-ENODEV;}
result =pm_runtime_get_sync(&device->pdev->dev);if(result <0){dev_err(device->dev,"Runtime PM: Unable to wake up the device, rc = %d\n",
result);return result;}
result =0;// 调用在adreno_functable中定义的adreno_device_private_create[见3.2节]创建kgsl_device_private
dev_priv = device->ftbl->device_private_create();if(dev_priv ==NULL){
result =-ENOMEM;goto err;}
dev_priv->device = device;
filep->private_data = dev_priv;// 打开adreno device[见3.3节]
result =kgsl_open_device(device);if(result)goto err;/*
* Get file (per process) private struct. This must be done
* after the first start so that the global pagetable mappings
* are set up before we create the per-process pagetable.
*/// 创建kgsl process[3.4节]
dev_priv->process_priv =kgsl_process_private_open(device);if(IS_ERR(dev_priv->process_priv)){
result =PTR_ERR(dev_priv->process_priv);kgsl_close_device(device);goto err;}
err:if(result){
filep->private_data =NULL;kfree(dev_priv);pm_runtime_put(&device->pdev->dev);}return result;}
/**
* struct adreno_device_private - Adreno private structure per fd
* @dev_priv: the kgsl device private structure
* @perfcounter_list: list of perfcounters used by the process
*/structadreno_device_private{structkgsl_device_private dev_priv;structlist_head perfcounter_list;};
/**
* struct kgsl_process_private - Private structure for a KGSL process (across
* all devices)
*/structkgsl_process_private{// Internal flags, use KGSL_PROCESS_* valuesunsignedlong priv;structpid*pid;char comm[TASK_COMM_LEN];spinlock_t mem_lock;structkref refcount;// Iterator for assigning IDs to memory allocationsstructidr mem_idr;structkgsl_pagetable*pagetable;structlist_head list;// Pointer to a kobj for the sysfs directory for this processstructkobject kobj;structkobject kobj_memtype;// Pointer to the debugfs root for this processstructdentry*debug_root;// Memory allocation statistics for this processstruct{atomic64_t cur;uint64_t max;} stats[KGSL_MEM_ENTRY_MAX];// KGSL memory mapped in the process address spaceatomic64_t gpumem_mapped;structidr syncsource_idr;spinlock_t syncsource_lock;int fd_count;// 进程kgsl_context数量:adreno_context[见3.2.4节]创建时更新atomic_t ctxt_count;spinlock_t ctxt_count_lock;// Count for the number of frames processedatomic64_t frame_count;};
3.2.4 adreno_context
/**
* struct adreno_context - Adreno GPU draw context
*/structadreno_context{// [见3.2.5节]structkgsl_context base;// Last issued context-specific timestampunsignedint timestamp;// Global timestamp of the last issued commandunsignedint internal_timestamp;// Context type (GL, CL, RS)unsignedint type;spinlock_t lock;/* Dispatcher */structkgsl_drawobj*drawqueue[ADRENO_CONTEXT_DRAWQUEUE_SIZE];unsignedint drawqueue_head;unsignedint drawqueue_tail;wait_queue_head_t wq;wait_queue_head_t waiting;wait_queue_head_t timeout;// Number of commands queued in the drawqueueint queued;unsignedint fault_policy;// debugfs entry for this contextstructdentry*debug_root;unsignedint queued_timestamp;// The ringbuffer in which this context submits commandsstructadreno_ringbuffer*rb;// The last timestamp that was submitted for this contextunsignedint submitted_timestamp;uint64_t submit_retire_ticks[SUBMIT_RETIRE_TICKS_SIZE];int ticks_index;structlist_head active_node;// Time when this context last seenunsignedlong active_time;};
3.2.5 kgsl_context
/**
* struct kgsl_context - The context fields that are valid for a user defined context
*/structkgsl_context{structkref refcount;uint32_t id;uint32_t priority;pid_t tid;structkgsl_device_private*dev_priv;structkgsl_process_private*proc_priv;// in-kernel context flags, use KGSL_CONTEXT_* valuesunsignedlong priv;structkgsl_device*device;unsignedint reset_status;// sync timeline used to create fences that can be signaled when a sync_pt timestamp expiresstructkgsl_sync_timeline*ktimeline;structkgsl_event_group events;// flags from userspace controlling the behavior of this contextunsignedint flags;structkgsl_pwr_constraint pwr_constraint;structkgsl_pwr_constraint l3_pwr_constraint;unsignedint fault_count;unsignedlong fault_time;structkgsl_mem_entry*user_ctxt_record;unsignedint total_fault_count;unsignedint last_faulted_cmd_ts;
bool gmu_registered;/**
* @gmu_dispatch_queue: dispatch queue id to which this context will be
* submitted
*/
u32 gmu_dispatch_queue;};
3.3 kgsl_open_device
staticintkgsl_open_device(structkgsl_device*device){int result =0;mutex_lock(&device->mutex);if(device->open_count ==0){// 如果是第一次打开, 则调用adreno_first_open-->adreno_open打开GPU
result = device->ftbl->first_open(device);if(result)goto out;}// kgsl_device->open_count记录/dev/kgsl-3d0被打开的次数
device->open_count++;
out:mutex_unlock(&device->mutex);return result;}
3.4 kgsl_process_private_open
staticstructkgsl_process_private*kgsl_process_private_open(structkgsl_device*device){structkgsl_process_private*private;int i;// 创建kgsl_process_private[3.4.1节]
private =_process_private_open(device);/*
* If we get error and error is -EEXIST that means previous process
* private destroy is triggered but didn't complete. Retry creating
* process private after sometime to allow previous destroy to complete.
*/for(i =0;(PTR_ERR_OR_ZERO(private)==-EEXIST)&&(i <5); i++){usleep_range(10,100);
private =_process_private_open(device);}return private;}
staticstructkgsl_process_private*kgsl_process_private_new(structkgsl_device*device){structkgsl_process_private*private;// 当前进程pidstructpid*cur_pid =get_task_pid(current->group_leader, PIDTYPE_PID);/* Search in the process list */// 遍历kgsl_driver的进程链表list_for_each_entry(private,&kgsl_driver.process_list, list){// 进程已存在if(private->pid == cur_pid){if(!kgsl_process_private_get(private))/*
* This will happen only if refcount is zero
* i.e. destroy is triggered but didn't complete
* yet. Return -EEXIST to indicate caller that
* destroy is pending to allow caller to take
* appropriate action.
*/
private =ERR_PTR(-EEXIST);/*
* We need to hold only one reference to the PID for
* each process struct to avoid overflowing the
* reference counter which can lead to use-after-free.
*/put_pid(cur_pid);return private;}}/* Create a new object */// 创建新的kgsl_process_private
private =kzalloc(sizeof(structkgsl_process_private), GFP_KERNEL);if(private ==NULL){put_pid(cur_pid);returnERR_PTR(-ENOMEM);}kref_init(&private->refcount);// 更新pid和cmdline
private->pid = cur_pid;get_task_comm(private->comm, current->group_leader);spin_lock_init(&private->mem_lock);spin_lock_init(&private->syncsource_lock);spin_lock_init(&private->ctxt_count_lock);idr_init(&private->mem_idr);idr_init(&private->syncsource_idr);/* Allocate a pagetable for the new process object */// 分配页表
private->pagetable =kgsl_mmu_getpagetable(&device->mmu,pid_nr(cur_pid));if(IS_ERR(private->pagetable)){int err =PTR_ERR(private->pagetable);idr_destroy(&private->mem_idr);idr_destroy(&private->syncsource_idr);put_pid(private->pid);kfree(private);
private =ERR_PTR(err);return private;}// 为进程创建sysfs下的文件kgsl_process_init_sysfs(device, private);// 为进程创建debugfs下的目录kgsl_process_init_debugfs(private);write_lock(&kgsl_driver.proclist_lock);// 将进程添加到kgsl_driver的进程链表list_add(&private->list,&kgsl_driver.process_list);write_unlock(&kgsl_driver.proclist_lock);return private;}
static int __init kgsl_3d_init(void){ int ret; // 初始化kgsl_driver[见第2节] ret = kgsl_core_init(); if (ret) return ret; // 初始化gmu[见第3节] gmu_core_register(); // 注册adreno_platform_driver:见"adreno源码系列(四)注册platform_driver" ret = platform_driv