adreno系列kgsl driver
Posted bubbleben
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了adreno系列kgsl driver相关的知识,希望对你有一定的参考价值。
1. kgsl_driver定义
/**
* struct kgsl_driver - main container for global KGSL things
*/
struct kgsl_driver
// Character device struct
struct cdev cdev;
dev_t major;
struct class *class;
struct device virtdev;
struct kobject *ptkobj;
struct kobject *prockobj;
// Array of pointers to the individual KGSL device structs
struct kgsl_device *devp[1];
// kgsl_process_private链表
struct list_head process_list;
// List of open pagetables
struct list_head pagetable_list;
spinlock_t ptlock;
struct mutex process_mutex;
rwlock_t proclist_lock;
struct mutex devlock;
// Struct containing atomic memory statistics
struct
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;
unsigned int full_cache_threshold;
struct workqueue_struct *workqueue;
struct workqueue_struct *mem_workqueue;
struct kthread_worker worker;
struct task_struct *worker_thread;
;
2. kgsl_driver初始化
struct kgsl_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),
;
3. kgsl_fops
// open("/dev/kgsl-3d0", 0):通过open打开kgsl驱动
// kgsl_fops是kgsl_driver字符设备的file_operations
static const struct file_operations kgsl_fops =
.owner = THIS_MODULE,
.release = kgsl_release,
// open系统调用到kgsl_open[见3.1节]
.open = kgsl_open,
.mmap = kgsl_mmap,
.read = kgsl_read,
.get_unmapped_area = kgsl_get_unmapped_area,
.unlocked_ioctl = kgsl_ioctl,
.compat_ioctl = kgsl_compat_ioctl,
;
3.1 kgsl_open
static int kgsl_open(struct inode *inodep, struct file *filep)
int result;
struct kgsl_device_private *dev_priv;
struct kgsl_device *device;
unsigned int 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;
3.2 adreno_device_private_create
/**
* adreno_device_private_create(): Allocate an adreno_device_private structure
*/
static struct kgsl_device_private *adreno_device_private_create(void)
// 创建adreno_device_private[见3.2.1节]
struct adreno_device_private *adreno_priv =
kzalloc(sizeof(*adreno_priv), GFP_KERNEL);
if (adreno_priv)
INIT_LIST_HEAD(&adreno_priv->perfcounter_list);
// 返回adreno_device_private的成员kgsl_device_private
return &adreno_priv->dev_priv;
return NULL;
3.2.1 adreno_device_private
/**
* 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
*/
struct adreno_device_private
struct kgsl_device_private dev_priv;
struct list_head perfcounter_list;
;
3.2.2 kgsl_device_private
struct kgsl_device_private
struct kgsl_device *device;
// kgsl process[见3.2.3节]
struct kgsl_process_private *process_priv;
;
3.2.3 kgsl_process_private
/**
* struct kgsl_process_private - Private structure for a KGSL process (across
* all devices)
*/
struct kgsl_process_private
// Internal flags, use KGSL_PROCESS_* values
unsigned long priv;
struct pid *pid;
char comm[TASK_COMM_LEN];
spinlock_t mem_lock;
struct kref refcount;
// Iterator for assigning IDs to memory allocations
struct idr mem_idr;
struct kgsl_pagetable *pagetable;
struct list_head list;
// Pointer to a kobj for the sysfs directory for this process
struct kobject kobj;
struct kobject kobj_memtype;
// Pointer to the debugfs root for this process
struct dentry *debug_root;
// Memory allocation statistics for this process
struct
atomic64_t cur;
uint64_t max;
stats[KGSL_MEM_ENTRY_MAX];
// KGSL memory mapped in the process address space
atomic64_t gpumem_mapped;
struct idr 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 processed
atomic64_t frame_count;
;
3.2.4 adreno_context
/**
* struct adreno_context - Adreno GPU draw context
*/
struct adreno_context
// [见3.2.5节]
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 */
struct kgsl_drawobj *drawqueue[ADRENO_CONTEXT_DRAWQUEUE_SIZE];
unsigned int drawqueue_head;
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;
// debugfs entry for this context
struct dentry *debug_root;
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;
uint64_t submit_retire_ticks[SUBMIT_RETIRE_TICKS_SIZE];
int ticks_index;
struct list_head active_node;
// Time when this context last seen
unsigned long active_time;
;
3.2.5 kgsl_context
/**
* struct kgsl_context - The context fields that are valid for a user defined context
*/
struct kgsl_context
struct kref refcount;
uint32_t id;
uint32_t priority;
pid_t tid;
struct kgsl_device_private *dev_priv;
struct kgsl_process_private *proc_priv;
// in-kernel context flags, use KGSL_CONTEXT_* values
unsigned long priv;
struct kgsl_device *device;
unsigned int reset_status;
// sync timeline used to create fences that can be signaled when a sync_pt timestamp expires
struct kgsl_sync_timeline *ktimeline;
struct kgsl_event_group events;
// flags from userspace controlling the behavior of this context
unsigned int flags;
struct kgsl_pwr_constraint pwr_constraint;
struct kgsl_pwr_constraint l3_pwr_constraint;
unsigned int fault_count;
unsigned long fault_time;
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;
;
3.3 kgsl_open_device
static int kgsl_open_device(struct kgsl_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
static struct kgsl_process_private *kgsl_process_private_open(
struct kgsl_device *device)
struct kgsl_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;
3.4.1 _process_private_open
static struct kgsl_process_private *_process_private_open(
struct kgsl_device *device)
struct kgsl_process_private *private;
mutex_lock(&kgsl_driver.process_mutex);
// 创建kgsl_process_private[3.4.2节]
private = kgsl_process_private_new(device);
if (IS_ERR(private))
goto done;
// 进程的fd数量加1
private->fd_count++;
done:
mutex_unlock(&kgsl_driver.process_mutex);
return private;
3.4.2 kgsl_process_private_new
static struct kgsl_process_private *kgsl_process_private_new(
struct kgsl_device *device)
struct kgsl_process_private *private;
// 当前进程pid
struct pid *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(struct kgsl_process_private), GFP_KERNEL);
if (private == NULL)
put_pid(cur_pid);
return ERR_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;
以上是关于adreno系列kgsl driver的主要内容,如果未能解决你的问题,请参考以下文章