+ DPRINTF(GPUDriver, "ioctl: AMDKFD_IOC_WAIT_EVENTS\n");
+ TypedBufferArg<kfd_ioctl_wait_events_args> args(ioc_buf);
+ args.copyIn(virt_proxy);
+ kfd_event_data *events =
+ (kfd_event_data *)args->events_ptr;
+ DPRINTF(GPUDriver, "amdkfd wait for events"
+ "(wait on all: %d, timeout : %d, num_events: %s)\n",
+ args->wait_for_all, args->timeout, args->num_events);
+ panic_if(args->wait_for_all != 0 && args->num_events > 1,
+ "Wait for all events not supported\n");
+ bool should_sleep = true;
+ if (TCEvents.count(tc) == 0) {
+ // This thread context trying to wait on an event for the first
+ // time, initialize it.
+ TCEvents.emplace(std::piecewise_construct, std::make_tuple(tc),
+ std::make_tuple(this, tc));
+ DPRINTF(GPUDriver, "\tamdkfd creating event list"
+ " for thread %d\n", tc->cpuId());
+ }
+ panic_if(TCEvents[tc].signalEvents.size() != 0,
+ "There are %d events that put this thread to sleep,"
+ " this thread should not be running\n",
+ TCEvents[tc].signalEvents.size());
+ for (int i = 0; i < args->num_events; i++) {
+ panic_if(!events,
+ "Event pointer invalid\n");
+ Addr eventDataAddr = (Addr)(events + i);
+ TypedBufferArg<kfd_event_data> EventData(
+ eventDataAddr, sizeof(kfd_event_data));
+ EventData.copyIn(virt_proxy);
+ DPRINTF(GPUDriver,
+ "\tamdkfd wait for event %d\n", EventData->event_id);
+ panic_if(ETable.count(EventData->event_id) == 0,
+ "Event ID invalid, cannot set this event\n");
+ panic_if(ETable[EventData->event_id].threadWaiting,
+ "Multiple threads waiting on the same event\n");
+ if (ETable[EventData->event_id].setEvent) {
+ // If event is already set, the event has already happened.
+ // Just unset the event and dont put this thread to sleep.
+ ETable[EventData->event_id].setEvent = false;
+ should_sleep = false;
+ }
+ if (should_sleep) {
+ // Put this thread to sleep
+ ETable[EventData->event_id].threadWaiting = true;
+ ETable[EventData->event_id].tc = tc;
+ TCEvents[tc].signalEvents.insert(EventData->event_id);
+ }
+ }
+
+ // TODO: Return the correct wait_result back. Currently, returning
+ // success for both KFD_WAIT_TIMEOUT and KFD_WAIT_COMPLETE.
+ // Ideally, this needs to be done after the event is triggered and
+ // after the thread is woken up.
+ args->wait_result = 0;
+ args.copyOut(virt_proxy);
+ if (should_sleep) {
+ // Put this thread to sleep
+ sleepCPU(tc, args->timeout);
+ } else {
+ // Remove events that tried to put this thread to sleep
+ TCEvents[tc].clearEvents();
+ }