Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amdkfd: Use wait_queue_t to implement event waiting

Use standard wait queues for waiting and waking up waiting threads
instead of inventing our own. We still have our own wait loop
because the HSA event semantics require the ability to have one
thread waiting on multiple wait queues (events) at the same time.

Signed-off-by: Kent Russell <kent.russell@amd.com>
Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Acked-by: Oded Gabbay <oded.gabbay@gmail.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>

authored by

Felix Kuehling and committed by
Oded Gabbay
74e40716 ebf947fe

+24 -38
+22 -37
drivers/gpu/drm/amd/amdkfd/kfd_events.c
··· 33 33 #include <linux/device.h> 34 34 35 35 /* 36 - * A task can only be on a single wait_queue at a time, but we need to support 37 - * waiting on multiple events (any/all). 38 - * Instead of each event simply having a wait_queue with sleeping tasks, it 39 - * has a singly-linked list of tasks. 40 - * A thread that wants to sleep creates an array of these, one for each event 41 - * and adds one to each event's waiter chain. 36 + * Wrapper around wait_queue_entry_t 42 37 */ 43 38 struct kfd_event_waiter { 44 - struct list_head waiters; 45 - struct task_struct *sleeping_task; 46 - 47 - /* Transitions to true when the event this belongs to is signaled. */ 48 - bool activated; 49 - 50 - /* Event */ 51 - struct kfd_event *event; 39 + wait_queue_entry_t wait; 40 + struct kfd_event *event; /* Event to wait for */ 41 + bool activated; /* Becomes true when event is signaled */ 52 42 }; 53 43 54 44 /* ··· 334 344 335 345 static void destroy_event(struct kfd_process *p, struct kfd_event *ev) 336 346 { 337 - /* Wake up pending waiters. They will return failure */ 338 - while (!list_empty(&ev->waiters)) { 339 - struct kfd_event_waiter *waiter = 340 - list_first_entry(&ev->waiters, struct kfd_event_waiter, 341 - waiters); 347 + struct kfd_event_waiter *waiter; 342 348 349 + /* Wake up pending waiters. They will return failure */ 350 + list_for_each_entry(waiter, &ev->wq.head, wait.entry) 343 351 waiter->event = NULL; 344 - /* _init because free_waiters will call list_del */ 345 - list_del_init(&waiter->waiters); 346 - wake_up_process(waiter->sleeping_task); 347 - } 352 + wake_up_all(&ev->wq); 348 353 349 354 if (ev->signal_page) { 350 355 release_event_notification_slot(ev->signal_page, ··· 409 424 ev->auto_reset = auto_reset; 410 425 ev->signaled = false; 411 426 412 - INIT_LIST_HEAD(&ev->waiters); 427 + init_waitqueue_head(&ev->wq); 413 428 414 429 *event_page_offset = 0; 415 430 ··· 467 482 static void set_event(struct kfd_event *ev) 468 483 { 469 484 struct kfd_event_waiter *waiter; 470 - struct kfd_event_waiter *next; 471 485 472 - /* Auto reset if the list is non-empty and we're waking someone. */ 473 - ev->signaled = !ev->auto_reset || list_empty(&ev->waiters); 486 + /* Auto reset if the list is non-empty and we're waking 487 + * someone. waitqueue_active is safe here because we're 488 + * protected by the p->event_mutex, which is also held when 489 + * updating the wait queues in kfd_wait_on_events. 490 + */ 491 + ev->signaled = !ev->auto_reset || !waitqueue_active(&ev->wq); 474 492 475 - list_for_each_entry_safe(waiter, next, &ev->waiters, waiters) { 493 + list_for_each_entry(waiter, &ev->wq.head, wait.entry) 476 494 waiter->activated = true; 477 495 478 - /* _init because free_waiters will call list_del */ 479 - list_del_init(&waiter->waiters); 480 - 481 - wake_up_process(waiter->sleeping_task); 482 - } 496 + wake_up_all(&ev->wq); 483 497 } 484 498 485 499 /* Assumes that p is current. */ ··· 598 614 GFP_KERNEL); 599 615 600 616 for (i = 0; (event_waiters) && (i < num_events) ; i++) { 601 - INIT_LIST_HEAD(&event_waiters[i].waiters); 602 - event_waiters[i].sleeping_task = current; 617 + init_wait(&event_waiters[i].wait); 603 618 event_waiters[i].activated = false; 604 619 } 605 620 ··· 629 646 * wait on this event. 630 647 */ 631 648 if (!waiter->activated) 632 - list_add(&waiter->waiters, &ev->waiters); 649 + add_wait_queue(&ev->wq, &waiter->wait); 633 650 } 634 651 635 652 /* test_event_condition - Test condition of events being waited for ··· 719 736 uint32_t i; 720 737 721 738 for (i = 0; i < num_events; i++) 722 - list_del(&waiters[i].waiters); 739 + if (waiters[i].event) 740 + remove_wait_queue(&waiters[i].event->wq, 741 + &waiters[i].wait); 723 742 724 743 kfree(waiters); 725 744 }
+2 -1
drivers/gpu/drm/amd/amdkfd/kfd_events.h
··· 27 27 #include <linux/hashtable.h> 28 28 #include <linux/types.h> 29 29 #include <linux/list.h> 30 + #include <linux/wait.h> 30 31 #include "kfd_priv.h" 31 32 #include <uapi/linux/kfd_ioctl.h> 32 33 ··· 57 56 58 57 int type; 59 58 60 - struct list_head waiters; /* List of kfd_event_waiter by waiters. */ 59 + wait_queue_head_t wq; /* List of event waiters. */ 61 60 62 61 /* Only for signal events. */ 63 62 struct signal_page *signal_page;