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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值