drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
Extension
.c
Size
106247 bytes
Lines
3943
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct copy_context_work_handler_workarea {
	struct work_struct copy_context_work;
	struct kfd_process *p;
};

static void copy_context_work_handler(struct work_struct *work)
{
	struct copy_context_work_handler_workarea *workarea;
	struct mqd_manager *mqd_mgr;
	struct queue *q;
	struct mm_struct *mm;
	struct kfd_process *p;
	uint32_t tmp_ctl_stack_used_size, tmp_save_area_used_size;
	int i;

	workarea = container_of(work,
			struct copy_context_work_handler_workarea,
			copy_context_work);

	p = workarea->p;
	mm = get_task_mm(p->lead_thread);

	if (!mm)
		return;

	kthread_use_mm(mm);
	for (i = 0; i < p->n_pdds; i++) {
		struct kfd_process_device *pdd = p->pdds[i];
		struct device_queue_manager *dqm = pdd->dev->dqm;
		struct qcm_process_device *qpd = &pdd->qpd;

		list_for_each_entry(q, &qpd->queues_list, list) {
			if (q->properties.type != KFD_QUEUE_TYPE_COMPUTE)
				continue;

			mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_CP];

			/* We ignore the return value from get_wave_state
			 * because
			 * i) right now, it always returns 0, and
			 * ii) if we hit an error, we would continue to the
			 *      next queue anyway.
			 */
			mqd_mgr->get_wave_state(mqd_mgr,
					q->mqd,
					&q->properties,
					(void __user *)	q->properties.ctx_save_restore_area_address,
					&tmp_ctl_stack_used_size,
					&tmp_save_area_used_size);
		}
	}
	kthread_unuse_mm(mm);
	mmput(mm);
}

static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
{
	if (!usr_queue_id_array)
		return num_queues ? ERR_PTR(-EINVAL) : NULL;

	if (num_queues > KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
		return ERR_PTR(-EINVAL);

	return memdup_user(usr_queue_id_array,
			   array_size(num_queues, sizeof(uint32_t)));
}

int resume_queues(struct kfd_process *p,
		uint32_t num_queues,
		uint32_t *usr_queue_id_array)
{
	uint32_t *queue_ids = NULL;
	int total_resumed = 0;
	int i;

	if (usr_queue_id_array) {
		queue_ids = get_queue_ids(num_queues, usr_queue_id_array);

		if (IS_ERR(queue_ids))
			return PTR_ERR(queue_ids);

		/* mask all queues as invalid.  unmask per successful request */
		q_array_invalidate(num_queues, queue_ids);
	}

	for (i = 0; i < p->n_pdds; i++) {
		struct kfd_process_device *pdd = p->pdds[i];
		struct device_queue_manager *dqm = pdd->dev->dqm;
		struct device *dev = dqm->dev->adev->dev;
		struct qcm_process_device *qpd = &pdd->qpd;

Annotation

Implementation Notes