1f3a39818SAndrew Lewycky /* 2f3a39818SAndrew Lewycky * Copyright 2014 Advanced Micro Devices, Inc. 3f3a39818SAndrew Lewycky * 4f3a39818SAndrew Lewycky * Permission is hereby granted, free of charge, to any person obtaining a 5f3a39818SAndrew Lewycky * copy of this software and associated documentation files (the "Software"), 6f3a39818SAndrew Lewycky * to deal in the Software without restriction, including without limitation 7f3a39818SAndrew Lewycky * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8f3a39818SAndrew Lewycky * and/or sell copies of the Software, and to permit persons to whom the 9f3a39818SAndrew Lewycky * Software is furnished to do so, subject to the following conditions: 10f3a39818SAndrew Lewycky * 11f3a39818SAndrew Lewycky * The above copyright notice and this permission notice shall be included in 12f3a39818SAndrew Lewycky * all copies or substantial portions of the Software. 13f3a39818SAndrew Lewycky * 14f3a39818SAndrew Lewycky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15f3a39818SAndrew Lewycky * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16f3a39818SAndrew Lewycky * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17f3a39818SAndrew Lewycky * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18f3a39818SAndrew Lewycky * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19f3a39818SAndrew Lewycky * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20f3a39818SAndrew Lewycky * OTHER DEALINGS IN THE SOFTWARE. 21f3a39818SAndrew Lewycky */ 22f3a39818SAndrew Lewycky 23f3a39818SAndrew Lewycky #include <linux/mm_types.h> 24f3a39818SAndrew Lewycky #include <linux/slab.h> 25f3a39818SAndrew Lewycky #include <linux/types.h> 263f07c014SIngo Molnar #include <linux/sched/signal.h> 279b56bb11SFelix Kuehling #include <linux/sched/mm.h> 28f3a39818SAndrew Lewycky #include <linux/uaccess.h> 29f3a39818SAndrew Lewycky #include <linux/mman.h> 30f3a39818SAndrew Lewycky #include <linux/memory.h> 31f3a39818SAndrew Lewycky #include "kfd_priv.h" 32f3a39818SAndrew Lewycky #include "kfd_events.h" 3364d1c3a4SFelix Kuehling #include "kfd_iommu.h" 3459d3e8beSAlexey Skidanov #include <linux/device.h> 35f3a39818SAndrew Lewycky 36f3a39818SAndrew Lewycky /* 3774e40716SFelix Kuehling * Wrapper around wait_queue_entry_t 38f3a39818SAndrew Lewycky */ 39f3a39818SAndrew Lewycky struct kfd_event_waiter { 4074e40716SFelix Kuehling wait_queue_entry_t wait; 4174e40716SFelix Kuehling struct kfd_event *event; /* Event to wait for */ 4274e40716SFelix Kuehling bool activated; /* Becomes true when event is signaled */ 43f3a39818SAndrew Lewycky }; 44f3a39818SAndrew Lewycky 45f3a39818SAndrew Lewycky /* 46f3a39818SAndrew Lewycky * Each signal event needs a 64-bit signal slot where the signaler will write 47482f0777SFelix Kuehling * a 1 before sending an interrupt. (This is needed because some interrupts 48f3a39818SAndrew Lewycky * do not contain enough spare data bits to identify an event.) 49482f0777SFelix Kuehling * We get whole pages and map them to the process VA. 50482f0777SFelix Kuehling * Individual signal events use their event_id as slot index. 51f3a39818SAndrew Lewycky */ 5250cb7dd9SFelix Kuehling struct kfd_signal_page { 53f3a39818SAndrew Lewycky uint64_t *kernel_address; 54f3a39818SAndrew Lewycky uint64_t __user *user_address; 550fc8011fSFelix Kuehling bool need_to_free_pages; 56f3a39818SAndrew Lewycky }; 57f3a39818SAndrew Lewycky 58f3a39818SAndrew Lewycky 5950cb7dd9SFelix Kuehling static uint64_t *page_slots(struct kfd_signal_page *page) 60f3a39818SAndrew Lewycky { 61f3a39818SAndrew Lewycky return page->kernel_address; 62f3a39818SAndrew Lewycky } 63f3a39818SAndrew Lewycky 6450cb7dd9SFelix Kuehling static struct kfd_signal_page *allocate_signal_page(struct kfd_process *p) 65f3a39818SAndrew Lewycky { 66f3a39818SAndrew Lewycky void *backing_store; 6750cb7dd9SFelix Kuehling struct kfd_signal_page *page; 68f3a39818SAndrew Lewycky 6950cb7dd9SFelix Kuehling page = kzalloc(sizeof(*page), GFP_KERNEL); 70f3a39818SAndrew Lewycky if (!page) 7150cb7dd9SFelix Kuehling return NULL; 72f3a39818SAndrew Lewycky 7350cb7dd9SFelix Kuehling backing_store = (void *) __get_free_pages(GFP_KERNEL, 74f3a39818SAndrew Lewycky get_order(KFD_SIGNAL_EVENT_LIMIT * 8)); 75f3a39818SAndrew Lewycky if (!backing_store) 76f3a39818SAndrew Lewycky goto fail_alloc_signal_store; 77f3a39818SAndrew Lewycky 7850cb7dd9SFelix Kuehling /* Initialize all events to unsignaled */ 79f3a39818SAndrew Lewycky memset(backing_store, (uint8_t) UNSIGNALED_EVENT_SLOT, 80f3a39818SAndrew Lewycky KFD_SIGNAL_EVENT_LIMIT * 8); 81f3a39818SAndrew Lewycky 82f3a39818SAndrew Lewycky page->kernel_address = backing_store; 830fc8011fSFelix Kuehling page->need_to_free_pages = true; 8479775b62SKent Russell pr_debug("Allocated new event signal page at %p, for process %p\n", 85f3a39818SAndrew Lewycky page, p); 86f3a39818SAndrew Lewycky 8750cb7dd9SFelix Kuehling return page; 88f3a39818SAndrew Lewycky 89f3a39818SAndrew Lewycky fail_alloc_signal_store: 90f3a39818SAndrew Lewycky kfree(page); 9150cb7dd9SFelix Kuehling return NULL; 9250cb7dd9SFelix Kuehling } 9350cb7dd9SFelix Kuehling 94482f0777SFelix Kuehling static int allocate_event_notification_slot(struct kfd_process *p, 95482f0777SFelix Kuehling struct kfd_event *ev) 9650cb7dd9SFelix Kuehling { 97482f0777SFelix Kuehling int id; 98482f0777SFelix Kuehling 9950cb7dd9SFelix Kuehling if (!p->signal_page) { 10050cb7dd9SFelix Kuehling p->signal_page = allocate_signal_page(p); 10150cb7dd9SFelix Kuehling if (!p->signal_page) 102482f0777SFelix Kuehling return -ENOMEM; 103b9a5d0a5SFelix Kuehling /* Oldest user mode expects 256 event slots */ 104b9a5d0a5SFelix Kuehling p->signal_mapped_size = 256*8; 105f3a39818SAndrew Lewycky } 106f3a39818SAndrew Lewycky 107b9a5d0a5SFelix Kuehling /* 108b9a5d0a5SFelix Kuehling * Compatibility with old user mode: Only use signal slots 109b9a5d0a5SFelix Kuehling * user mode has mapped, may be less than 110b9a5d0a5SFelix Kuehling * KFD_SIGNAL_EVENT_LIMIT. This also allows future increase 111b9a5d0a5SFelix Kuehling * of the event limit without breaking user mode. 112b9a5d0a5SFelix Kuehling */ 113b9a5d0a5SFelix Kuehling id = idr_alloc(&p->event_idr, ev, 0, p->signal_mapped_size / 8, 114482f0777SFelix Kuehling GFP_KERNEL); 115482f0777SFelix Kuehling if (id < 0) 116482f0777SFelix Kuehling return id; 117f3a39818SAndrew Lewycky 118482f0777SFelix Kuehling ev->event_id = id; 119482f0777SFelix Kuehling page_slots(p->signal_page)[id] = UNSIGNALED_EVENT_SLOT; 120f3a39818SAndrew Lewycky 121482f0777SFelix Kuehling return 0; 122f3a39818SAndrew Lewycky } 123f3a39818SAndrew Lewycky 124f3a39818SAndrew Lewycky /* 125f3a39818SAndrew Lewycky * Assumes that p->event_mutex is held and of course that p is not going 126f3a39818SAndrew Lewycky * away (current or locked). 127f3a39818SAndrew Lewycky */ 128f3a39818SAndrew Lewycky static struct kfd_event *lookup_event_by_id(struct kfd_process *p, uint32_t id) 129f3a39818SAndrew Lewycky { 130482f0777SFelix Kuehling return idr_find(&p->event_idr, id); 131f3a39818SAndrew Lewycky } 132f3a39818SAndrew Lewycky 1333f04f961SFelix Kuehling /** 1343f04f961SFelix Kuehling * lookup_signaled_event_by_partial_id - Lookup signaled event from partial ID 1353f04f961SFelix Kuehling * @p: Pointer to struct kfd_process 1363f04f961SFelix Kuehling * @id: ID to look up 1373f04f961SFelix Kuehling * @bits: Number of valid bits in @id 1383f04f961SFelix Kuehling * 1393f04f961SFelix Kuehling * Finds the first signaled event with a matching partial ID. If no 1403f04f961SFelix Kuehling * matching signaled event is found, returns NULL. In that case the 1413f04f961SFelix Kuehling * caller should assume that the partial ID is invalid and do an 1423f04f961SFelix Kuehling * exhaustive search of all siglaned events. 1433f04f961SFelix Kuehling * 1443f04f961SFelix Kuehling * If multiple events with the same partial ID signal at the same 1453f04f961SFelix Kuehling * time, they will be found one interrupt at a time, not necessarily 1463f04f961SFelix Kuehling * in the same order the interrupts occurred. As long as the number of 1473f04f961SFelix Kuehling * interrupts is correct, all signaled events will be seen by the 1483f04f961SFelix Kuehling * driver. 1493f04f961SFelix Kuehling */ 1503f04f961SFelix Kuehling static struct kfd_event *lookup_signaled_event_by_partial_id( 1513f04f961SFelix Kuehling struct kfd_process *p, uint32_t id, uint32_t bits) 1523f04f961SFelix Kuehling { 1533f04f961SFelix Kuehling struct kfd_event *ev; 1543f04f961SFelix Kuehling 1553f04f961SFelix Kuehling if (!p->signal_page || id >= KFD_SIGNAL_EVENT_LIMIT) 1563f04f961SFelix Kuehling return NULL; 1573f04f961SFelix Kuehling 1583f04f961SFelix Kuehling /* Fast path for the common case that @id is not a partial ID 1593f04f961SFelix Kuehling * and we only need a single lookup. 1603f04f961SFelix Kuehling */ 1613f04f961SFelix Kuehling if (bits > 31 || (1U << bits) >= KFD_SIGNAL_EVENT_LIMIT) { 1623f04f961SFelix Kuehling if (page_slots(p->signal_page)[id] == UNSIGNALED_EVENT_SLOT) 1633f04f961SFelix Kuehling return NULL; 1643f04f961SFelix Kuehling 1653f04f961SFelix Kuehling return idr_find(&p->event_idr, id); 1663f04f961SFelix Kuehling } 1673f04f961SFelix Kuehling 1683f04f961SFelix Kuehling /* General case for partial IDs: Iterate over all matching IDs 1693f04f961SFelix Kuehling * and find the first one that has signaled. 1703f04f961SFelix Kuehling */ 1713f04f961SFelix Kuehling for (ev = NULL; id < KFD_SIGNAL_EVENT_LIMIT && !ev; id += 1U << bits) { 1723f04f961SFelix Kuehling if (page_slots(p->signal_page)[id] == UNSIGNALED_EVENT_SLOT) 1733f04f961SFelix Kuehling continue; 1743f04f961SFelix Kuehling 1753f04f961SFelix Kuehling ev = idr_find(&p->event_idr, id); 1763f04f961SFelix Kuehling } 1773f04f961SFelix Kuehling 1783f04f961SFelix Kuehling return ev; 1793f04f961SFelix Kuehling } 1803f04f961SFelix Kuehling 181f3a39818SAndrew Lewycky static int create_signal_event(struct file *devkfd, 182f3a39818SAndrew Lewycky struct kfd_process *p, 183f3a39818SAndrew Lewycky struct kfd_event *ev) 184f3a39818SAndrew Lewycky { 185482f0777SFelix Kuehling int ret; 186482f0777SFelix Kuehling 187b9a5d0a5SFelix Kuehling if (p->signal_mapped_size && 188b9a5d0a5SFelix Kuehling p->signal_event_count == p->signal_mapped_size / 8) { 189c986169fSFelix Kuehling if (!p->signal_event_limit_reached) { 19079775b62SKent Russell pr_warn("Signal event wasn't created because limit was reached\n"); 191c986169fSFelix Kuehling p->signal_event_limit_reached = true; 192c986169fSFelix Kuehling } 193482f0777SFelix Kuehling return -ENOSPC; 194f3a39818SAndrew Lewycky } 195f3a39818SAndrew Lewycky 196482f0777SFelix Kuehling ret = allocate_event_notification_slot(p, ev); 197482f0777SFelix Kuehling if (ret) { 19879775b62SKent Russell pr_warn("Signal event wasn't created because out of kernel memory\n"); 199482f0777SFelix Kuehling return ret; 200f3a39818SAndrew Lewycky } 201f3a39818SAndrew Lewycky 202f3a39818SAndrew Lewycky p->signal_event_count++; 203f3a39818SAndrew Lewycky 204482f0777SFelix Kuehling ev->user_signal_address = &p->signal_page->user_address[ev->event_id]; 20579775b62SKent Russell pr_debug("Signal event number %zu created with id %d, address %p\n", 2066235e15eSOded Gabbay p->signal_event_count, ev->event_id, 2076235e15eSOded Gabbay ev->user_signal_address); 2086235e15eSOded Gabbay 209f3a39818SAndrew Lewycky return 0; 210f3a39818SAndrew Lewycky } 211f3a39818SAndrew Lewycky 212f3a39818SAndrew Lewycky static int create_other_event(struct kfd_process *p, struct kfd_event *ev) 213f3a39818SAndrew Lewycky { 214482f0777SFelix Kuehling /* Cast KFD_LAST_NONSIGNAL_EVENT to uint32_t. This allows an 215482f0777SFelix Kuehling * intentional integer overflow to -1 without a compiler 216482f0777SFelix Kuehling * warning. idr_alloc treats a negative value as "maximum 217482f0777SFelix Kuehling * signed integer". 218482f0777SFelix Kuehling */ 219482f0777SFelix Kuehling int id = idr_alloc(&p->event_idr, ev, KFD_FIRST_NONSIGNAL_EVENT_ID, 220482f0777SFelix Kuehling (uint32_t)KFD_LAST_NONSIGNAL_EVENT_ID + 1, 221482f0777SFelix Kuehling GFP_KERNEL); 222482f0777SFelix Kuehling 223482f0777SFelix Kuehling if (id < 0) 224482f0777SFelix Kuehling return id; 225482f0777SFelix Kuehling ev->event_id = id; 226f3a39818SAndrew Lewycky 227f3a39818SAndrew Lewycky return 0; 228f3a39818SAndrew Lewycky } 229f3a39818SAndrew Lewycky 230f3a39818SAndrew Lewycky void kfd_event_init_process(struct kfd_process *p) 231f3a39818SAndrew Lewycky { 232f3a39818SAndrew Lewycky mutex_init(&p->event_mutex); 233482f0777SFelix Kuehling idr_init(&p->event_idr); 23450cb7dd9SFelix Kuehling p->signal_page = NULL; 235f3a39818SAndrew Lewycky p->signal_event_count = 0; 236f3a39818SAndrew Lewycky } 237f3a39818SAndrew Lewycky 238f3a39818SAndrew Lewycky static void destroy_event(struct kfd_process *p, struct kfd_event *ev) 239f3a39818SAndrew Lewycky { 24074e40716SFelix Kuehling struct kfd_event_waiter *waiter; 241fe528c13SFelix Kuehling 24274e40716SFelix Kuehling /* Wake up pending waiters. They will return failure */ 24374e40716SFelix Kuehling list_for_each_entry(waiter, &ev->wq.head, wait.entry) 244fe528c13SFelix Kuehling waiter->event = NULL; 24574e40716SFelix Kuehling wake_up_all(&ev->wq); 246fe528c13SFelix Kuehling 247482f0777SFelix Kuehling if (ev->type == KFD_EVENT_TYPE_SIGNAL || 248482f0777SFelix Kuehling ev->type == KFD_EVENT_TYPE_DEBUG) 249f3a39818SAndrew Lewycky p->signal_event_count--; 250f3a39818SAndrew Lewycky 251482f0777SFelix Kuehling idr_remove(&p->event_idr, ev->event_id); 252f3a39818SAndrew Lewycky kfree(ev); 253f3a39818SAndrew Lewycky } 254f3a39818SAndrew Lewycky 255f3a39818SAndrew Lewycky static void destroy_events(struct kfd_process *p) 256f3a39818SAndrew Lewycky { 257f3a39818SAndrew Lewycky struct kfd_event *ev; 258482f0777SFelix Kuehling uint32_t id; 259f3a39818SAndrew Lewycky 260482f0777SFelix Kuehling idr_for_each_entry(&p->event_idr, ev, id) 261f3a39818SAndrew Lewycky destroy_event(p, ev); 262482f0777SFelix Kuehling idr_destroy(&p->event_idr); 263f3a39818SAndrew Lewycky } 264f3a39818SAndrew Lewycky 265f3a39818SAndrew Lewycky /* 266f3a39818SAndrew Lewycky * We assume that the process is being destroyed and there is no need to 267f3a39818SAndrew Lewycky * unmap the pages or keep bookkeeping data in order. 268f3a39818SAndrew Lewycky */ 26950cb7dd9SFelix Kuehling static void shutdown_signal_page(struct kfd_process *p) 270f3a39818SAndrew Lewycky { 27150cb7dd9SFelix Kuehling struct kfd_signal_page *page = p->signal_page; 272f3a39818SAndrew Lewycky 27350cb7dd9SFelix Kuehling if (page) { 2740fc8011fSFelix Kuehling if (page->need_to_free_pages) 275f3a39818SAndrew Lewycky free_pages((unsigned long)page->kernel_address, 276f3a39818SAndrew Lewycky get_order(KFD_SIGNAL_EVENT_LIMIT * 8)); 277f3a39818SAndrew Lewycky kfree(page); 278f3a39818SAndrew Lewycky } 279f3a39818SAndrew Lewycky } 280f3a39818SAndrew Lewycky 281f3a39818SAndrew Lewycky void kfd_event_free_process(struct kfd_process *p) 282f3a39818SAndrew Lewycky { 283f3a39818SAndrew Lewycky destroy_events(p); 28450cb7dd9SFelix Kuehling shutdown_signal_page(p); 285f3a39818SAndrew Lewycky } 286f3a39818SAndrew Lewycky 287f3a39818SAndrew Lewycky static bool event_can_be_gpu_signaled(const struct kfd_event *ev) 288f3a39818SAndrew Lewycky { 289f3a39818SAndrew Lewycky return ev->type == KFD_EVENT_TYPE_SIGNAL || 290f3a39818SAndrew Lewycky ev->type == KFD_EVENT_TYPE_DEBUG; 291f3a39818SAndrew Lewycky } 292f3a39818SAndrew Lewycky 293f3a39818SAndrew Lewycky static bool event_can_be_cpu_signaled(const struct kfd_event *ev) 294f3a39818SAndrew Lewycky { 295f3a39818SAndrew Lewycky return ev->type == KFD_EVENT_TYPE_SIGNAL; 296f3a39818SAndrew Lewycky } 297f3a39818SAndrew Lewycky 2980fc8011fSFelix Kuehling int kfd_event_page_set(struct kfd_process *p, void *kernel_address, 2990fc8011fSFelix Kuehling uint64_t size) 3000fc8011fSFelix Kuehling { 3010fc8011fSFelix Kuehling struct kfd_signal_page *page; 3020fc8011fSFelix Kuehling 3030fc8011fSFelix Kuehling if (p->signal_page) 3040fc8011fSFelix Kuehling return -EBUSY; 3050fc8011fSFelix Kuehling 3060fc8011fSFelix Kuehling page = kzalloc(sizeof(*page), GFP_KERNEL); 3070fc8011fSFelix Kuehling if (!page) 3080fc8011fSFelix Kuehling return -ENOMEM; 3090fc8011fSFelix Kuehling 3100fc8011fSFelix Kuehling /* Initialize all events to unsignaled */ 3110fc8011fSFelix Kuehling memset(kernel_address, (uint8_t) UNSIGNALED_EVENT_SLOT, 3120fc8011fSFelix Kuehling KFD_SIGNAL_EVENT_LIMIT * 8); 3130fc8011fSFelix Kuehling 3140fc8011fSFelix Kuehling page->kernel_address = kernel_address; 3150fc8011fSFelix Kuehling 3160fc8011fSFelix Kuehling p->signal_page = page; 3170fc8011fSFelix Kuehling p->signal_mapped_size = size; 3180fc8011fSFelix Kuehling 3190fc8011fSFelix Kuehling return 0; 3200fc8011fSFelix Kuehling } 3210fc8011fSFelix Kuehling 322f3a39818SAndrew Lewycky int kfd_event_create(struct file *devkfd, struct kfd_process *p, 323f3a39818SAndrew Lewycky uint32_t event_type, bool auto_reset, uint32_t node_id, 324f3a39818SAndrew Lewycky uint32_t *event_id, uint32_t *event_trigger_data, 325f3a39818SAndrew Lewycky uint64_t *event_page_offset, uint32_t *event_slot_index) 326f3a39818SAndrew Lewycky { 327f3a39818SAndrew Lewycky int ret = 0; 328f3a39818SAndrew Lewycky struct kfd_event *ev = kzalloc(sizeof(*ev), GFP_KERNEL); 329f3a39818SAndrew Lewycky 330f3a39818SAndrew Lewycky if (!ev) 331f3a39818SAndrew Lewycky return -ENOMEM; 332f3a39818SAndrew Lewycky 333f3a39818SAndrew Lewycky ev->type = event_type; 334f3a39818SAndrew Lewycky ev->auto_reset = auto_reset; 335f3a39818SAndrew Lewycky ev->signaled = false; 336f3a39818SAndrew Lewycky 33774e40716SFelix Kuehling init_waitqueue_head(&ev->wq); 338f3a39818SAndrew Lewycky 339f3a39818SAndrew Lewycky *event_page_offset = 0; 340f3a39818SAndrew Lewycky 341f3a39818SAndrew Lewycky mutex_lock(&p->event_mutex); 342f3a39818SAndrew Lewycky 343f3a39818SAndrew Lewycky switch (event_type) { 344f3a39818SAndrew Lewycky case KFD_EVENT_TYPE_SIGNAL: 345f3a39818SAndrew Lewycky case KFD_EVENT_TYPE_DEBUG: 346f3a39818SAndrew Lewycky ret = create_signal_event(devkfd, p, ev); 347f3a39818SAndrew Lewycky if (!ret) { 348df03ef93SHarish Kasiviswanathan *event_page_offset = KFD_MMAP_TYPE_EVENTS; 349f3a39818SAndrew Lewycky *event_page_offset <<= PAGE_SHIFT; 350482f0777SFelix Kuehling *event_slot_index = ev->event_id; 351f3a39818SAndrew Lewycky } 352f3a39818SAndrew Lewycky break; 353f3a39818SAndrew Lewycky default: 354f3a39818SAndrew Lewycky ret = create_other_event(p, ev); 355f3a39818SAndrew Lewycky break; 356f3a39818SAndrew Lewycky } 357f3a39818SAndrew Lewycky 358f3a39818SAndrew Lewycky if (!ret) { 359f3a39818SAndrew Lewycky *event_id = ev->event_id; 360f3a39818SAndrew Lewycky *event_trigger_data = ev->event_id; 361f3a39818SAndrew Lewycky } else { 362f3a39818SAndrew Lewycky kfree(ev); 363f3a39818SAndrew Lewycky } 364f3a39818SAndrew Lewycky 365f3a39818SAndrew Lewycky mutex_unlock(&p->event_mutex); 366f3a39818SAndrew Lewycky 367f3a39818SAndrew Lewycky return ret; 368f3a39818SAndrew Lewycky } 369f3a39818SAndrew Lewycky 370f3a39818SAndrew Lewycky /* Assumes that p is current. */ 371f3a39818SAndrew Lewycky int kfd_event_destroy(struct kfd_process *p, uint32_t event_id) 372f3a39818SAndrew Lewycky { 373f3a39818SAndrew Lewycky struct kfd_event *ev; 374f3a39818SAndrew Lewycky int ret = 0; 375f3a39818SAndrew Lewycky 376f3a39818SAndrew Lewycky mutex_lock(&p->event_mutex); 377f3a39818SAndrew Lewycky 378f3a39818SAndrew Lewycky ev = lookup_event_by_id(p, event_id); 379f3a39818SAndrew Lewycky 380f3a39818SAndrew Lewycky if (ev) 381f3a39818SAndrew Lewycky destroy_event(p, ev); 382f3a39818SAndrew Lewycky else 383f3a39818SAndrew Lewycky ret = -EINVAL; 384f3a39818SAndrew Lewycky 385f3a39818SAndrew Lewycky mutex_unlock(&p->event_mutex); 386f3a39818SAndrew Lewycky return ret; 387f3a39818SAndrew Lewycky } 388f3a39818SAndrew Lewycky 389f3a39818SAndrew Lewycky static void set_event(struct kfd_event *ev) 390f3a39818SAndrew Lewycky { 391f3a39818SAndrew Lewycky struct kfd_event_waiter *waiter; 392f3a39818SAndrew Lewycky 39374e40716SFelix Kuehling /* Auto reset if the list is non-empty and we're waking 39474e40716SFelix Kuehling * someone. waitqueue_active is safe here because we're 39574e40716SFelix Kuehling * protected by the p->event_mutex, which is also held when 39674e40716SFelix Kuehling * updating the wait queues in kfd_wait_on_events. 39774e40716SFelix Kuehling */ 39874e40716SFelix Kuehling ev->signaled = !ev->auto_reset || !waitqueue_active(&ev->wq); 399f3a39818SAndrew Lewycky 40074e40716SFelix Kuehling list_for_each_entry(waiter, &ev->wq.head, wait.entry) 401f3a39818SAndrew Lewycky waiter->activated = true; 402f3a39818SAndrew Lewycky 40374e40716SFelix Kuehling wake_up_all(&ev->wq); 404f3a39818SAndrew Lewycky } 405f3a39818SAndrew Lewycky 406f3a39818SAndrew Lewycky /* Assumes that p is current. */ 407f3a39818SAndrew Lewycky int kfd_set_event(struct kfd_process *p, uint32_t event_id) 408f3a39818SAndrew Lewycky { 409f3a39818SAndrew Lewycky int ret = 0; 410f3a39818SAndrew Lewycky struct kfd_event *ev; 411f3a39818SAndrew Lewycky 412f3a39818SAndrew Lewycky mutex_lock(&p->event_mutex); 413f3a39818SAndrew Lewycky 414f3a39818SAndrew Lewycky ev = lookup_event_by_id(p, event_id); 415f3a39818SAndrew Lewycky 416f3a39818SAndrew Lewycky if (ev && event_can_be_cpu_signaled(ev)) 417f3a39818SAndrew Lewycky set_event(ev); 418f3a39818SAndrew Lewycky else 419f3a39818SAndrew Lewycky ret = -EINVAL; 420f3a39818SAndrew Lewycky 421f3a39818SAndrew Lewycky mutex_unlock(&p->event_mutex); 422f3a39818SAndrew Lewycky return ret; 423f3a39818SAndrew Lewycky } 424f3a39818SAndrew Lewycky 425f3a39818SAndrew Lewycky static void reset_event(struct kfd_event *ev) 426f3a39818SAndrew Lewycky { 427f3a39818SAndrew Lewycky ev->signaled = false; 428f3a39818SAndrew Lewycky } 429f3a39818SAndrew Lewycky 430f3a39818SAndrew Lewycky /* Assumes that p is current. */ 431f3a39818SAndrew Lewycky int kfd_reset_event(struct kfd_process *p, uint32_t event_id) 432f3a39818SAndrew Lewycky { 433f3a39818SAndrew Lewycky int ret = 0; 434f3a39818SAndrew Lewycky struct kfd_event *ev; 435f3a39818SAndrew Lewycky 436f3a39818SAndrew Lewycky mutex_lock(&p->event_mutex); 437f3a39818SAndrew Lewycky 438f3a39818SAndrew Lewycky ev = lookup_event_by_id(p, event_id); 439f3a39818SAndrew Lewycky 440f3a39818SAndrew Lewycky if (ev && event_can_be_cpu_signaled(ev)) 441f3a39818SAndrew Lewycky reset_event(ev); 442f3a39818SAndrew Lewycky else 443f3a39818SAndrew Lewycky ret = -EINVAL; 444f3a39818SAndrew Lewycky 445f3a39818SAndrew Lewycky mutex_unlock(&p->event_mutex); 446f3a39818SAndrew Lewycky return ret; 447f3a39818SAndrew Lewycky 448f3a39818SAndrew Lewycky } 449f3a39818SAndrew Lewycky 450f3a39818SAndrew Lewycky static void acknowledge_signal(struct kfd_process *p, struct kfd_event *ev) 451f3a39818SAndrew Lewycky { 452482f0777SFelix Kuehling page_slots(p->signal_page)[ev->event_id] = UNSIGNALED_EVENT_SLOT; 453f3a39818SAndrew Lewycky } 454f3a39818SAndrew Lewycky 455f3a39818SAndrew Lewycky static void set_event_from_interrupt(struct kfd_process *p, 456f3a39818SAndrew Lewycky struct kfd_event *ev) 457f3a39818SAndrew Lewycky { 458f3a39818SAndrew Lewycky if (ev && event_can_be_gpu_signaled(ev)) { 459f3a39818SAndrew Lewycky acknowledge_signal(p, ev); 460f3a39818SAndrew Lewycky set_event(ev); 461f3a39818SAndrew Lewycky } 462f3a39818SAndrew Lewycky } 463f3a39818SAndrew Lewycky 464f3a39818SAndrew Lewycky void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id, 465f3a39818SAndrew Lewycky uint32_t valid_id_bits) 466f3a39818SAndrew Lewycky { 4673f04f961SFelix Kuehling struct kfd_event *ev = NULL; 468f3a39818SAndrew Lewycky 469f3a39818SAndrew Lewycky /* 470f3a39818SAndrew Lewycky * Because we are called from arbitrary context (workqueue) as opposed 471f3a39818SAndrew Lewycky * to process context, kfd_process could attempt to exit while we are 472abb208a8SFelix Kuehling * running so the lookup function increments the process ref count. 473f3a39818SAndrew Lewycky */ 474f3a39818SAndrew Lewycky struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); 475f3a39818SAndrew Lewycky 476f3a39818SAndrew Lewycky if (!p) 477f3a39818SAndrew Lewycky return; /* Presumably process exited. */ 478f3a39818SAndrew Lewycky 479f3a39818SAndrew Lewycky mutex_lock(&p->event_mutex); 480f3a39818SAndrew Lewycky 4813f04f961SFelix Kuehling if (valid_id_bits) 4823f04f961SFelix Kuehling ev = lookup_signaled_event_by_partial_id(p, partial_id, 4833f04f961SFelix Kuehling valid_id_bits); 4843f04f961SFelix Kuehling if (ev) { 485f3a39818SAndrew Lewycky set_event_from_interrupt(p, ev); 48650cb7dd9SFelix Kuehling } else if (p->signal_page) { 487f3a39818SAndrew Lewycky /* 4883f04f961SFelix Kuehling * Partial ID lookup failed. Assume that the event ID 4893f04f961SFelix Kuehling * in the interrupt payload was invalid and do an 4903f04f961SFelix Kuehling * exhaustive search of signaled events. 491f3a39818SAndrew Lewycky */ 492482f0777SFelix Kuehling uint64_t *slots = page_slots(p->signal_page); 493482f0777SFelix Kuehling uint32_t id; 494f3a39818SAndrew Lewycky 4953f04f961SFelix Kuehling if (valid_id_bits) 4963f04f961SFelix Kuehling pr_debug_ratelimited("Partial ID invalid: %u (%u valid bits)\n", 4973f04f961SFelix Kuehling partial_id, valid_id_bits); 4983f04f961SFelix Kuehling 499eeb27b7eSFelix Kuehling if (p->signal_event_count < KFD_SIGNAL_EVENT_LIMIT / 64) { 500482f0777SFelix Kuehling /* With relatively few events, it's faster to 501482f0777SFelix Kuehling * iterate over the event IDR 502482f0777SFelix Kuehling */ 503482f0777SFelix Kuehling idr_for_each_entry(&p->event_idr, ev, id) { 504482f0777SFelix Kuehling if (id >= KFD_SIGNAL_EVENT_LIMIT) 505482f0777SFelix Kuehling break; 506482f0777SFelix Kuehling 507482f0777SFelix Kuehling if (slots[id] != UNSIGNALED_EVENT_SLOT) 508f3a39818SAndrew Lewycky set_event_from_interrupt(p, ev); 509f3a39818SAndrew Lewycky } 510482f0777SFelix Kuehling } else { 511482f0777SFelix Kuehling /* With relatively many events, it's faster to 512482f0777SFelix Kuehling * iterate over the signal slots and lookup 513482f0777SFelix Kuehling * only signaled events from the IDR. 514482f0777SFelix Kuehling */ 515482f0777SFelix Kuehling for (id = 0; id < KFD_SIGNAL_EVENT_LIMIT; id++) 516482f0777SFelix Kuehling if (slots[id] != UNSIGNALED_EVENT_SLOT) { 517482f0777SFelix Kuehling ev = lookup_event_by_id(p, id); 518482f0777SFelix Kuehling set_event_from_interrupt(p, ev); 519482f0777SFelix Kuehling } 520482f0777SFelix Kuehling } 521f3a39818SAndrew Lewycky } 522f3a39818SAndrew Lewycky 523f3a39818SAndrew Lewycky mutex_unlock(&p->event_mutex); 524abb208a8SFelix Kuehling kfd_unref_process(p); 525f3a39818SAndrew Lewycky } 526f3a39818SAndrew Lewycky 527f3a39818SAndrew Lewycky static struct kfd_event_waiter *alloc_event_waiters(uint32_t num_events) 528f3a39818SAndrew Lewycky { 529f3a39818SAndrew Lewycky struct kfd_event_waiter *event_waiters; 530f3a39818SAndrew Lewycky uint32_t i; 531f3a39818SAndrew Lewycky 532f3a39818SAndrew Lewycky event_waiters = kmalloc_array(num_events, 533f3a39818SAndrew Lewycky sizeof(struct kfd_event_waiter), 534f3a39818SAndrew Lewycky GFP_KERNEL); 535f3a39818SAndrew Lewycky 536f3a39818SAndrew Lewycky for (i = 0; (event_waiters) && (i < num_events) ; i++) { 53774e40716SFelix Kuehling init_wait(&event_waiters[i].wait); 538f3a39818SAndrew Lewycky event_waiters[i].activated = false; 539f3a39818SAndrew Lewycky } 540f3a39818SAndrew Lewycky 541f3a39818SAndrew Lewycky return event_waiters; 542f3a39818SAndrew Lewycky } 543f3a39818SAndrew Lewycky 5441f9d09beSSean Keely static int init_event_waiter_get_status(struct kfd_process *p, 545f3a39818SAndrew Lewycky struct kfd_event_waiter *waiter, 546ebf947feSFelix Kuehling uint32_t event_id) 547f3a39818SAndrew Lewycky { 548f3a39818SAndrew Lewycky struct kfd_event *ev = lookup_event_by_id(p, event_id); 549f3a39818SAndrew Lewycky 550f3a39818SAndrew Lewycky if (!ev) 551f3a39818SAndrew Lewycky return -EINVAL; 552f3a39818SAndrew Lewycky 55359d3e8beSAlexey Skidanov waiter->event = ev; 554f3a39818SAndrew Lewycky waiter->activated = ev->signaled; 555f3a39818SAndrew Lewycky ev->signaled = ev->signaled && !ev->auto_reset; 556f3a39818SAndrew Lewycky 557f3a39818SAndrew Lewycky return 0; 558f3a39818SAndrew Lewycky } 559f3a39818SAndrew Lewycky 5601f9d09beSSean Keely static void init_event_waiter_add_to_waitlist(struct kfd_event_waiter *waiter) 5611f9d09beSSean Keely { 5621f9d09beSSean Keely struct kfd_event *ev = waiter->event; 5631f9d09beSSean Keely 5641f9d09beSSean Keely /* Only add to the wait list if we actually need to 5651f9d09beSSean Keely * wait on this event. 5661f9d09beSSean Keely */ 5671f9d09beSSean Keely if (!waiter->activated) 56874e40716SFelix Kuehling add_wait_queue(&ev->wq, &waiter->wait); 5691f9d09beSSean Keely } 5701f9d09beSSean Keely 571fe528c13SFelix Kuehling /* test_event_condition - Test condition of events being waited for 572fe528c13SFelix Kuehling * @all: Return completion only if all events have signaled 573fe528c13SFelix Kuehling * @num_events: Number of events to wait for 574fe528c13SFelix Kuehling * @event_waiters: Array of event waiters, one per event 575fe528c13SFelix Kuehling * 576fe528c13SFelix Kuehling * Returns KFD_IOC_WAIT_RESULT_COMPLETE if all (or one) event(s) have 577fe528c13SFelix Kuehling * signaled. Returns KFD_IOC_WAIT_RESULT_TIMEOUT if no (or not all) 578fe528c13SFelix Kuehling * events have signaled. Returns KFD_IOC_WAIT_RESULT_FAIL if any of 579fe528c13SFelix Kuehling * the events have been destroyed. 580fe528c13SFelix Kuehling */ 581fe528c13SFelix Kuehling static uint32_t test_event_condition(bool all, uint32_t num_events, 582f3a39818SAndrew Lewycky struct kfd_event_waiter *event_waiters) 583f3a39818SAndrew Lewycky { 584f3a39818SAndrew Lewycky uint32_t i; 585f3a39818SAndrew Lewycky uint32_t activated_count = 0; 586f3a39818SAndrew Lewycky 587f3a39818SAndrew Lewycky for (i = 0; i < num_events; i++) { 588fe528c13SFelix Kuehling if (!event_waiters[i].event) 589fe528c13SFelix Kuehling return KFD_IOC_WAIT_RESULT_FAIL; 590fe528c13SFelix Kuehling 591f3a39818SAndrew Lewycky if (event_waiters[i].activated) { 592f3a39818SAndrew Lewycky if (!all) 593fe528c13SFelix Kuehling return KFD_IOC_WAIT_RESULT_COMPLETE; 594f3a39818SAndrew Lewycky 595f3a39818SAndrew Lewycky activated_count++; 596f3a39818SAndrew Lewycky } 597f3a39818SAndrew Lewycky } 598f3a39818SAndrew Lewycky 599fe528c13SFelix Kuehling return activated_count == num_events ? 600fe528c13SFelix Kuehling KFD_IOC_WAIT_RESULT_COMPLETE : KFD_IOC_WAIT_RESULT_TIMEOUT; 601f3a39818SAndrew Lewycky } 602f3a39818SAndrew Lewycky 60359d3e8beSAlexey Skidanov /* 60459d3e8beSAlexey Skidanov * Copy event specific data, if defined. 60559d3e8beSAlexey Skidanov * Currently only memory exception events have additional data to copy to user 60659d3e8beSAlexey Skidanov */ 607fdf0c833SFelix Kuehling static int copy_signaled_event_data(uint32_t num_events, 60859d3e8beSAlexey Skidanov struct kfd_event_waiter *event_waiters, 60959d3e8beSAlexey Skidanov struct kfd_event_data __user *data) 61059d3e8beSAlexey Skidanov { 61159d3e8beSAlexey Skidanov struct kfd_hsa_memory_exception_data *src; 61259d3e8beSAlexey Skidanov struct kfd_hsa_memory_exception_data __user *dst; 61359d3e8beSAlexey Skidanov struct kfd_event_waiter *waiter; 61459d3e8beSAlexey Skidanov struct kfd_event *event; 61559d3e8beSAlexey Skidanov uint32_t i; 61659d3e8beSAlexey Skidanov 61759d3e8beSAlexey Skidanov for (i = 0; i < num_events; i++) { 61859d3e8beSAlexey Skidanov waiter = &event_waiters[i]; 61959d3e8beSAlexey Skidanov event = waiter->event; 62059d3e8beSAlexey Skidanov if (waiter->activated && event->type == KFD_EVENT_TYPE_MEMORY) { 621ebf947feSFelix Kuehling dst = &data[i].memory_exception_data; 62259d3e8beSAlexey Skidanov src = &event->memory_exception_data; 62359d3e8beSAlexey Skidanov if (copy_to_user(dst, src, 62459d3e8beSAlexey Skidanov sizeof(struct kfd_hsa_memory_exception_data))) 625fdf0c833SFelix Kuehling return -EFAULT; 62659d3e8beSAlexey Skidanov } 62759d3e8beSAlexey Skidanov } 62859d3e8beSAlexey Skidanov 629fdf0c833SFelix Kuehling return 0; 63059d3e8beSAlexey Skidanov 63159d3e8beSAlexey Skidanov } 63259d3e8beSAlexey Skidanov 63359d3e8beSAlexey Skidanov 63459d3e8beSAlexey Skidanov 635f3a39818SAndrew Lewycky static long user_timeout_to_jiffies(uint32_t user_timeout_ms) 636f3a39818SAndrew Lewycky { 637f3a39818SAndrew Lewycky if (user_timeout_ms == KFD_EVENT_TIMEOUT_IMMEDIATE) 638f3a39818SAndrew Lewycky return 0; 639f3a39818SAndrew Lewycky 640f3a39818SAndrew Lewycky if (user_timeout_ms == KFD_EVENT_TIMEOUT_INFINITE) 641f3a39818SAndrew Lewycky return MAX_SCHEDULE_TIMEOUT; 642f3a39818SAndrew Lewycky 643f3a39818SAndrew Lewycky /* 644f3a39818SAndrew Lewycky * msecs_to_jiffies interprets all values above 2^31-1 as infinite, 645f3a39818SAndrew Lewycky * but we consider them finite. 646f3a39818SAndrew Lewycky * This hack is wrong, but nobody is likely to notice. 647f3a39818SAndrew Lewycky */ 648f3a39818SAndrew Lewycky user_timeout_ms = min_t(uint32_t, user_timeout_ms, 0x7FFFFFFF); 649f3a39818SAndrew Lewycky 650f3a39818SAndrew Lewycky return msecs_to_jiffies(user_timeout_ms) + 1; 651f3a39818SAndrew Lewycky } 652f3a39818SAndrew Lewycky 653f3a39818SAndrew Lewycky static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters) 654f3a39818SAndrew Lewycky { 655f3a39818SAndrew Lewycky uint32_t i; 656f3a39818SAndrew Lewycky 657f3a39818SAndrew Lewycky for (i = 0; i < num_events; i++) 65874e40716SFelix Kuehling if (waiters[i].event) 65974e40716SFelix Kuehling remove_wait_queue(&waiters[i].event->wq, 66074e40716SFelix Kuehling &waiters[i].wait); 661f3a39818SAndrew Lewycky 662f3a39818SAndrew Lewycky kfree(waiters); 663f3a39818SAndrew Lewycky } 664f3a39818SAndrew Lewycky 665f3a39818SAndrew Lewycky int kfd_wait_on_events(struct kfd_process *p, 66659d3e8beSAlexey Skidanov uint32_t num_events, void __user *data, 667f3a39818SAndrew Lewycky bool all, uint32_t user_timeout_ms, 668fdf0c833SFelix Kuehling uint32_t *wait_result) 669f3a39818SAndrew Lewycky { 67059d3e8beSAlexey Skidanov struct kfd_event_data __user *events = 67159d3e8beSAlexey Skidanov (struct kfd_event_data __user *) data; 672f3a39818SAndrew Lewycky uint32_t i; 673f3a39818SAndrew Lewycky int ret = 0; 6741f9d09beSSean Keely 675f3a39818SAndrew Lewycky struct kfd_event_waiter *event_waiters = NULL; 676f3a39818SAndrew Lewycky long timeout = user_timeout_to_jiffies(user_timeout_ms); 677f3a39818SAndrew Lewycky 678fdf0c833SFelix Kuehling event_waiters = alloc_event_waiters(num_events); 679fdf0c833SFelix Kuehling if (!event_waiters) { 680fdf0c833SFelix Kuehling ret = -ENOMEM; 681fdf0c833SFelix Kuehling goto out; 682fdf0c833SFelix Kuehling } 683fdf0c833SFelix Kuehling 684f3a39818SAndrew Lewycky mutex_lock(&p->event_mutex); 685f3a39818SAndrew Lewycky 686f3a39818SAndrew Lewycky for (i = 0; i < num_events; i++) { 68759d3e8beSAlexey Skidanov struct kfd_event_data event_data; 688f3a39818SAndrew Lewycky 68959d3e8beSAlexey Skidanov if (copy_from_user(&event_data, &events[i], 6908bf79388SPan Bian sizeof(struct kfd_event_data))) { 6918bf79388SPan Bian ret = -EFAULT; 692fdf0c833SFelix Kuehling goto out_unlock; 6938bf79388SPan Bian } 694f3a39818SAndrew Lewycky 6951f9d09beSSean Keely ret = init_event_waiter_get_status(p, &event_waiters[i], 696ebf947feSFelix Kuehling event_data.event_id); 697f3a39818SAndrew Lewycky if (ret) 698fdf0c833SFelix Kuehling goto out_unlock; 699f3a39818SAndrew Lewycky } 700f3a39818SAndrew Lewycky 7011f9d09beSSean Keely /* Check condition once. */ 702fe528c13SFelix Kuehling *wait_result = test_event_condition(all, num_events, event_waiters); 703fe528c13SFelix Kuehling if (*wait_result == KFD_IOC_WAIT_RESULT_COMPLETE) { 704fdf0c833SFelix Kuehling ret = copy_signaled_event_data(num_events, 705fdf0c833SFelix Kuehling event_waiters, events); 706fdf0c833SFelix Kuehling goto out_unlock; 707fe528c13SFelix Kuehling } else if (WARN_ON(*wait_result == KFD_IOC_WAIT_RESULT_FAIL)) { 708fe528c13SFelix Kuehling /* This should not happen. Events shouldn't be 709fe528c13SFelix Kuehling * destroyed while we're holding the event_mutex 710fe528c13SFelix Kuehling */ 711fe528c13SFelix Kuehling goto out_unlock; 712fe528c13SFelix Kuehling } 713fe528c13SFelix Kuehling 7141f9d09beSSean Keely /* Add to wait lists if we need to wait. */ 7151f9d09beSSean Keely for (i = 0; i < num_events; i++) 7161f9d09beSSean Keely init_event_waiter_add_to_waitlist(&event_waiters[i]); 7171f9d09beSSean Keely 718f3a39818SAndrew Lewycky mutex_unlock(&p->event_mutex); 719f3a39818SAndrew Lewycky 720f3a39818SAndrew Lewycky while (true) { 721f3a39818SAndrew Lewycky if (fatal_signal_pending(current)) { 722f3a39818SAndrew Lewycky ret = -EINTR; 723f3a39818SAndrew Lewycky break; 724f3a39818SAndrew Lewycky } 725f3a39818SAndrew Lewycky 726f3a39818SAndrew Lewycky if (signal_pending(current)) { 727f3a39818SAndrew Lewycky /* 728f3a39818SAndrew Lewycky * This is wrong when a nonzero, non-infinite timeout 729f3a39818SAndrew Lewycky * is specified. We need to use 730f3a39818SAndrew Lewycky * ERESTARTSYS_RESTARTBLOCK, but struct restart_block 731f3a39818SAndrew Lewycky * contains a union with data for each user and it's 732f3a39818SAndrew Lewycky * in generic kernel code that I don't want to 733f3a39818SAndrew Lewycky * touch yet. 734f3a39818SAndrew Lewycky */ 735f3a39818SAndrew Lewycky ret = -ERESTARTSYS; 736f3a39818SAndrew Lewycky break; 737f3a39818SAndrew Lewycky } 738f3a39818SAndrew Lewycky 739d9aeec4cSSean Keely /* Set task state to interruptible sleep before 740d9aeec4cSSean Keely * checking wake-up conditions. A concurrent wake-up 741d9aeec4cSSean Keely * will put the task back into runnable state. In that 742d9aeec4cSSean Keely * case schedule_timeout will not put the task to 743d9aeec4cSSean Keely * sleep and we'll get a chance to re-check the 744d9aeec4cSSean Keely * updated conditions almost immediately. Otherwise, 745d9aeec4cSSean Keely * this race condition would lead to a soft hang or a 746d9aeec4cSSean Keely * very long sleep. 747d9aeec4cSSean Keely */ 748d9aeec4cSSean Keely set_current_state(TASK_INTERRUPTIBLE); 749d9aeec4cSSean Keely 750fe528c13SFelix Kuehling *wait_result = test_event_condition(all, num_events, 751fe528c13SFelix Kuehling event_waiters); 752fe528c13SFelix Kuehling if (*wait_result != KFD_IOC_WAIT_RESULT_TIMEOUT) 753f3a39818SAndrew Lewycky break; 754f3a39818SAndrew Lewycky 755fe528c13SFelix Kuehling if (timeout <= 0) 756f3a39818SAndrew Lewycky break; 757f3a39818SAndrew Lewycky 758d9aeec4cSSean Keely timeout = schedule_timeout(timeout); 759f3a39818SAndrew Lewycky } 760f3a39818SAndrew Lewycky __set_current_state(TASK_RUNNING); 761f3a39818SAndrew Lewycky 762fdf0c833SFelix Kuehling /* copy_signaled_event_data may sleep. So this has to happen 763fdf0c833SFelix Kuehling * after the task state is set back to RUNNING. 764fdf0c833SFelix Kuehling */ 765fdf0c833SFelix Kuehling if (!ret && *wait_result == KFD_IOC_WAIT_RESULT_COMPLETE) 766fdf0c833SFelix Kuehling ret = copy_signaled_event_data(num_events, 767fdf0c833SFelix Kuehling event_waiters, events); 768fdf0c833SFelix Kuehling 769f3a39818SAndrew Lewycky mutex_lock(&p->event_mutex); 770fdf0c833SFelix Kuehling out_unlock: 771f3a39818SAndrew Lewycky free_waiters(num_events, event_waiters); 772f3a39818SAndrew Lewycky mutex_unlock(&p->event_mutex); 773fdf0c833SFelix Kuehling out: 774fdf0c833SFelix Kuehling if (ret) 775fdf0c833SFelix Kuehling *wait_result = KFD_IOC_WAIT_RESULT_FAIL; 776fe528c13SFelix Kuehling else if (*wait_result == KFD_IOC_WAIT_RESULT_FAIL) 777fe528c13SFelix Kuehling ret = -EIO; 778f3a39818SAndrew Lewycky 779f3a39818SAndrew Lewycky return ret; 780f3a39818SAndrew Lewycky } 781f3a39818SAndrew Lewycky 782f3a39818SAndrew Lewycky int kfd_event_mmap(struct kfd_process *p, struct vm_area_struct *vma) 783f3a39818SAndrew Lewycky { 784f3a39818SAndrew Lewycky unsigned long pfn; 78550cb7dd9SFelix Kuehling struct kfd_signal_page *page; 786b9a5d0a5SFelix Kuehling int ret; 787f3a39818SAndrew Lewycky 788b9a5d0a5SFelix Kuehling /* check required size doesn't exceed the allocated size */ 789b9a5d0a5SFelix Kuehling if (get_order(KFD_SIGNAL_EVENT_LIMIT * 8) < 790f3a39818SAndrew Lewycky get_order(vma->vm_end - vma->vm_start)) { 79179775b62SKent Russell pr_err("Event page mmap requested illegal size\n"); 792f3a39818SAndrew Lewycky return -EINVAL; 793f3a39818SAndrew Lewycky } 794f3a39818SAndrew Lewycky 79550cb7dd9SFelix Kuehling page = p->signal_page; 796f3a39818SAndrew Lewycky if (!page) { 797f3a39818SAndrew Lewycky /* Probably KFD bug, but mmap is user-accessible. */ 79850cb7dd9SFelix Kuehling pr_debug("Signal page could not be found\n"); 799f3a39818SAndrew Lewycky return -EINVAL; 800f3a39818SAndrew Lewycky } 801f3a39818SAndrew Lewycky 802f3a39818SAndrew Lewycky pfn = __pa(page->kernel_address); 803f3a39818SAndrew Lewycky pfn >>= PAGE_SHIFT; 804f3a39818SAndrew Lewycky 805f3a39818SAndrew Lewycky vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE 806f3a39818SAndrew Lewycky | VM_DONTDUMP | VM_PFNMAP; 807f3a39818SAndrew Lewycky 80879775b62SKent Russell pr_debug("Mapping signal page\n"); 809f3a39818SAndrew Lewycky pr_debug(" start user address == 0x%08lx\n", vma->vm_start); 810f3a39818SAndrew Lewycky pr_debug(" end user address == 0x%08lx\n", vma->vm_end); 811f3a39818SAndrew Lewycky pr_debug(" pfn == 0x%016lX\n", pfn); 812f3a39818SAndrew Lewycky pr_debug(" vm_flags == 0x%08lX\n", vma->vm_flags); 813f3a39818SAndrew Lewycky pr_debug(" size == 0x%08lX\n", 814f3a39818SAndrew Lewycky vma->vm_end - vma->vm_start); 815f3a39818SAndrew Lewycky 816f3a39818SAndrew Lewycky page->user_address = (uint64_t __user *)vma->vm_start; 817f3a39818SAndrew Lewycky 818f3a39818SAndrew Lewycky /* mapping the page to user process */ 819b9a5d0a5SFelix Kuehling ret = remap_pfn_range(vma, vma->vm_start, pfn, 820f3a39818SAndrew Lewycky vma->vm_end - vma->vm_start, vma->vm_page_prot); 821b9a5d0a5SFelix Kuehling if (!ret) 822b9a5d0a5SFelix Kuehling p->signal_mapped_size = vma->vm_end - vma->vm_start; 823b9a5d0a5SFelix Kuehling 824b9a5d0a5SFelix Kuehling return ret; 825f3a39818SAndrew Lewycky } 82659d3e8beSAlexey Skidanov 82759d3e8beSAlexey Skidanov /* 82859d3e8beSAlexey Skidanov * Assumes that p->event_mutex is held and of course 82959d3e8beSAlexey Skidanov * that p is not going away (current or locked). 83059d3e8beSAlexey Skidanov */ 83159d3e8beSAlexey Skidanov static void lookup_events_by_type_and_signal(struct kfd_process *p, 83259d3e8beSAlexey Skidanov int type, void *event_data) 83359d3e8beSAlexey Skidanov { 83459d3e8beSAlexey Skidanov struct kfd_hsa_memory_exception_data *ev_data; 83559d3e8beSAlexey Skidanov struct kfd_event *ev; 836482f0777SFelix Kuehling uint32_t id; 83759d3e8beSAlexey Skidanov bool send_signal = true; 83859d3e8beSAlexey Skidanov 83959d3e8beSAlexey Skidanov ev_data = (struct kfd_hsa_memory_exception_data *) event_data; 84059d3e8beSAlexey Skidanov 841482f0777SFelix Kuehling id = KFD_FIRST_NONSIGNAL_EVENT_ID; 842482f0777SFelix Kuehling idr_for_each_entry_continue(&p->event_idr, ev, id) 84359d3e8beSAlexey Skidanov if (ev->type == type) { 84459d3e8beSAlexey Skidanov send_signal = false; 84559d3e8beSAlexey Skidanov dev_dbg(kfd_device, 84659d3e8beSAlexey Skidanov "Event found: id %X type %d", 84759d3e8beSAlexey Skidanov ev->event_id, ev->type); 84859d3e8beSAlexey Skidanov set_event(ev); 84959d3e8beSAlexey Skidanov if (ev->type == KFD_EVENT_TYPE_MEMORY && ev_data) 85059d3e8beSAlexey Skidanov ev->memory_exception_data = *ev_data; 85159d3e8beSAlexey Skidanov } 85259d3e8beSAlexey Skidanov 853*101fee63SMoses Reuben if (type == KFD_EVENT_TYPE_MEMORY) { 854*101fee63SMoses Reuben dev_warn(kfd_device, 855*101fee63SMoses Reuben "Sending SIGSEGV to HSA Process with PID %d ", 856*101fee63SMoses Reuben p->lead_thread->pid); 857*101fee63SMoses Reuben send_sig(SIGSEGV, p->lead_thread, 0); 858*101fee63SMoses Reuben } 859*101fee63SMoses Reuben 86059d3e8beSAlexey Skidanov /* Send SIGTERM no event of type "type" has been found*/ 86159d3e8beSAlexey Skidanov if (send_signal) { 86281663016SOded Gabbay if (send_sigterm) { 86359d3e8beSAlexey Skidanov dev_warn(kfd_device, 86459d3e8beSAlexey Skidanov "Sending SIGTERM to HSA Process with PID %d ", 86559d3e8beSAlexey Skidanov p->lead_thread->pid); 86659d3e8beSAlexey Skidanov send_sig(SIGTERM, p->lead_thread, 0); 86781663016SOded Gabbay } else { 86881663016SOded Gabbay dev_err(kfd_device, 86981663016SOded Gabbay "HSA Process (PID %d) got unhandled exception", 87081663016SOded Gabbay p->lead_thread->pid); 87181663016SOded Gabbay } 87259d3e8beSAlexey Skidanov } 87359d3e8beSAlexey Skidanov } 87459d3e8beSAlexey Skidanov 87564d1c3a4SFelix Kuehling #ifdef KFD_SUPPORT_IOMMU_V2 87659d3e8beSAlexey Skidanov void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid, 87759d3e8beSAlexey Skidanov unsigned long address, bool is_write_requested, 87859d3e8beSAlexey Skidanov bool is_execute_requested) 87959d3e8beSAlexey Skidanov { 88059d3e8beSAlexey Skidanov struct kfd_hsa_memory_exception_data memory_exception_data; 88159d3e8beSAlexey Skidanov struct vm_area_struct *vma; 88259d3e8beSAlexey Skidanov 88359d3e8beSAlexey Skidanov /* 88459d3e8beSAlexey Skidanov * Because we are called from arbitrary context (workqueue) as opposed 88559d3e8beSAlexey Skidanov * to process context, kfd_process could attempt to exit while we are 886abb208a8SFelix Kuehling * running so the lookup function increments the process ref count. 88759d3e8beSAlexey Skidanov */ 88859d3e8beSAlexey Skidanov struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); 8899b56bb11SFelix Kuehling struct mm_struct *mm; 89059d3e8beSAlexey Skidanov 89159d3e8beSAlexey Skidanov if (!p) 89259d3e8beSAlexey Skidanov return; /* Presumably process exited. */ 89359d3e8beSAlexey Skidanov 8949b56bb11SFelix Kuehling /* Take a safe reference to the mm_struct, which may otherwise 8959b56bb11SFelix Kuehling * disappear even while the kfd_process is still referenced. 8969b56bb11SFelix Kuehling */ 8979b56bb11SFelix Kuehling mm = get_task_mm(p->lead_thread); 8989b56bb11SFelix Kuehling if (!mm) { 899abb208a8SFelix Kuehling kfd_unref_process(p); 9009b56bb11SFelix Kuehling return; /* Process is exiting */ 9019b56bb11SFelix Kuehling } 9029b56bb11SFelix Kuehling 90359d3e8beSAlexey Skidanov memset(&memory_exception_data, 0, sizeof(memory_exception_data)); 90459d3e8beSAlexey Skidanov 9059b56bb11SFelix Kuehling down_read(&mm->mmap_sem); 9069b56bb11SFelix Kuehling vma = find_vma(mm, address); 90759d3e8beSAlexey Skidanov 90859d3e8beSAlexey Skidanov memory_exception_data.gpu_id = dev->id; 90959d3e8beSAlexey Skidanov memory_exception_data.va = address; 91059d3e8beSAlexey Skidanov /* Set failure reason */ 91159d3e8beSAlexey Skidanov memory_exception_data.failure.NotPresent = 1; 91259d3e8beSAlexey Skidanov memory_exception_data.failure.NoExecute = 0; 91359d3e8beSAlexey Skidanov memory_exception_data.failure.ReadOnly = 0; 91459d3e8beSAlexey Skidanov if (vma) { 91559d3e8beSAlexey Skidanov if (vma->vm_start > address) { 91659d3e8beSAlexey Skidanov memory_exception_data.failure.NotPresent = 1; 91759d3e8beSAlexey Skidanov memory_exception_data.failure.NoExecute = 0; 91859d3e8beSAlexey Skidanov memory_exception_data.failure.ReadOnly = 0; 91959d3e8beSAlexey Skidanov } else { 92059d3e8beSAlexey Skidanov memory_exception_data.failure.NotPresent = 0; 92159d3e8beSAlexey Skidanov if (is_write_requested && !(vma->vm_flags & VM_WRITE)) 92259d3e8beSAlexey Skidanov memory_exception_data.failure.ReadOnly = 1; 92359d3e8beSAlexey Skidanov else 92459d3e8beSAlexey Skidanov memory_exception_data.failure.ReadOnly = 0; 92559d3e8beSAlexey Skidanov if (is_execute_requested && !(vma->vm_flags & VM_EXEC)) 92659d3e8beSAlexey Skidanov memory_exception_data.failure.NoExecute = 1; 92759d3e8beSAlexey Skidanov else 92859d3e8beSAlexey Skidanov memory_exception_data.failure.NoExecute = 0; 92959d3e8beSAlexey Skidanov } 93059d3e8beSAlexey Skidanov } 93159d3e8beSAlexey Skidanov 9329b56bb11SFelix Kuehling up_read(&mm->mmap_sem); 9339b56bb11SFelix Kuehling mmput(mm); 93459d3e8beSAlexey Skidanov 93559d3e8beSAlexey Skidanov mutex_lock(&p->event_mutex); 93659d3e8beSAlexey Skidanov 93759d3e8beSAlexey Skidanov /* Lookup events by type and signal them */ 93859d3e8beSAlexey Skidanov lookup_events_by_type_and_signal(p, KFD_EVENT_TYPE_MEMORY, 93959d3e8beSAlexey Skidanov &memory_exception_data); 94059d3e8beSAlexey Skidanov 94159d3e8beSAlexey Skidanov mutex_unlock(&p->event_mutex); 942abb208a8SFelix Kuehling kfd_unref_process(p); 94359d3e8beSAlexey Skidanov } 94464d1c3a4SFelix Kuehling #endif /* KFD_SUPPORT_IOMMU_V2 */ 945930c5ff4SAlexey Skidanov 946930c5ff4SAlexey Skidanov void kfd_signal_hw_exception_event(unsigned int pasid) 947930c5ff4SAlexey Skidanov { 948930c5ff4SAlexey Skidanov /* 949930c5ff4SAlexey Skidanov * Because we are called from arbitrary context (workqueue) as opposed 950930c5ff4SAlexey Skidanov * to process context, kfd_process could attempt to exit while we are 951abb208a8SFelix Kuehling * running so the lookup function increments the process ref count. 952930c5ff4SAlexey Skidanov */ 953930c5ff4SAlexey Skidanov struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); 954930c5ff4SAlexey Skidanov 955930c5ff4SAlexey Skidanov if (!p) 956930c5ff4SAlexey Skidanov return; /* Presumably process exited. */ 957930c5ff4SAlexey Skidanov 958930c5ff4SAlexey Skidanov mutex_lock(&p->event_mutex); 959930c5ff4SAlexey Skidanov 960930c5ff4SAlexey Skidanov /* Lookup events by type and signal them */ 961930c5ff4SAlexey Skidanov lookup_events_by_type_and_signal(p, KFD_EVENT_TYPE_HW_EXCEPTION, NULL); 962930c5ff4SAlexey Skidanov 963930c5ff4SAlexey Skidanov mutex_unlock(&p->event_mutex); 964abb208a8SFelix Kuehling kfd_unref_process(p); 965930c5ff4SAlexey Skidanov } 966