diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2116-drm-amdkfd-Simplify-events-page-allocator.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2116-drm-amdkfd-Simplify-events-page-allocator.patch | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2116-drm-amdkfd-Simplify-events-page-allocator.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2116-drm-amdkfd-Simplify-events-page-allocator.patch new file mode 100644 index 00000000..daa9330f --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/2116-drm-amdkfd-Simplify-events-page-allocator.patch @@ -0,0 +1,486 @@ +From 187f24e703a35588437d2b1f6dbd528cd06a9bc8 Mon Sep 17 00:00:00 2001 +From: Felix Kuehling <Felix.Kuehling@amd.com> +Date: Sat, 30 Sep 2017 20:46:03 -0400 +Subject: [PATCH 2116/4131] drm/amdkfd: Simplify events page allocator + +The first event page is always big enough to handle all events. +Handling of multiple events pages is not supported by user mode, and +not necessary. + +Change-Id: I75f61dc90ff647e9c49208097307694ff699b38d +Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> +--- + drivers/gpu/drm/amd/amdkfd/kfd_events.c | 227 ++++++++++---------------------- + drivers/gpu/drm/amd/amdkfd/kfd_events.h | 1 - + drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 5 +- + 3 files changed, 73 insertions(+), 160 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c +index 0baf130..9b76c38 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c +@@ -57,12 +57,10 @@ struct kfd_event_waiter { + * Individual signal events are then allocated a slot in a page. + */ + +-struct signal_page { +- struct list_head event_pages; /* kfd_process.signal_event_pages */ ++struct kfd_signal_page { + uint64_t *kernel_address; + uint64_t handle; + uint64_t __user *user_address; +- uint32_t page_index; /* Index into the mmap aperture. */ + unsigned int free_slots; + unsigned long used_slot_bitmap[SLOT_BITMAP_LONGS]; + }; +@@ -73,57 +71,48 @@ struct signal_page { + */ + + #define INTERRUPT_DATA_BITS 12 +-#define SIGNAL_EVENT_ID_SLOT_SHIFT 0 + +-static uint64_t *page_slots(struct signal_page *page) ++static uint64_t *page_slots(struct kfd_signal_page *page) + { + return page->kernel_address; + } + + static bool allocate_free_slot(struct kfd_process *process, +- struct signal_page **out_page, +- unsigned int *out_slot_index) ++ unsigned int *out_slot_index) + { +- struct signal_page *page; ++ struct kfd_signal_page *page = process->signal_page; ++ unsigned int slot; + +- list_for_each_entry(page, &process->signal_event_pages, event_pages) { +- if (page->free_slots > 0) { +- unsigned int slot = +- find_first_zero_bit(page->used_slot_bitmap, +- SLOTS_PER_PAGE); ++ if (!page || page->free_slots == 0) { ++ pr_debug("No free event signal slots were found for process %p\n", ++ process); + +- __set_bit(slot, page->used_slot_bitmap); +- page->free_slots--; ++ return false; ++ } + +- page_slots(page)[slot] = UNSIGNALED_EVENT_SLOT; ++ slot = find_first_zero_bit(page->used_slot_bitmap, SLOTS_PER_PAGE); + +- *out_page = page; +- *out_slot_index = slot; ++ __set_bit(slot, page->used_slot_bitmap); ++ page->free_slots--; + +- pr_debug("Allocated event signal slot in page %p, slot %d\n", +- page, slot); ++ page_slots(page)[slot] = UNSIGNALED_EVENT_SLOT; + +- return true; +- } +- } ++ *out_slot_index = slot; + +- pr_debug("No free event signal slots were found for process %p\n", +- process); ++ pr_debug("Allocated event signal slot in page %p, slot %d\n", ++ page, slot); + +- return false; ++ return true; + } + +-#define list_tail_entry(head, type, member) \ +- list_entry((head)->prev, type, member) +- +-static bool allocate_signal_page(struct file *devkfd, struct kfd_process *p) ++static struct kfd_signal_page *allocate_signal_page(struct kfd_process *p) + { + void *backing_store; +- struct signal_page *page; ++ struct kfd_signal_page *page; + + page = kzalloc(sizeof(*page), GFP_KERNEL); + if (!page) +- goto fail_alloc_signal_page; ++ return NULL; + + page->free_slots = SLOTS_PER_PAGE; + +@@ -132,99 +121,51 @@ static bool allocate_signal_page(struct file *devkfd, struct kfd_process *p) + if (!backing_store) + goto fail_alloc_signal_store; + +- /* prevent user-mode info leaks */ +- memset(backing_store, (uint8_t) UNSIGNALED_EVENT_SLOT, +- KFD_SIGNAL_EVENT_LIMIT * 8); +- + page->kernel_address = backing_store; +- +- if (list_empty(&p->signal_event_pages)) +- page->page_index = 0; +- else +- page->page_index = list_tail_entry(&p->signal_event_pages, +- struct signal_page, +- event_pages)->page_index + 1; +- + pr_debug("Allocated new event signal page at %p, for process %p\n", + page, p); +- pr_debug("Page index is %d\n", page->page_index); +- +- list_add(&page->event_pages, &p->signal_event_pages); + +- return true; ++ return page; + + fail_alloc_signal_store: + kfree(page); +-fail_alloc_signal_page: +- return false; ++ return NULL; + } + +-static bool allocate_event_notification_slot(struct file *devkfd, +- struct kfd_process *p, +- struct signal_page **page, +- unsigned int *signal_slot_index) ++static bool allocate_event_notification_slot(struct kfd_process *p, ++ unsigned int *signal_slot_index) + { +- bool ret; +- +- ret = allocate_free_slot(p, page, signal_slot_index); +- if (!ret) { +- ret = allocate_signal_page(devkfd, p); +- if (ret) +- ret = allocate_free_slot(p, page, signal_slot_index); ++ if (!p->signal_page) { ++ p->signal_page = allocate_signal_page(p); ++ if (!p->signal_page) ++ return false; + } + +- return ret; ++ return allocate_free_slot(p, signal_slot_index); + } + +-static bool allocate_signal_page_dgpu(struct kfd_process *p, +- uint64_t *kernel_address, uint64_t handle) ++static struct kfd_signal_page *allocate_signal_page_dgpu( ++ struct kfd_process *p, uint64_t *kernel_address, uint64_t handle) + { +- struct signal_page *my_page; ++ struct kfd_signal_page *my_page; + + my_page = kzalloc(sizeof(*my_page), GFP_KERNEL); + if (!my_page) +- return false; +- +- /* prevent user-mode info leaks */ +- memset(kernel_address, (uint8_t) UNSIGNALED_EVENT_SLOT, +- KFD_SIGNAL_EVENT_LIMIT * 8); ++ return NULL; + + my_page->kernel_address = kernel_address; + my_page->handle = handle; + my_page->user_address = NULL; + my_page->free_slots = SLOTS_PER_PAGE; +- if (list_empty(&p->signal_event_pages)) +- my_page->page_index = 0; +- else +- my_page->page_index = list_tail_entry(&p->signal_event_pages, +- struct signal_page, +- event_pages)->page_index + 1; + + pr_debug("Allocated new event signal page at %p, for process %p\n", + my_page, p); +- pr_debug("Page index is %d\n", my_page->page_index); +- +- list_add(&my_page->event_pages, &p->signal_event_pages); +- +- return true; +-} +- +-void kfd_free_signal_page_dgpu(struct kfd_process *p, uint64_t handle) +-{ +- struct signal_page *page, *tmp; + +- list_for_each_entry_safe(page, tmp, &p->signal_event_pages, +- event_pages) { +- if (page->handle == handle) { +- list_del(&page->event_pages); +- kfree(page); +- break; +- } +- } ++ return my_page; + } + + /* Assumes that the process's event_mutex is locked. */ +-static void release_event_notification_slot(struct signal_page *page, ++static void release_event_notification_slot(struct kfd_signal_page *page, + size_t slot_index) + { + __clear_bit(slot_index, page->used_slot_bitmap); +@@ -235,22 +176,6 @@ static void release_event_notification_slot(struct signal_page *page, + */ + } + +-static struct signal_page *lookup_signal_page_by_index(struct kfd_process *p, +- unsigned int page_index) +-{ +- struct signal_page *page; +- +- /* +- * This is safe because we don't delete signal pages until the +- * process exits. +- */ +- list_for_each_entry(page, &p->signal_event_pages, event_pages) +- if (page->page_index == page_index) +- return page; +- +- return NULL; +-} +- + /* + * Assumes that p->event_mutex is held and of course that p is not going + * away (current or locked). +@@ -272,13 +197,6 @@ static struct kfd_event *lookup_event_by_id(struct kfd_process *p, uint32_t id) + return NULL; + } + +-static u32 make_signal_event_id(struct signal_page *page, +- unsigned int signal_slot_index) +-{ +- return page->page_index | +- (signal_slot_index << SIGNAL_EVENT_ID_SLOT_SHIFT); +-} +- + /* + * Produce a kfd event id for a nonsignal event. + * These are arbitrary numbers, so we do a sequential search through +@@ -324,10 +242,9 @@ static u32 make_nonsignal_event_id(struct kfd_process *p) + } + + static struct kfd_event *lookup_event_by_page_slot(struct kfd_process *p, +- struct signal_page *page, + unsigned int signal_slot) + { +- return lookup_event_by_id(p, make_signal_event_id(page, signal_slot)); ++ return lookup_event_by_id(p, signal_slot); + } + + static int create_signal_event(struct file *devkfd, +@@ -342,8 +259,7 @@ static int create_signal_event(struct file *devkfd, + return -ENOMEM; + } + +- if (!allocate_event_notification_slot(devkfd, p, &ev->signal_page, +- &ev->signal_slot_index)) { ++ if (!allocate_event_notification_slot(p, &ev->signal_slot_index)) { + pr_warn("Signal event wasn't created because out of kernel memory\n"); + return -ENOMEM; + } +@@ -351,10 +267,9 @@ static int create_signal_event(struct file *devkfd, + p->signal_event_count++; + + ev->user_signal_address = +- &ev->signal_page->user_address[ev->signal_slot_index]; ++ &p->signal_page->user_address[ev->signal_slot_index]; + +- ev->event_id = make_signal_event_id(ev->signal_page, +- ev->signal_slot_index); ++ ev->event_id = ev->signal_slot_index; + + pr_debug("Signal event number %zu created with id %d, address %p\n", + p->signal_event_count, ev->event_id, +@@ -381,7 +296,7 @@ void kfd_event_init_process(struct kfd_process *p) + { + mutex_init(&p->event_mutex); + hash_init(p->events); +- INIT_LIST_HEAD(&p->signal_event_pages); ++ p->signal_page = NULL; + p->next_nonsignal_event_id = KFD_FIRST_NONSIGNAL_EVENT_ID; + p->signal_event_count = 0; + } +@@ -395,8 +310,9 @@ static void destroy_event(struct kfd_process *p, struct kfd_event *ev) + waiter->event = NULL; + wake_up_all(&ev->wq); + +- if (ev->signal_page) { +- release_event_notification_slot(ev->signal_page, ++ if ((ev->type == KFD_EVENT_TYPE_SIGNAL || ++ ev->type == KFD_EVENT_TYPE_DEBUG) && p->signal_page) { ++ release_event_notification_slot(p->signal_page, + ev->signal_slot_index); + p->signal_event_count--; + } +@@ -425,12 +341,11 @@ static void destroy_events(struct kfd_process *p) + * We assume that the process is being destroyed and there is no need to + * unmap the pages or keep bookkeeping data in order. + */ +-static void shutdown_signal_pages(struct kfd_process *p) ++static void shutdown_signal_page(struct kfd_process *p) + { +- struct signal_page *page, *tmp; ++ struct kfd_signal_page *page = p->signal_page; + +- list_for_each_entry_safe(page, tmp, &p->signal_event_pages, +- event_pages) { ++ if (page) { + if (page->user_address) + free_pages((unsigned long)page->kernel_address, + get_order(KFD_SIGNAL_EVENT_LIMIT * 8)); +@@ -441,7 +356,7 @@ static void shutdown_signal_pages(struct kfd_process *p) + void kfd_event_free_process(struct kfd_process *p) + { + destroy_events(p); +- shutdown_signal_pages(p); ++ shutdown_signal_page(p); + } + + static bool event_can_be_gpu_signaled(const struct kfd_event *ev) +@@ -475,8 +390,12 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p, + + mutex_lock(&p->event_mutex); + +- if (kern_addr && list_empty(&p->signal_event_pages)) +- allocate_signal_page_dgpu(p, kern_addr, *event_page_offset); ++ if (kern_addr && !p->signal_page) { ++ p->signal_page = allocate_signal_page_dgpu(p, kern_addr, ++ *event_page_offset); ++ if (!p->signal_page) ++ return -ENOMEM; ++ } + + *event_page_offset = 0; + +@@ -485,8 +404,7 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p, + case KFD_EVENT_TYPE_DEBUG: + ret = create_signal_event(devkfd, p, ev); + if (!ret) { +- *event_page_offset = (ev->signal_page->page_index | +- KFD_MMAP_TYPE_EVENTS); ++ *event_page_offset = KFD_MMAP_TYPE_EVENTS; + *event_page_offset <<= PAGE_SHIFT; + *event_slot_index = ev->signal_slot_index; + } +@@ -588,13 +506,17 @@ int kfd_reset_event(struct kfd_process *p, uint32_t event_id) + + static void acknowledge_signal(struct kfd_process *p, struct kfd_event *ev) + { +- page_slots(ev->signal_page)[ev->signal_slot_index] = ++ page_slots(p->signal_page)[ev->signal_slot_index] = + UNSIGNALED_EVENT_SLOT; + } + +-static bool is_slot_signaled(struct signal_page *page, unsigned int index) ++static bool is_slot_signaled(struct kfd_process *p, unsigned int index) + { +- return page_slots(page)[index] != UNSIGNALED_EVENT_SLOT; ++ if (!p->signal_page) ++ return false; ++ else ++ return page_slots(p->signal_page)[index] != ++ UNSIGNALED_EVENT_SLOT; + } + + static void set_event_from_interrupt(struct kfd_process *p, +@@ -627,22 +549,19 @@ void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id, + /* Partial ID is a full ID. */ + ev = lookup_event_by_id(p, partial_id); + set_event_from_interrupt(p, ev); +- } else { ++ } else if (p->signal_page) { + /* + * Partial ID is in fact partial. For now we completely + * ignore it, but we could use any bits we did receive to + * search faster. + */ +- struct signal_page *page; + unsigned int i; + +- list_for_each_entry(page, &p->signal_event_pages, event_pages) +- for (i = 0; i < SLOTS_PER_PAGE; i++) +- if (is_slot_signaled(page, i)) { +- ev = lookup_event_by_page_slot(p, +- page, i); +- set_event_from_interrupt(p, ev); +- } ++ for (i = 0; i < SLOTS_PER_PAGE; i++) ++ if (is_slot_signaled(p, i)) { ++ ev = lookup_event_by_page_slot(p, i); ++ set_event_from_interrupt(p, ev); ++ } + } + + mutex_unlock(&p->event_mutex); +@@ -906,9 +825,8 @@ int kfd_wait_on_events(struct kfd_process *p, + int kfd_event_mmap(struct kfd_process *p, struct vm_area_struct *vma) + { + +- unsigned int page_index; + unsigned long pfn; +- struct signal_page *page; ++ struct kfd_signal_page *page; + + /* check required size is logical */ + if (get_order(KFD_SIGNAL_EVENT_LIMIT * 8) != +@@ -917,13 +835,10 @@ int kfd_event_mmap(struct kfd_process *p, struct vm_area_struct *vma) + return -EINVAL; + } + +- page_index = vma->vm_pgoff; +- +- page = lookup_signal_page_by_index(p, page_index); ++ page = p->signal_page; + if (!page) { + /* Probably KFD bug, but mmap is user-accessible. */ +- pr_debug("Signal page could not be found for page_index %u\n", +- page_index); ++ pr_debug("Signal page could not be found\n"); + return -EINVAL; + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.h b/drivers/gpu/drm/amd/amdkfd/kfd_events.h +index 96f9122..f85fcee 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.h +@@ -60,7 +60,6 @@ struct kfd_event { + wait_queue_head_t wq; /* List of event waiters. */ + + /* Only for signal events. */ +- struct signal_page *signal_page; + unsigned int signal_slot_index; + uint64_t __user *user_signal_address; + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +index 1ac4db5..4fca10f 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +@@ -719,8 +719,8 @@ struct kfd_process { + struct mutex event_mutex; + /* All events in process hashed by ID, linked on kfd_event.events. */ + DECLARE_HASHTABLE(events, 4); +- /* struct slot_page_header.event_pages */ +- struct list_head signal_event_pages; ++ /* Event page */ ++ struct kfd_signal_page *signal_page; + u32 next_nonsignal_event_id; + size_t signal_event_count; + bool signal_event_limit_reached; +@@ -1060,7 +1060,6 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p, + uint64_t *event_page_offset, uint32_t *event_slot_index, + void *kern_addr); + int kfd_event_destroy(struct kfd_process *p, uint32_t event_id); +-void kfd_free_signal_page_dgpu(struct kfd_process *p, uint64_t handle); + + void kfd_signal_vm_fault_event(struct kfd_dev *dev, unsigned int pasid, + struct kfd_vm_fault_info *info); +-- +2.7.4 + |