/**
* struct kgsl_drawobj - KGSL drawobj descriptor
*/// kgsl_drawobj的容器为kgsl_drawobj_cmd[见1.3节]structkgsl_drawobj{// KGSL GPU device that the command was created forstructkgsl_device*device;// KGSL context that created the commandstructkgsl_context*context;// Object typeuint32_t type;// Timestamp assigned to the commanduint32_t timestamp;// 标志位unsignedlong flags;// 引用计数structkref refcount;/** @destroy: Callbak function to take down the object */void(*destroy)(structkgsl_drawobj*drawobj);/** @destroy_object: Callback function to free the object memory */void(*destroy_object)(structkgsl_drawobj*drawobj);};
1.3 kgsl_drawobj_cmd
/**
* struct kgsl_drawobj_cmd - KGSL command obj, This covers marker
* cmds also since markers are special form of cmds that do not
* need their cmds to be executed.
*/structkgsl_drawobj_cmd{// 第一个成员structkgsl_drawobj base;// Internal flagsunsignedlong priv;// The ringbuffer timestamp corresponding to this command objunsignedint global_ts;unsignedlong fault_policy;unsignedlong fault_recovery;// List of IBs to issuestructlist_head cmdlist;// List of all memory used in this command batchstructlist_head memlist;// For markers, the timestamp of the last "real" command that was queuedunsignedint marker_timestamp;// profilingstructkgsl_mem_entry*profiling_buf_entry;uint64_t profiling_buffer_gpuaddr;unsignedint profile_index;// Variable to hold ticks at the time of command obj submituint64_t submit_ticks;};
2. _process_command_input
// kgsl_command_object最多100000个#defineKGSL_MAX_NUMIBS100000// kgsl_command_syncpoint最多32个#defineKGSL_MAX_SYNCPOINTS32#defineCMDOBJ_TYPEBIT(0)#defineMARKEROBJ_TYPEBIT(1)#defineSYNCOBJ_TYPEBIT(2)#defineTIMELINEOBJ_TYPEBIT(4)/* Returns 0 on failure. Returns command type(s) on success */staticunsignedint_process_command_input(structkgsl_device*device,unsignedint flags,unsignedint numcmds,unsignedint numobjs,unsignedint numsyncs){// kgsl_gpu_command的成员numcmds, numobjs和numsyncs不能超过最大限制if(numcmds > KGSL_MAX_NUMIBS ||
numobjs > KGSL_MAX_NUMIBS ||
numsyncs > KGSL_MAX_SYNCPOINTS)return0;/*
* The SYNC bit is supposed to identify a dummy sync object
* so warn the user if they specified any IBs with it.
* A MARKER command can either have IBs or not but if the
* command has 0 IBs it is automatically assumed to be a marker.
*//* If they specify the flag, go with what they say */// 首先根据标志位判断对象类型if(flags & KGSL_DRAWOBJ_MARKER)return MARKEROBJ_TYPE;elseif(flags & KGSL_DRAWOBJ_SYNC)return SYNCOBJ_TYPE;/* If not, deduce what they meant */// 然后根据numsyncs和numcmds确定对象类型if(numsyncs && numcmds)return SYNCOBJ_TYPE | CMDOBJ_TYPE;elseif(numsyncs)return SYNCOBJ_TYPE;elseif(numcmds)return CMDOBJ_TYPE;elseif(numcmds ==0)return MARKEROBJ_TYPE;return0;}
staticintdrawobj_init(structkgsl_device*device,structkgsl_context*context,structkgsl_drawobj*drawobj,int type){/*
* Increase the reference count on the context so it doesn't disappear
* during the lifetime of this object
*/// 增加kgsl_context引用计数if(!_kgsl_context_get(context))return-ENOENT;// 初始化kgsl_drawobj的引用计数kref_init(&drawobj->refcount);
drawobj->device = device;// 设置kgsl_drawobj所属的kgsl_context
drawobj->context = context;// 设置kgsl_drawobj类型
drawobj->type = type;return0;}
4. kgsl_drawobj_cmd_add_cmdlist
/* This can only accept MARKEROBJ_TYPE and CMDOBJ_TYPE */// ptr:kgsl_gpu_command的cmdlist// size:kgsl_gpu_command的cmdsize// count:kgsl_gpu_command的numcmdsintkgsl_drawobj_cmd_add_cmdlist(structkgsl_device*device,structkgsl_drawobj_cmd*cmdobj,void __user *ptr,unsignedint size,unsignedint count){// kgsl_command_object[见4.1节]structkgsl_command_object obj;structkgsl_drawobj*baseobj =DRAWOBJ(cmdobj);int i, ret;/* Ignore everything if this is a MARKER */if(baseobj->type & MARKEROBJ_TYPE)return0;// 参数校验
ret =_verify_input_list(count, ptr, size);if(ret <=0)return ret;// 遍历每一个cmdfor(i =0; i < count; i++){memset(&obj,0,sizeof(obj));// 将用户空间传入的ptr指向的大小为size的对象拷贝到kgsl_command_object
ret =kgsl_copy_from_user(&obj, ptr,sizeof(obj), size);if(ret)return ret;/* Sanity check the flags */if(!(obj.flags & CMDLIST_FLAGS)){dev_err(device->dev,"invalid cmdobj ctxt %d flags %d id %d offset %llu addr %llx size %llu\n",
baseobj->context->id, obj.flags, obj.id,
obj.offset, obj.gpuaddr, obj.size);return-EINVAL;}// 将kgsl_command_object添加到kgsl_drawobj_cmd的链表cmdlist[见4.2节]
ret =kgsl_drawobj_add_memobject(&cmdobj->cmdlist,&obj);if(ret)return ret;// ptr指针向后移动以遍历下一个cmd
ptr +=sizeof(obj);}return0;}
4.1 kgsl_command_object
/**
* struct kgsl_command_object - GPU command object
*/structkgsl_command_object{// GPU address offset of the object
__u64 offset;// GPU address of the object
__u64 gpuaddr;// Size of the object
__u64 size;// Current flags for the objectunsignedint flags;// GPU command object IDunsignedint id;};
/**
* struct kgsl_memobj_node - Memory object descriptor
* @node: Local list node for the object
* @id: GPU memory ID for the object
* offset: Offset within the object
* @gpuaddr: GPU address for the object
* @flags: External flags passed by the user
* @priv: Internal flags set by the driver
*/structkgsl_memobj_node{structlist_head node;unsignedint id;uint64_t offset;uint64_t gpuaddr;uint64_t size;unsignedlong flags;unsignedlong priv;};
5. kgsl_drawobj_cmd_add_memlist
// ptr:kgsl_gpu_command的objlist// size:kgsl_gpu_command的objsize// count:kgsl_gpu_command的numobjsintkgsl_drawobj_cmd_add_memlist(structkgsl_device*device,structkgsl_drawobj_cmd*cmdobj,void __user *ptr,unsignedint size,unsignedint count){structkgsl_command_object obj;structkgsl_drawobj*baseobj =DRAWOBJ(cmdobj);int i, ret;/* Ignore everything if this is a MARKER */if(baseobj->type & MARKEROBJ_TYPE)return0;
ret =_verify_input_list(count, ptr, size);if(ret <=0)return ret;// 遍历每一个cmdfor(i =0; i < count; i++){memset(&obj,0,sizeof(obj));// 将用户空间传入的ptr指向的大小为size的对象拷贝到kgsl_command_object
ret =kgsl_copy_from_user(&obj, ptr,sizeof(obj), size);if(ret)return ret;if(!(obj.flags & KGSL_OBJLIST_MEMOBJ)){dev_err(device->dev,"invalid memobj ctxt %d flags %d id %d offset %lld addr %lld size %lld\n",DRAWOBJ(cmdobj)->context->id, obj.flags,
obj.id, obj.offset, obj.gpuaddr,
obj.size);return-EINVAL;}if(obj.flags & KGSL_OBJLIST_PROFILE)add_profiling_buffer(device, cmdobj, obj.gpuaddr,
obj.size, obj.id, obj.offset);else{// 将kgsl_command_object添加到kgsl_drawobj_cmd的链表memlist
ret =kgsl_drawobj_add_memobject(&cmdobj->memlist,&obj);if(ret)return ret;}// ptr指针向后移动以遍历下一个cmd
ptr +=sizeof(obj);}return0;}
6. adreno_queue_cmds
staticintadreno_queue_cmds(structkgsl_device_private*dev_priv,structkgsl_context*context,structkgsl_drawobj*drawobj[],
u32 count, u32 *timestamp){structkgsl_device*device = dev_priv->device;if(test_bit(GMU_DISPATCH,&device->gmu_core.flags))returnadreno_hwsched_queue_cmds(dev_priv, context, drawobj,
count, timestamp);// Queue a new draw object in the context[见第7节]returnadreno_dispatcher_queue_cmds(dev_priv, context, drawobj, count,
timestamp);}
7. adreno_dispatcher_queue_cmds
/* Number of commands that can be queued in a context before it sleeps */staticunsignedint _context_drawqueue_size =50;/**
* adreno_dispactcher_queue_cmds() - Queue a new draw object in the context
* @dev_priv: Pointer to the device private struct
* @context: Pointer to the kgsl draw context
* @drawobj: Pointer to the array of drawobj's being submitted
* @count: Number of drawobj's being submitted
* @timestamp: Pointer to the requested timestamp
*
* Queue a command in the context - if there isn't any room in the queue, then
* block until there is
*/intadreno_dispatcher_queue_cmds(structkgsl_device_private*dev_priv,structkgsl_context*context,structkgsl_drawobj*drawobj[],uint32_t count,uint32_t*timestamp){structkgsl_device*device = dev_priv->device;structadreno_device*adreno_dev =ADRENO_DEVICE(device);structadreno_context*drawctxt =ADRENO_CONTEXT(context);structadreno_dispatcher_drawqueue*dispatch_q;structadreno_dispatch_job*job;int ret;unsignedint i, user_ts;/*
* There is always a possibility that dispatcher may end up pushing
* the last popped draw object back to the context drawqueue. Hence,
* we can only queue up to _context_drawqueue_size - 1 here to make
* sure we never let drawqueue->queued exceed _context_drawqueue_size.
*/if(!count || count > _context_drawqueue_size -1)return-EINVAL;// 检查kgsl_context的状态
ret =_check_context_state(&drawctxt->base);if(ret)return ret;// 检查kgsl_drawobj_cmd的cmdlist链表中的每个kgsl_memobj_node的有效性
ret =_verify_cmdobj(dev_priv, context, drawobj, count);if(ret)return ret;/* wait for the suspend gate */wait_for_completion(&device->halt_gate);
job =kmem_cache_alloc(jobs_cache, GFP_KERNEL);if(!job)return-ENOMEM;
job->drawctxt = drawctxt;spin_lock(&drawctxt->lock);
ret =_check_context_state_to_queue_cmds(drawctxt, count);if(ret){spin_unlock(&drawctxt->lock);kmem_cache_free(jobs_cache, job);return ret;}
user_ts =*timestamp;/*
* If there is only one drawobj in the array and it is of
* type SYNCOBJ_TYPE, skip comparing user_ts as it can be 0
*/if(!(count ==1&& drawobj[0]->type == SYNCOBJ_TYPE)&&(drawctxt->base.flags & KGSL_CONTEXT_USER_GENERATED_TS)){/*
* User specified timestamps need to be greater than the last
* issued timestamp in the context
*/if(timestamp_cmp(drawctxt->timestamp, user_ts)>=0){spin_unlock(&drawctxt->lock);kmem_cache_free(jobs_cache, job);return-ERANGE;}}// 遍历传入的每个kgsl_drawobjfor(i =0; i < count; i++){switch(drawobj[i]->type){case MARKEROBJ_TYPE:
ret =drawctxt_queue_markerobj(adreno_dev, drawctxt,
drawobj[i], timestamp, user_ts);if(ret){spin_unlock(&drawctxt->lock);kmem_cache_free(jobs_cache, job);}if(ret ==1)goto done;elseif(ret)return ret;break;case CMDOBJ_TYPE:// drawctxt_queue_cmdobj[见7.1节]
ret =drawctxt_queue_cmdobj(adreno_dev, drawctxt,
drawobj[i], timestamp, user_ts);if(ret){spin_unlock(&drawctxt->lock);kmem_cache_free(jobs_cache, job);return ret;}break;case SYNCOBJ_TYPE:drawctxt_queue_syncobj(drawctxt, drawobj[i], timestamp);break;case TIMELINEOBJ_TYPE:
ret =drawctxt_queue_auxobj(adreno_dev,
drawctxt, drawobj[i], timestamp, user_ts);if(ret){spin_unlock(&drawctxt->lock);kmem_cache_free(jobs_cache, job);return ret;}break;default:spin_unlock(&drawctxt->lock);kmem_cache_free(jobs_cache, job);return-EINVAL;}}// 返回adreno_ringbuffer中的adreno_dispatcher_drawqueue
dispatch_q =ADRENO_DRAWOBJ_DISPATCH_DRAWQUEUE(drawobj[0]);_track_context(adreno_dev, dispatch_q, drawctxt);spin_unlock(&drawctxt->lock);/* Add the context to the dispatcher pending list */if(_kgsl_context_get(&drawctxt->base)){trace_dispatch_queue_context(drawctxt);llist_add(&job->node,&adreno_dev->dispatcher.jobs[drawctxt->base.priority]);}else{kmem_cache_free(jobs_cache, job);goto done;}/*
* Only issue commands if inflight is less than burst -this prevents us
* from sitting around waiting for the mutex on a busy system - the work
* loop will schedule it for us. Inflight is mutex protected but the
* worse that can happen is that it will go to 0 after we check and if
* it goes to 0 it is because the work loop decremented it and the work
* queue will try to schedule new commands anyway.
*/if(dispatch_q->inflight < _context_drawobj_burst)adreno_dispatcher_issuecmds(adreno_dev);
done:if(test_and_clear_bit(ADRENO_CONTEXT_FAULT,&context->priv))return-EPROTO;return0;}
7.1 drawctxt_queue_cmdobj
staticintdrawctxt_queue_cmdobj(structadreno_device*adreno_dev,structadreno_context*drawctxt,structkgsl_drawobj*drawobj,uint32_t*timestamp,unsignedint user_ts){structkgsl_drawobj_cmd*cmdobj =CMDOBJ(drawobj);unsignedint j;int ret;
ret =get_timestamp(drawctxt, drawobj, timestamp, user_ts);if(ret)return ret;/*
* If this is a real command then we need to force any markers
* queued before it to dispatch to keep time linear - set the
* skip bit so the commands get NOPed.
*/
j = drawctxt->drawqueue_head;while(j != drawctxt->drawqueue_tail){if(drawctxt->drawqueue[j]->type == MARKEROBJ_TYPE){structkgsl_drawobj_cmd*markerobj =CMDOBJ(drawctxt->drawqueue[j]);set_bit(CMDOBJ_SKIP,&markerobj->priv);}
j =DRAWQUEUE_NEXT(j, ADRENO_CONTEXT_DRAWQUEUE_SIZE);}
drawctxt->queued_timestamp =*timestamp;_set_ft_policy(adreno_dev, drawctxt, cmdobj);_cmdobj_set_flags(drawctxt, cmdobj);_queue_drawobj(drawctxt, drawobj);return0;}