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

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
Extension
.c
Size
9285 bytes
Lines
330
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

while (wptr > 0) {
			queue_address[wptr] = kq->nop_packet;
			wptr = (wptr + 1) % queue_size_dwords;
			wptr64++;
		}
	}

	*buffer_ptr = &queue_address[wptr];
	kq->pending_wptr = wptr + packet_size_in_dwords;
	kq->pending_wptr64 = wptr64 + packet_size_in_dwords;

	return 0;

err_no_space:
	*buffer_ptr = NULL;
	return -ENOMEM;
}

int kq_submit_packet(struct kernel_queue *kq)
{
#ifdef DEBUG
	int i;

	for (i = *kq->wptr_kernel; i < kq->pending_wptr; i++) {
		pr_debug("0x%2X ", kq->pq_kernel_addr[i]);
		if (i % 15 == 0)
			pr_debug("\n");
	}
	pr_debug("\n");
#endif
	/* Fatal err detected, packet submission won't go through */
	if (amdgpu_amdkfd_is_fed(kq->dev->adev))
		return -EIO;

	/* Make sure ring buffer is updated before wptr updated */
	mb();

	if (kq->dev->kfd->device_info.doorbell_size == 8) {
		*kq->wptr64_kernel = kq->pending_wptr64;
		mb(); /* Make sure wptr updated before ring doorbell */
		write_kernel_doorbell64(kq->queue->properties.doorbell_ptr,
					kq->pending_wptr64);
	} else {
		*kq->wptr_kernel = kq->pending_wptr;
		mb(); /* Make sure wptr updated before ring doorbell */
		write_kernel_doorbell(kq->queue->properties.doorbell_ptr,
					kq->pending_wptr);
	}

	return 0;
}

void kq_rollback_packet(struct kernel_queue *kq)
{
	if (kq->dev->kfd->device_info.doorbell_size == 8) {
		kq->pending_wptr64 = *kq->wptr64_kernel;
		kq->pending_wptr = *kq->wptr_kernel %
			(kq->queue->properties.queue_size / 4);
	} else {
		kq->pending_wptr = *kq->wptr_kernel;
	}
}

struct kernel_queue *kernel_queue_init(struct kfd_node *dev,
					enum kfd_queue_type type)
{
	struct kernel_queue *kq;

	kq = kzalloc_obj(*kq);
	if (!kq)
		return NULL;

	if (kq_initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE))
		return kq;

	dev_err(dev->adev->dev, "Failed to init kernel queue\n");

	kfree(kq);
	return NULL;
}

void kernel_queue_uninit(struct kernel_queue *kq)
{
	kq_uninitialize(kq);
	kfree(kq);
}

Annotation

Implementation Notes