kgsl_ioctl_drawctxt_create
Posted bubbleben
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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, ¶m->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);以上是关于kgsl_ioctl_drawctxt_create的主要内容,如果未能解决你的问题,请参考以下文章