1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2020 Mellanox Technologies, Ltd
3  */
4 
5 #include <rte_interrupts.h>
6 
7 #include "eal_private.h"
8 #include "eal_windows.h"
9 
10 static pthread_t intr_thread;
11 
12 static HANDLE intr_iocp;
13 
14 static void
eal_intr_process(const OVERLAPPED_ENTRY * event)15 eal_intr_process(const OVERLAPPED_ENTRY *event)
16 {
17 	RTE_SET_USED(event);
18 }
19 
20 static void *
eal_intr_thread_main(LPVOID arg __rte_unused)21 eal_intr_thread_main(LPVOID arg __rte_unused)
22 {
23 	while (1) {
24 		OVERLAPPED_ENTRY events[16];
25 		ULONG event_count, i;
26 		BOOL result;
27 
28 		result = GetQueuedCompletionStatusEx(
29 			intr_iocp, events, RTE_DIM(events), &event_count,
30 			INFINITE, /* no timeout */
31 			TRUE);    /* alertable wait for alarm APCs */
32 
33 		if (!result) {
34 			DWORD error = GetLastError();
35 			if (error != WAIT_IO_COMPLETION) {
36 				RTE_LOG_WIN32_ERR("GetQueuedCompletionStatusEx()");
37 				RTE_LOG(ERR, EAL, "Failed waiting for interrupts\n");
38 				break;
39 			}
40 
41 			/* No I/O events, all work is done in completed APCs. */
42 			continue;
43 		}
44 
45 		for (i = 0; i < event_count; i++)
46 			eal_intr_process(&events[i]);
47 	}
48 
49 	CloseHandle(intr_iocp);
50 	intr_iocp = NULL;
51 	return NULL;
52 }
53 
54 int
rte_eal_intr_init(void)55 rte_eal_intr_init(void)
56 {
57 	int ret = 0;
58 
59 	intr_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
60 	if (intr_iocp == NULL) {
61 		RTE_LOG_WIN32_ERR("CreateIoCompletionPort()");
62 		RTE_LOG(ERR, EAL, "Cannot create interrupt IOCP\n");
63 		return -1;
64 	}
65 
66 	ret = rte_ctrl_thread_create(&intr_thread, "eal-intr-thread", NULL,
67 			eal_intr_thread_main, NULL);
68 	if (ret != 0) {
69 		rte_errno = -ret;
70 		RTE_LOG(ERR, EAL, "Cannot create interrupt thread\n");
71 	}
72 
73 	return ret;
74 }
75 
76 int
rte_thread_is_intr(void)77 rte_thread_is_intr(void)
78 {
79 	return pthread_equal(intr_thread, pthread_self());
80 }
81 
82 int
rte_intr_rx_ctl(__rte_unused struct rte_intr_handle * intr_handle,__rte_unused int epfd,__rte_unused int op,__rte_unused unsigned int vec,__rte_unused void * data)83 rte_intr_rx_ctl(__rte_unused struct rte_intr_handle *intr_handle,
84 		__rte_unused int epfd, __rte_unused int op,
85 		__rte_unused unsigned int vec, __rte_unused void *data)
86 {
87 	return -ENOTSUP;
88 }
89 
90 int
eal_intr_thread_schedule(void (* func)(void * arg),void * arg)91 eal_intr_thread_schedule(void (*func)(void *arg), void *arg)
92 {
93 	HANDLE handle;
94 
95 	handle = OpenThread(THREAD_ALL_ACCESS, FALSE, intr_thread);
96 	if (handle == NULL) {
97 		RTE_LOG_WIN32_ERR("OpenThread(%llu)", intr_thread);
98 		return -ENOENT;
99 	}
100 
101 	if (!QueueUserAPC((PAPCFUNC)(ULONG_PTR)func, handle, (ULONG_PTR)arg)) {
102 		RTE_LOG_WIN32_ERR("QueueUserAPC()");
103 		return -EINVAL;
104 	}
105 
106 	return 0;
107 }
108