kgsl_ioctl_gpu_command

Posted bubbleben

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kgsl_ioctl_gpu_command相关的知识,希望对你有一定的参考价值。

// ioctl命令:IOCTL_KGSL_GPU_COMMAND
// ioctl参数:kgsl_gpu_command
// ioctl函数:kgsl_ioctl_gpu_command
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_COMMAND, kgsl_ioctl_gpu_command),

1. kgsl_ioctl_gpu_command

long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data)

    // IOCTL_KGSL_GPU_COMMAND命令参数[见1.1节]
	struct kgsl_gpu_command *param = data;
	struct kgsl_device *device = dev_priv->device;
	struct kgsl_context *context;
    // kgsl_drawobj[见第1.2节]数组:用于存放kgsl_drawobj_sync和kgsl_drawobj_cmd中的kgsl_drawobj
	struct kgsl_drawobj *drawobj[2];
	unsigned int type;
	long result;
	unsigned int i = 0;

    // 根据参数计算对象类型[见第2节]
	type = _process_command_input(device, param->flags, param->numcmds,
			param->numobjs, param->numsyncs);
	if (!type)
		return -EINVAL;

    // 根据context id查找对应的kgsl_context
	context = kgsl_context_get_owner(dev_priv, param->context_id);
	if (context == NULL)
		return -EINVAL;

    // 1.如果指定KGSL_DRAWOBJ_SYNC标志位, 则命令类型为SYNCOBJ_TYPE
    // 2.如果传入的kgsl_gpu_command的numsyncs大于0, 则命令类型包含SYNCOBJ_TYPE
	if (type & SYNCOBJ_TYPE) 
		struct kgsl_drawobj_sync *syncobj =
				kgsl_drawobj_sync_create(device, context);

		if (IS_ERR(syncobj)) 
			result = PTR_ERR(syncobj);
			goto done;
		

		drawobj[i++] = DRAWOBJ(syncobj);

		result = kgsl_drawobj_sync_add_synclist(device, syncobj,
				u64_to_user_ptr(param->synclist),
				param->syncsize, param->numsyncs);
		if (result)
			goto done;
	

    // 1.如果指定KGSL_DRAWOBJ_MARKER标志位, 则命令类型为MARKEROBJ_TYPE
    // 2.如果传入的kgsl_gpu_command的numcmds大于0, 则命令类型包含CMDOBJ_TYPE
    // 3.如果传入的kgsl_gpu_command的numcmds等于0, 则命令类型为MARKEROBJ_TYPE
	if (type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)) 
        // 调用kgsl_drawobj_cmd_create[见第3节]创建kgsl_drawobj_cmd
		struct kgsl_drawobj_cmd *cmdobj =
				kgsl_drawobj_cmd_create(device,
					context, param->flags, type);

		if (IS_ERR(cmdobj)) 
			result = PTR_ERR(cmdobj);
			goto done;
		

        // drawobj数组元素加1
		drawobj[i++] = DRAWOBJ(cmdobj);

        // 将cmdlist插入kgsl_drawobj_cmd的cmdlist链表[第4节]
		result = kgsl_drawobj_cmd_add_cmdlist(device, cmdobj,
			u64_to_user_ptr(param->cmdlist),
			param->cmdsize, param->numcmds);
		if (result)
			goto done;

        // 将objlist插入kgsl_drawobj_cmd的memlist链表[第5节]
		result = kgsl_drawobj_cmd_add_memlist(device, cmdobj,
			u64_to_user_ptr(param->objlist),
			param->objsize, param->numobjs);
		if (result)
			goto done;

		/* If no profiling buffer was specified, clear the flag */
		if (cmdobj->profiling_buf_entry == NULL)
			DRAWOBJ(cmdobj)->flags &=
				~(unsigned long)KGSL_DRAWOBJ_PROFILING;
	

    // 调用adreno_functable中定义的adreno_queue_cmds[第6节]将kgsl_drawobj提交给ringbuffer
	result = device->ftbl->queue_cmds(dev_priv, context, drawobj,
				i, &param->timestamp);

done:
	/*
	 * -EPROTO is a "success" error - it just tells the user that the
	 * context had previously faulted
	 */
	if (result && result != -EPROTO)
		while (i--)
			kgsl_drawobj_destroy(drawobj[i]);

	kgsl_context_put(context);
	return result;

1.1 kgsl_gpu_command

/**
 * struct kgsl_command_object - Argument for IOCTL_KGSL_GPU_COMMAND
 */
struct kgsl_gpu_command 
    // 标志位
	__u64 flags;

    // 指向kgsl_command_object链表的指针(for submission)
	__u64 __user cmdlist;
    // kgsl_command_object的大小
	unsigned int cmdsize;
    // cmdlist中kgsl_command_object的数量
	unsigned int numcmds;

    // 指向kgsl_command_object链表的指针(for tracking)
	__u64 __user objlist;
    // kgsl_command_object的大小
	unsigned int objsize;
    // objlist中kgsl_command_object的数量
	unsigned int numobjs;

    // 指向kgsl_command_syncpoint链表的指针
    __u64 __user synclist;
    // kgsl_command_syncpoint的大小
	unsigned int syncsize;
    // synclist中kgsl_command_syncpoint的数量
	unsigned int numsyncs;

    // kgsl_context的id
	unsigned int context_id;
    // Timestamp for the submitted commands
	unsigned int timestamp;
;

1.2 kgsl_drawobj

/**
 * struct kgsl_drawobj - KGSL drawobj descriptor
 */
// kgsl_drawobj的容器为kgsl_drawobj_cmd[见1.3节]
struct kgsl_drawobj 
    // KGSL GPU device that the command was created for
	struct kgsl_device *device;
    // KGSL context that created the command
	struct kgsl_context *context;
    // Object type
	uint32_t type;
    // Timestamp assigned to the command
	uint32_t timestamp;
    // 标志位
	unsigned long flags;
    // 引用计数
	struct kref refcount;
	/** @destroy: Callbak function to take down the object */
	void (*destroy)(struct kgsl_drawobj *drawobj);
	/** @destroy_object: Callback function to free the object memory */
	void (*destroy_object)(struct kgsl_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.
 */
struct kgsl_drawobj_cmd 
    // 第一个成员
	struct kgsl_drawobj base;
    // Internal flags
	unsigned long priv;

    // The ringbuffer timestamp corresponding to this command obj
	unsigned int global_ts;

    unsigned long fault_policy;
	unsigned long fault_recovery;

    // List of IBs to issue
	struct list_head cmdlist;
    // List of all memory used in this command batch
	struct list_head memlist;
    // For markers, the timestamp of the last "real" command that was queued
	unsigned int marker_timestamp;

    // profiling
	struct kgsl_mem_entry *profiling_buf_entry;
	uint64_t profiling_buffer_gpuaddr;
	unsigned int profile_index;

    // Variable to hold ticks at the time of command obj submit
	uint64_t submit_ticks;
;

2. _process_command_input

// kgsl_command_object最多100000个
#define KGSL_MAX_NUMIBS 100000
// kgsl_command_syncpoint最多32个
#define KGSL_MAX_SYNCPOINTS 32

#define CMDOBJ_TYPE     BIT(0)
#define MARKEROBJ_TYPE  BIT(1)
#define SYNCOBJ_TYPE    BIT(2)
#define TIMELINEOBJ_TYPE    BIT(4)

/* Returns 0 on failure.  Returns command type(s) on success */
static unsigned int _process_command_input(struct kgsl_device *device,
		unsigned int flags, unsigned int numcmds,
		unsigned int numobjs, unsigned int numsyncs)

    // kgsl_gpu_command的成员numcmds, numobjs和numsyncs不能超过最大限制
	if (numcmds > KGSL_MAX_NUMIBS ||
			numobjs > KGSL_MAX_NUMIBS ||
			numsyncs > KGSL_MAX_SYNCPOINTS)
		return 0;

	/*
	 * 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;
	else if (flags & KGSL_DRAWOBJ_SYNC)
		return SYNCOBJ_TYPE;

	/* If not, deduce what they meant */
    // 然后根据numsyncs和numcmds确定对象类型
	if (numsyncs && numcmds)
		return SYNCOBJ_TYPE | CMDOBJ_TYPE;
	else if (numsyncs)
		return SYNCOBJ_TYPE;
	else if (numcmds)
		return CMDOBJ_TYPE;
	else if (numcmds == 0)
		return MARKEROBJ_TYPE;

	return 0;

3. kgsl_drawobj_cmd_create

/**
 * kgsl_drawobj_cmd_create() - Create a new command obj structure
 * Allocate a new kgsl_drawobj_cmd structure
 */
struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device,
		struct kgsl_context *context, unsigned int flags,
		unsigned int type)

    // 分配kgsl_drawobj_cmd
	struct kgsl_drawobj_cmd *cmdobj = kzalloc(sizeof(*cmdobj), GFP_KERNEL);
	int ret;

	if (!cmdobj)
		return ERR_PTR(-ENOMEM);

    // 初始化kgsl_drawobj[见3.1节]
	ret = drawobj_init(device, context, &cmdobj->base,
		(type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)));
	if (ret) 
		kfree(cmdobj);
		return ERR_PTR(ret);
	

    // 设置kgsl_drawobj的destroy回调
	cmdobj->base.destroy = cmdobj_destroy;
    // 设置kgsl_drawobj的destroy_object回调
	cmdobj->base.destroy_object = cmdobj_destroy_object;

	/* sanitize our flags for drawobjs */
    // 设置kgsl_drawobj的标志位
	cmdobj->base.flags = flags & (KGSL_DRAWOBJ_CTX_SWITCH
		| KGSL_DRAWOBJ_MARKER
		| KGSL_DRAWOBJ_END_OF_FRAME
		| KGSL_DRAWOBJ_PWR_CONSTRAINT
		| KGSL_DRAWOBJ_MEMLIST
		| KGSL_DRAWOBJ_PROFILING
		| KGSL_DRAWOBJ_PROFILING_KTIME);

    // 初始化kgsl_drawobj_cmd的cmdlist
	INIT_LIST_HEAD(&cmdobj->cmdlist);
    // 初始化kgsl_drawobj_cmd的memlist
	INIT_LIST_HEAD(&cmdobj->memlist);

	return cmdobj;

3.1 drawobj_init

static int drawobj_init(struct kgsl_device *device,
	struct kgsl_context *context, struct kgsl_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;

	return 0;

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的numcmds
int kgsl_drawobj_cmd_add_cmdlist(struct kgsl_device *device,
		struct kgsl_drawobj_cmd *cmdobj, void __user *ptr,
		unsigned int size, unsigned int count)

    // kgsl_command_object[见4.1节]
	struct kgsl_command_object obj;
	struct kgsl_drawobj *baseobj = DRAWOBJ(cmdobj);
	int i, ret;

	/* Ignore everything if this is a MARKER */
	if (baseobj->type & MARKEROBJ_TYPE)
		return 0;

    // 参数校验
	ret = _verify_input_list(count, ptr, size);
	if (ret <= 0)
		return ret;

    // 遍历每一个cmd
	for (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);
	

	return 0;

4.1 kgsl_command_object

/**
 * struct kgsl_command_object - GPU command object
 */
struct kgsl_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 object
	unsigned int flags;
    // GPU command object ID
	unsigned int id;
;

4.2 kgsl_drawobj_add_memobject

static int kgsl_drawobj_add_memobject(struct list_head *head,
		struct kgsl_command_object *obj)

	struct kgsl_memobj_node *mem;

    // 创建kgsl_memobj_node[见4.2.1节]
	mem = kmem_cache_alloc(memobjs_cache, GFP_KERNEL);
	if (mem == NULL)
		return -ENOMEM;

    // 将kgsl_command_object的成员赋值给kgsl_memobj_node
	mem->gpuaddr = obj->gpuaddr;
	mem->size = obj->size;
	mem->id = obj->id;
	mem->offset = obj->offset;
	mem->flags = obj->flags;
    // 初始化priv成员
	mem->priv = 0;

    // 将kgsl_memobj_node插入到kgsl_drawobj_cmd链表cmdlist的表尾
	list_add_tail(&mem->node, head);
	return 0;

4.2.1 kgsl_memobj_node

/**
 * 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
 */
struct kgsl_memobj_node 
	struct list_head node;
	unsigned int id;
	uint64_t offset;
	uint64_t gpuaddr;
	uint64_t size;
	unsigned long flags;
	unsigned long priv;
;

5. kgsl_drawobj_cmd_add_memlist

// ptr:kgsl_gpu_command的objlist
// size:kgsl_gpu_command的objsize
// count:kgsl_gpu_command的numobjs
int kgsl_drawobj_cmd_add_memlist(struct kgsl_device *device,
		struct kgsl_drawobj_cmd *cmdobj, void __user *ptr,
		unsigned int size, unsigned int count)

	struct kgsl_command_object obj;
	struct kgsl_drawobj *baseobj = DRAWOBJ(cmdobj);
	int i, ret;

	/* Ignore everything if this is a MARKER */
	if (baseobj->type & MARKEROBJ_TYPE)
		return 0;

	ret = _verify_input_list(count, ptr, size);
	if (ret <= 0)
		return ret;

    // 遍历每一个cmd
	for (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);
	

	return 0;

6. adreno_queue_cmds

static int adreno_queue_cmds(struct kgsl_device_private *dev_priv,
	struct kgsl_context *context, struct kgsl_drawobj *drawobj[],
	u32 count, u32 *timestamp)

	struct kgsl_device *device = dev_priv->device;

	if (test_bit(GMU_DISPATCH, &device->gmu_core.flags))
		return adreno_hwsched_queue_cmds(dev_priv, context, drawobj,
				count, timestamp);

    // Queue a new draw object in the context[见第7节]
	return adreno_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 */
static unsigned int _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
 */
int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,
		struct kgsl_con

以上是关于kgsl_ioctl_gpu_command的主要内容,如果未能解决你的问题,请参考以下文章

如何批量判断excel里面链接的有效性(是不是可以打开)?

Linux Shell中编写判断IP地址有效性脚本碰到了问题

excel 数据有效性的二次嵌套怎么做

用户传入的任何参数都必须做有效性验证,如果忽略的话可能会导致哪些危害系统

POI删除Excel中数据有效性

Excel知识点与技巧5 -分类汇总 数据有效性