赞
踩
/** * 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; };
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), };
// 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,
};
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; }
/** * 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; }
/**
* 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;
};
struct kgsl_device_private {
struct kgsl_device *device;
// kgsl process[见3.2.3节]
struct kgsl_process_private *process_priv;
};
/** * 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; };
/** * 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; };
/** * 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; };
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; }
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; }
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; }
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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。