kgsl_ioctl_drawctxt_create

// ioctl命令:IOCTL_KGSL_DRAWCTXT_CREATE
// ioctl函数:kgsl_ioctl_drawctxt_create
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE, kgsl_ioctl_drawctxt_create);

long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	int result = 0;
    // ioctl命令参数:kgsl_drawctxt_create[见第1节]
	struct kgsl_drawctxt_create *param = data;
	struct kgsl_context *context = NULL;
	struct kgsl_device *device = dev_priv->device;

    // 创建kgsl_context:调用在adreno_functable中定义的adreno_drawctxt_create[见第2节]
	context = device->ftbl->drawctxt_create(dev_priv, &param->flags);
	if (IS_ERR(context)) {
		result = PTR_ERR(context);
		goto done;
	}
	trace_kgsl_context_create(dev_priv->device, context, param->flags);

	/* Commit the pointer to the context in context_idr */
	write_lock(&device->context_lock);
	idr_replace(&device->context_idr, context, context->id);
    // 通过kgsl_drawctxt_create返回创建的kgsl_context的id
	param->drawctxt_id = context->id;
	write_unlock(&device->context_lock);

done:
	return result;
}

1. kgsl_drawctxt_create

/* create a draw context, which is used to preserve GPU state.
 * The flags field may contain a mask KGSL_CONTEXT_*  values
 */
struct kgsl_drawctxt_create {
    // 入参:标志位
	unsigned int flags;
    // 返回值:kgsl_context的id
	unsigned int drawctxt_id; /*output param */
};

// IOCTL_KGSL_DRAWCTXT_CREATE命令:参数为kgsl_drawctxt_create
#define IOCTL_KGSL_DRAWCTXT_CREATE \
	_IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create)

2. adreno_drawctxt_create

/**
 * adreno_drawctxt_create - create a new adreno draw context
 * @dev_priv: the owner of the context
 * @flags: flags for the context (passed from user space)
 *
 * Create and return a new draw context for the 3D core.
 */
struct kgsl_context *
adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
			uint32_t *flags)
{
	struct adreno_context *drawctxt;
	struct kgsl_device *device = dev_priv->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	const struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	int ret;
	unsigned int local;

	local = *flags & (KGSL_CONTEXT_PREAMBLE |
		KGSL_CONTEXT_NO_GMEM_ALLOC |
		KGSL_CONTEXT_PER_CONTEXT_TS |
		KGSL_CONTEXT_USER_GENERATED_TS |
		KGSL_CONTEXT_NO_FAULT_TOLERANCE |
		KGSL_CONTEXT_INVALIDATE_ON_FAULT |
		KGSL_CONTEXT_CTX_SWITCH |
		KGSL_CONTEXT_PRIORITY_MASK |
		KGSL_CONTEXT_TYPE_MASK |
		KGSL_CONTEXT_PWR_CONSTRAINT |
		KGSL_CONTEXT_IFH_NOP |
		KGSL_CONTEXT_SECURE |
		KGSL_CONTEXT_PREEMPT_STYLE_MASK |
		KGSL_CONTEXT_NO_SNAPSHOT);

	/* Check for errors before trying to initialize */

	/* If preemption is not supported, ignore preemption request */
    // 判断是否支持抢占功能: 如果不支持则移除抢占相关的标志位
	if (!test_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv))
		local &= ~KGSL_CONTEXT_PREEMPT_STYLE_MASK;

	/* We no longer support legacy context switching */
	if ((local & KGSL_CONTEXT_PREAMBLE) == 0 ||
		(local & KGSL_CONTEXT_NO_GMEM_ALLOC) == 0) {
		dev_err_once(device->dev,
			"legacy context switch not supported\n");
		return ERR_PTR(-EINVAL);
	}

	/* Make sure that our target can support secure contexts if requested */
	if (!kgsl_mmu_is_secured(&dev_priv->device->mmu) &&
			(local & KGSL_CONTEXT_SECURE)) {
		dev_err_once(device->dev, "Secure context not supported\n");
		return ERR_PTR(-EOPNOTSUPP);
	}

    // 创建adreno_context对象[见2.1节]
	drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);

	if (drawctxt == NULL)
		return ERR_PTR(-ENOMEM);

	drawctxt->timestamp = 0;

    // 将标志位传递给kgsl_context
	drawctxt->base.flags = local;

	/* Always enable per-context timestamps */
	drawctxt->base.flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
    // kgsl_context类型:GL, CL, C2D, RS, VK
	drawctxt->type = (drawctxt->base.flags & KGSL_CONTEXT_TYPE_MASK)
		>> KGSL_CONTEXT_TYPE_SHIFT;
	spin_lock_init(&drawctxt->lock);
    // 初始化工作队列
	init_waitqueue_head(&drawctxt->wq);
	init_waitqueue_head(&drawctxt->waiting);
	init_waitqueue_head(&drawctxt->timeout);

	/* If the priority is not set by user, set it for them */
    // 如果未定义优先级, 则默认设置为KGSL_CONTEXT_PRIORITY_MED
	if ((drawctxt->base.flags & KGSL_CONTEXT_PRIORITY_MASK) ==
			KGSL_CONTEXT_PRIORITY_UNDEF)
		drawctxt->base.flags |= (KGSL_CONTEXT_PRIORITY_MED <<
				KGSL_CONTEXT_PRIORITY_SHIFT);

	/* Store the context priority */
	drawctxt->base.priority =
		(drawctxt->base.flags & KGSL_CONTEXT_PRIORITY_MASK) >>
		KGSL_CONTEXT_PRIORITY_SHIFT;

	/*
	 * Now initialize the common part of the context. This allocates the
	 * context id, and then possibly another thread could look it up.
	 * So we want all of our initializtion that doesn't require the context
	 * id to be done before this call.
	 */
    // 初始化kgsl_context[见2.2节], 初始化成功返回0
	ret = kgsl_context_init(dev_priv, &drawctxt->base);
	if (ret != 0) {
		kfree(drawctxt);
		return ERR_PTR(ret);
	}

	kgsl_sharedmem_writel(device->memstore,
			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
			0);
	kgsl_sharedmem_writel(device->memstore,
			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, eoptimestamp),
			0);

    // 在debugfs文件系统下为adreno_context创建节点[见2.3节]
	adreno_context_debugfs_init(ADRENO_DEVICE(device), drawctxt);

	INIT_LIST_HEAD(&drawctxt->active_node);

    // adreno_dispatcher_init中定义的setup_context方法:adreno_dispatcher_setup_context[见2.4节]
	if (adreno_dev->dispatch_ops && adreno_dev->dispatch_ops->setup_context)
		adreno_dev->dispatch_ops->setup_context(adreno_dev, drawctxt);

	if (gpudev->preemption_context_init) {
		ret = gpudev->preemption_context_init(&drawctxt->base);
		if (ret != 0) {
			kgsl_context_detach(&drawctxt->base);
			return ERR_PTR(ret);
		}
	}

	/* copy back whatever flags we dediced were valid */
    // 更新传入的标志位
	*flags = drawctxt->base.flags;

    // 返回kgsl_context
	return &drawctxt->base;
}

2.1 adreno_context

#define ADRENO_CONTEXT_DRAWQUEUE_SIZE 128
#define SUBMIT_RETIRE_TICKS_SIZE 7

/**
 * struct adreno_context - Adreno GPU draw context
 */
struct adreno_context {
    // kgsl_context[见2.1.1节]
	struct kgsl_context base;
    // Last issued context-specific timestamp
	unsigned int timestamp;
    // Global timestamp of the last issued command
	unsigned int internal_timestamp;
    // Context type (GL, CL, RS)
	unsigned int type;
	spinlock_t lock;

	/* Dispatcher */
    // Queue of drawobjs waiting to be dispatched for this context
	struct kgsl_drawobj *drawqueue[ADRENO_CONTEXT_DRAWQUEUE_SIZE];
    // Head of the drawqueue queue
	unsigned int drawqueue_head;
    // Tail of the drawqueue queue
	unsigned int drawqueue_tail;

	wait_queue_head_t wq;
	wait_queue_head_t waiting;
	wait_queue_head_t timeout;

    // Number of commands queued in the drawqueue
	int queued;
	unsigned int fault_policy;
	struct dentry *debug_root;
    // The last timestamp that was queued on this context
	unsigned int queued_timestamp;
    // The ringbuffer in which this context submits commands.
	struct adreno_ringbuffer *rb;
    // The last timestamp that was submitted for this context
	unsigned int submitted_timestamp;
    // Array to hold command obj execution times from submit to retire
	uint64_t submit_retire_ticks[SUBMIT_RETIRE_TICKS_SIZE];
    // The index into submit_retire_ticks[] where the new delta will be written.    
	int ticks_index;

    // Linkage for nodes in active_list
	struct list_head active_node;
    // Time when this context last seen
	unsigned long active_time;
};

2.1.1 kgsl_context

/**
 * struct kgsl_context - The context fields that are valid for a user defined context
 */
struct kgsl_context {
    // kref object for reference counting the context
	struct kref refcount;
    // integer identifier for the context
	uint32_t id;
    // The context's priority to submit commands to GPU
	uint32_t priority;
    // task that created this context.
	pid_t tid;
    // pointer to the owning device instance
	struct kgsl_device_private *dev_priv;
    // pointer to process private, the process that allocated the context[见2.1.2节]
	struct kgsl_process_private *proc_priv;
	unsigned long priv;
	struct kgsl_device *device;
	unsigned int reset_status;
	struct kgsl_sync_timeline *ktimeline;
    // A kgsl_event_group for this context - contains the list of GPU events[见2.1.3节]
	struct kgsl_event_group events;
	unsigned int flags;
	struct kgsl_pwr_constraint pwr_constraint;
	struct kgsl_pwr_constraint l3_pwr_constraint;
	unsigned int fault_count;
	ktime_t fault_time;
    // memory descriptor used by CP to save/restore VPC data across preemption
	struct kgsl_mem_entry *user_ctxt_record;
	unsigned int total_fault_count;
	unsigned int last_faulted_cmd_ts;
	bool gmu_registered;
	/**
	 * @gmu_dispatch_queue: dispatch queue id to which this context will be
	 * submitted
	 */
	u32 gmu_dispatch_queue;
};

2.1.2 kgsl_process_private

/**
 * struct kgsl_process_private -  Private structure for a KGSL process (across
 * all devices)
 */
struct kgsl_process_private {
	unsigned long priv;
	struct pid *pid;
	char comm[TASK_COMM_LEN];
	spinlock_t mem_lock;
	struct kref refcount;
	struct idr mem_idr;
    // 页表
	struct kgsl_pagetable *pagetable;
	struct list_head list;
	struct list_head reclaim_list;
	struct kobject kobj;
	struct dentry *debug_root;
	struct {
		atomic64_t cur;
		uint64_t max;
	} stats[KGSL_MEM_ENTRY_MAX];
	atomic64_t gpumem_mapped;
	struct idr syncsource_idr;
	spinlock_t syncsource_lock;
	int fd_count;
    // 进程的kgsl_context数量
	atomic_t ctxt_count;
	spinlock_t ctxt_count_lock;
	atomic64_t frame_count;
	/**
	 * @state: state consisting KGSL_PROC_STATE and KGSL_PROC_PINNED_STATE
	 */
	unsigned long state;
	/**
	 * @unpinned_page_count: The number of pages unpinned for reclaim
	 */
	atomic_t unpinned_page_count;
	/**
	 * @fg_work: Work struct to schedule foreground work
	 */
	struct work_struct fg_work;
	/**
	 * @reclaim_lock: Mutex lock to protect KGSL_PROC_PINNED_STATE
	 */
	struct mutex reclaim_lock;
	/**
	 * @cmd_count: The number of cmds that are active for the process
	 */
	atomic_t cmd_count;
	/**
	 * @kobj_memtype: Pointer to a kobj for memtype sysfs directory for this
	 * process
	 */
	struct kobject kobj_memtype;
};

2.1.3 kgsl_event_group

/**
 * struct event_group - A list of GPU events
 */
struct kgsl_event_group {
    // Pointer to the active context for the events
	struct kgsl_context *context;
	spinlock_t lock;
    // List of active GPU events
	struct list_head events;
    // Node for the master group list
	struct list_head group;
    // Last processed timestamp
	unsigned int processed;
    // String name for the group (for the debugfs file)
	char name[64];
    // Function pointer to read a timestamp
	readtimestamp_func readtimestamp;
    // Priv member to pass to the readtimestamp function
	void *priv;
};

2.2 kgsl_context_init

#define KGSL_MAX_CONTEXTS_PER_PROC 200

/**
 * kgsl_context_init() - helper to initialize kgsl_context members
 * @dev_priv: the owner of the context
 * @context: the newly created context struct, should be allocated by
 * the device specific drawctxt_create function.
 */
int kgsl_context_init(struct kgsl_device_private *dev_priv,
			struct kgsl_context *context)
{
	struct kgsl_device *device = dev_priv->device;
	int ret = 0, id;
    // 创建kgsl_context的进程
	struct kgsl_process_private  *proc_priv = dev_priv->process_priv;

	/*
	 * Read and increment the context count under lock to make sure
	 * no process goes beyond the specified context limit.
	 */
	spin_lock(&proc_priv->ctxt_count_lock);
    // 每个进程持有的kgsl_context数量不能超过200
	if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) {
		dev_err(device->dev,
			     "Per process context limit reached for pid %u\n",
			     pid_nr(dev_priv->process_priv->pid));
		spin_unlock(&proc_priv->ctxt_count_lock);
		kgsl_context_debug_info(device);
		return -ENOSPC;
	}

    // 进程的kgsl_context数量加1
	atomic_inc(&proc_priv->ctxt_count);
	spin_unlock(&proc_priv->ctxt_count_lock);

    // 分配新的context id
	id = _kgsl_get_context_id(device);
	if (id == -ENOSPC) {
		/*
		 * Before declaring that there are no contexts left try
		 * flushing the event workqueue just in case there are
		 * detached contexts waiting to finish
		 */

		flush_workqueue(device->events_wq);
		id = _kgsl_get_context_id(device);
	}

	if (id < 0) {
		if (id == -ENOSPC) {
			dev_warn(device->dev,
				      "cannot have more than %zu contexts due to memstore limitation\n",
				      KGSL_MEMSTORE_MAX);
			kgsl_context_debug_info(device);
		}
		atomic_dec(&proc_priv->ctxt_count);
		return id;
	}

    // 设置kgsl_context的id
	context->id = id;

    // kgsl_context的引用计数加1
	kref_init(&context->refcount);
	/*
	 * Get a refernce to the process private so its not destroyed, until
	 * the context is destroyed. This will also prevent the pagetable
	 * from being destroyed
	 */
	if (!kgsl_process_private_get(dev_priv->process_priv)) {
		ret = -EBADF;
		goto out;
	}

    // 设置kgsl_context的kgsl_device
	context->device = dev_priv->device;
    // 设置kgsl_context的kgsl_device_private
	context->dev_priv = dev_priv;
    // 设置kgsl_context的kgsl_process_private
	context->proc_priv = dev_priv->process_priv;
    // 创建kgsl_context的进程pid
	context->tid = task_pid_nr(current);

	ret = kgsl_sync_timeline_create(context);
	if (ret) {
		kgsl_process_private_put(dev_priv->process_priv);
		goto out;
	}

    // 初始化kgsl_context的kgsl_event_group[见2.2.1节]
	kgsl_add_event_group(device, &context->events, context,
		kgsl_readtimestamp, context, "context-%d", id);

out:
	if (ret) {
		atomic_dec(&proc_priv->ctxt_count);
		write_lock(&device->context_lock);
		idr_remove(&dev_priv->device->context_idr, id);
		write_unlock(&device->context_lock);
	}

	return ret;
}

2.2.1 kgsl_add_event_group

void kgsl_add_event_group(struct kgsl_device *device,
		struct kgsl_event_group *group, struct kgsl_context *context,
		readtimestamp_func readtimestamp,
		void *priv, const char *fmt, ...)
{
	va_list args;

	WARN_ON(readtimestamp == NULL);

	spin_lock_init(&group->lock);
	INIT_LIST_HEAD(&group->events);

    // kgsl_context
	group->context = context;
    // kgsl_event_group的读时间戳的方法:kgsl_readtimestamp
	group->readtimestamp = readtimestamp;
    // priv成员也是kgsl_context
	group->priv = priv;

    // 设置kgsl_event_group的name为"context-id"
	if (fmt) {
		va_start(args, fmt);
		vsnprintf(group->name, sizeof(group->name), fmt, args);
		va_end(args);
	}

	write_lock(&device->event_groups_lock);
    // 将kgsl_event_group添加到kgsl_device的链表event_groups的表尾
	list_add_tail(&group->group, &device->event_groups);
	write_unlock(&device->event_groups_lock);
}

2.3 adreno_context_debugfs_init

void adreno_context_debugfs_init(struct adreno_device *adreno_dev,
			    struct adreno_context *ctx)
{
	unsigned char name[16];

	/*
	 * Get the context here to make sure it still exists for the life of the
	 * file
	 */
	_kgsl_context_get(&ctx->base);

    // 节点名称为kgsl_context的id
	snprintf(name, sizeof(name), "%d", ctx->base.id);

    // 在debugfs节点下创建"context-id":文件操作函数为ctx_fops
	ctx->debug_root = debugfs_create_file(name, 0444,
				adreno_dev->ctx_d_debugfs, ctx, &ctx_fops);
}

2.3.1 ctx_fops

static int ctx_open(struct inode *inode, struct file *file)
{
	int ret;
	struct adreno_context *ctx = inode->i_private;

	if (!_kgsl_context_get(&ctx->base))
		return -ENODEV;

	ret = single_open(file, ctx_print, &ctx->base);
	if (ret)
		kgsl_context_put(&ctx->base);
	return ret;
}

static const struct file_operations ctx_fops = {
    // 打开文件的函数
	.open = ctx_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = ctx_release,
};

2.4 adreno_dispatcher_setup_context

static void adreno_dispatcher_setup_context(struct adreno_device *adreno_dev,
		struct adreno_context *drawctxt)
{
    // 设置adreno_context的adreno_ringbuffer[见2.4.1节]
	drawctxt->rb = dispatch_get_rb(adreno_dev, drawctxt);
}

2.4.1 dispatch_get_rb

/* Return the ringbuffer that matches the draw context priority */
static struct adreno_ringbuffer *dispatch_get_rb(struct adreno_device *adreno_dev,
		struct adreno_context *drawctxt)
{
	int level;

	/* If preemption is disabled everybody goes on the same ringbuffer */
    // 不支持抢占, 则直接返回adreno_device的ringbuffers数组的第一个元素
	if (!adreno_is_preemption_enabled(adreno_dev))
		return &adreno_dev->ringbuffers[0];

	/*
	 * Math to convert the priority field in context structure to an RB ID.
	 * Divide up the context priority based on number of ringbuffer levels.
	 */
    // 否则根据kgsl_context的优先级来选择对应的adreno_ringbuffer
	level = min_t(int, drawctxt->base.priority / adreno_dev->num_ringbuffers,
		adreno_dev->num_ringbuffers - 1);

	return &adreno_dev->ringbuffers[level];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值