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

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/amdkfd/kfd_events.c
Extension
.c
Size
37658 bytes
Lines
1428
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 kfd_event_waiter {
	wait_queue_entry_t wait;
	struct kfd_event *event; /* Event to wait for */
	bool activated;		 /* Becomes true when event is signaled */
	bool event_age_enabled;  /* set to true when last_event_age is non-zero */
};

/*
 * Each signal event needs a 64-bit signal slot where the signaler will write
 * a 1 before sending an interrupt. (This is needed because some interrupts
 * do not contain enough spare data bits to identify an event.)
 * We get whole pages and map them to the process VA.
 * Individual signal events use their event_id as slot index.
 */
struct kfd_signal_page {
	uint64_t *kernel_address;
	uint64_t __user *user_address;
	bool need_to_free_pages;
};

static uint64_t *page_slots(struct kfd_signal_page *page)
{
	return page->kernel_address;
}

static struct kfd_signal_page *allocate_signal_page(struct kfd_process *p)
{
	void *backing_store;
	struct kfd_signal_page *page;

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

	backing_store = (void *) __get_free_pages(GFP_KERNEL,
					get_order(KFD_SIGNAL_EVENT_LIMIT * 8));
	if (!backing_store)
		goto fail_alloc_signal_store;

	/* Initialize all events to unsignaled */
	memset(backing_store, (uint8_t) UNSIGNALED_EVENT_SLOT,
	       KFD_SIGNAL_EVENT_LIMIT * 8);

	page->kernel_address = backing_store;
	page->need_to_free_pages = true;
	pr_debug("Allocated new event signal page at %p, for process %p\n",
			page, p);

	return page;

fail_alloc_signal_store:
	kfree(page);
	return NULL;
}

static int allocate_event_notification_slot(struct kfd_process *p,
					    struct kfd_event *ev,
					    const int *restore_id)
{
	int id;

	if (!p->signal_page) {
		p->signal_page = allocate_signal_page(p);
		if (!p->signal_page)
			return -ENOMEM;
		/* Oldest user mode expects 256 event slots */
		p->signal_mapped_size = 256*8;
	}

	if (restore_id) {
		id = idr_alloc(&p->event_idr, ev, *restore_id, *restore_id + 1,
				GFP_KERNEL);
	} else {
		/*
		 * Compatibility with old user mode: Only use signal slots
		 * user mode has mapped, may be less than
		 * KFD_SIGNAL_EVENT_LIMIT. This also allows future increase
		 * of the event limit without breaking user mode.
		 */
		id = idr_alloc(&p->event_idr, ev, 0, p->signal_mapped_size / 8,
				GFP_KERNEL);
	}
	if (id < 0)
		return id;

	ev->event_id = id;
	page_slots(p->signal_page)[id] = UNSIGNALED_EVENT_SLOT;

	return 0;
}

Annotation

Implementation Notes