accel/qaic: Add AIC200 support
[drm/drm-misc.git] / tools / testing / selftests / net / busy_poller.c
blob99b0e8c17fcade73602ac408c7f23c12c28e9543
1 // SPDX-License-Identifier: GPL-2.0
2 #include <assert.h>
3 #include <errno.h>
4 #include <error.h>
5 #include <fcntl.h>
6 #include <inttypes.h>
7 #include <limits.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <ynl.h>
14 #include <arpa/inet.h>
15 #include <netinet/in.h>
17 #include <sys/epoll.h>
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20 #include <sys/types.h>
22 #include <linux/genetlink.h>
23 #include <linux/netlink.h>
25 #include "netdev-user.h"
27 /* The below ifdef blob is required because:
29 * - sys/epoll.h does not (yet) have the ioctl definitions included. So,
30 * systems with older glibcs will not have them available. However,
31 * sys/epoll.h does include the type definition for epoll_data, which is
32 * needed by the user program (e.g. epoll_event.data.fd)
34 * - linux/eventpoll.h does not define the epoll_data type, it is simply an
35 * opaque __u64. It does, however, include the ioctl definition.
37 * Including both headers is impossible (types would be redefined), so I've
38 * opted instead to take sys/epoll.h, and include the blob below.
40 * Someday, when glibc is globally up to date, the blob below can be removed.
42 #if !defined(EPOLL_IOC_TYPE)
43 struct epoll_params {
44 uint32_t busy_poll_usecs;
45 uint16_t busy_poll_budget;
46 uint8_t prefer_busy_poll;
48 /* pad the struct to a multiple of 64bits */
49 uint8_t __pad;
52 #define EPOLL_IOC_TYPE 0x8A
53 #define EPIOCSPARAMS _IOW(EPOLL_IOC_TYPE, 0x01, struct epoll_params)
54 #define EPIOCGPARAMS _IOR(EPOLL_IOC_TYPE, 0x02, struct epoll_params)
55 #endif
57 static uint32_t cfg_port = 8000;
58 static struct in_addr cfg_bind_addr = { .s_addr = INADDR_ANY };
59 static char *cfg_outfile;
60 static int cfg_max_events = 8;
61 static int cfg_ifindex;
63 /* busy poll params */
64 static uint32_t cfg_busy_poll_usecs;
65 static uint32_t cfg_busy_poll_budget;
66 static uint32_t cfg_prefer_busy_poll;
68 /* IRQ params */
69 static uint32_t cfg_defer_hard_irqs;
70 static uint64_t cfg_gro_flush_timeout;
71 static uint64_t cfg_irq_suspend_timeout;
73 static void usage(const char *filepath)
75 error(1, 0,
76 "Usage: %s -p<port> -b<addr> -m<max_events> -u<busy_poll_usecs> -P<prefer_busy_poll> -g<busy_poll_budget> -o<outfile> -d<defer_hard_irqs> -r<gro_flush_timeout> -s<irq_suspend_timeout> -i<ifindex>",
77 filepath);
80 static void parse_opts(int argc, char **argv)
82 int ret;
83 int c;
85 if (argc <= 1)
86 usage(argv[0]);
88 while ((c = getopt(argc, argv, "p:m:b:u:P:g:o:d:r:s:i:")) != -1) {
89 switch (c) {
90 case 'u':
91 cfg_busy_poll_usecs = strtoul(optarg, NULL, 0);
92 if (cfg_busy_poll_usecs == ULONG_MAX ||
93 cfg_busy_poll_usecs > UINT32_MAX)
94 error(1, ERANGE, "busy_poll_usecs too large");
95 break;
96 case 'P':
97 cfg_prefer_busy_poll = strtoul(optarg, NULL, 0);
98 if (cfg_prefer_busy_poll == ULONG_MAX ||
99 cfg_prefer_busy_poll > 1)
100 error(1, ERANGE,
101 "prefer busy poll should be 0 or 1");
102 break;
103 case 'g':
104 cfg_busy_poll_budget = strtoul(optarg, NULL, 0);
105 if (cfg_busy_poll_budget == ULONG_MAX ||
106 cfg_busy_poll_budget > UINT16_MAX)
107 error(1, ERANGE,
108 "busy poll budget must be [0, UINT16_MAX]");
109 break;
110 case 'p':
111 cfg_port = strtoul(optarg, NULL, 0);
112 if (cfg_port > UINT16_MAX)
113 error(1, ERANGE, "port must be <= 65535");
114 break;
115 case 'b':
116 ret = inet_aton(optarg, &cfg_bind_addr);
117 if (ret == 0)
118 error(1, errno,
119 "bind address %s invalid", optarg);
120 break;
121 case 'o':
122 cfg_outfile = strdup(optarg);
123 if (!cfg_outfile)
124 error(1, 0, "outfile invalid");
125 break;
126 case 'm':
127 cfg_max_events = strtol(optarg, NULL, 0);
129 if (cfg_max_events == LONG_MIN ||
130 cfg_max_events == LONG_MAX ||
131 cfg_max_events <= 0)
132 error(1, ERANGE,
133 "max events must be > 0 and < LONG_MAX");
134 break;
135 case 'd':
136 cfg_defer_hard_irqs = strtoul(optarg, NULL, 0);
138 if (cfg_defer_hard_irqs == ULONG_MAX ||
139 cfg_defer_hard_irqs > INT32_MAX)
140 error(1, ERANGE,
141 "defer_hard_irqs must be <= INT32_MAX");
142 break;
143 case 'r':
144 cfg_gro_flush_timeout = strtoull(optarg, NULL, 0);
146 if (cfg_gro_flush_timeout == ULLONG_MAX)
147 error(1, ERANGE,
148 "gro_flush_timeout must be < ULLONG_MAX");
149 break;
150 case 's':
151 cfg_irq_suspend_timeout = strtoull(optarg, NULL, 0);
153 if (cfg_irq_suspend_timeout == ULLONG_MAX)
154 error(1, ERANGE,
155 "irq_suspend_timeout must be < ULLONG_MAX");
156 break;
157 case 'i':
158 cfg_ifindex = strtoul(optarg, NULL, 0);
159 if (cfg_ifindex == ULONG_MAX)
160 error(1, ERANGE,
161 "ifindex must be < ULONG_MAX");
162 break;
166 if (!cfg_ifindex)
167 usage(argv[0]);
169 if (optind != argc)
170 usage(argv[0]);
173 static void epoll_ctl_add(int epfd, int fd, uint32_t events)
175 struct epoll_event ev;
177 ev.events = events;
178 ev.data.fd = fd;
179 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
180 error(1, errno, "epoll_ctl add fd: %d", fd);
183 static void setnonblock(int sockfd)
185 int flags;
187 flags = fcntl(sockfd, F_GETFL, 0);
189 if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
190 error(1, errno, "unable to set socket to nonblocking mode");
193 static void write_chunk(int fd, char *buf, ssize_t buflen)
195 ssize_t remaining = buflen;
196 char *buf_offset = buf;
197 ssize_t writelen = 0;
198 ssize_t write_result;
200 while (writelen < buflen) {
201 write_result = write(fd, buf_offset, remaining);
202 if (write_result == -1)
203 error(1, errno, "unable to write data to outfile");
205 writelen += write_result;
206 remaining -= write_result;
207 buf_offset += write_result;
211 static void setup_queue(void)
213 struct netdev_napi_get_list *napi_list = NULL;
214 struct netdev_napi_get_req_dump *req = NULL;
215 struct netdev_napi_set_req *set_req = NULL;
216 struct ynl_sock *ys;
217 struct ynl_error yerr;
218 uint32_t napi_id;
220 ys = ynl_sock_create(&ynl_netdev_family, &yerr);
221 if (!ys)
222 error(1, 0, "YNL: %s", yerr.msg);
224 req = netdev_napi_get_req_dump_alloc();
225 netdev_napi_get_req_dump_set_ifindex(req, cfg_ifindex);
226 napi_list = netdev_napi_get_dump(ys, req);
228 /* assume there is 1 NAPI configured and take the first */
229 if (napi_list->obj._present.id)
230 napi_id = napi_list->obj.id;
231 else
232 error(1, 0, "napi ID not present?");
234 set_req = netdev_napi_set_req_alloc();
235 netdev_napi_set_req_set_id(set_req, napi_id);
236 netdev_napi_set_req_set_defer_hard_irqs(set_req, cfg_defer_hard_irqs);
237 netdev_napi_set_req_set_gro_flush_timeout(set_req,
238 cfg_gro_flush_timeout);
239 netdev_napi_set_req_set_irq_suspend_timeout(set_req,
240 cfg_irq_suspend_timeout);
242 if (netdev_napi_set(ys, set_req))
243 error(1, 0, "can't set NAPI params: %s\n", yerr.msg);
245 netdev_napi_get_list_free(napi_list);
246 netdev_napi_get_req_dump_free(req);
247 netdev_napi_set_req_free(set_req);
248 ynl_sock_destroy(ys);
251 static void run_poller(void)
253 struct epoll_event events[cfg_max_events];
254 struct epoll_params epoll_params = {0};
255 struct sockaddr_in server_addr;
256 int i, epfd, nfds;
257 ssize_t readlen;
258 int outfile_fd;
259 char buf[1024];
260 int sockfd;
261 int conn;
262 int val;
264 outfile_fd = open(cfg_outfile, O_WRONLY | O_CREAT, 0644);
265 if (outfile_fd == -1)
266 error(1, errno, "unable to open outfile: %s", cfg_outfile);
268 sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
269 if (sockfd == -1)
270 error(1, errno, "unable to create listen socket");
272 server_addr.sin_family = AF_INET;
273 server_addr.sin_port = htons(cfg_port);
274 server_addr.sin_addr = cfg_bind_addr;
276 /* these values are range checked during parse_opts, so casting is safe
277 * here
279 epoll_params.busy_poll_usecs = cfg_busy_poll_usecs;
280 epoll_params.busy_poll_budget = (uint16_t)cfg_busy_poll_budget;
281 epoll_params.prefer_busy_poll = (uint8_t)cfg_prefer_busy_poll;
282 epoll_params.__pad = 0;
284 val = 1;
285 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)))
286 error(1, errno, "poller setsockopt reuseaddr");
288 setnonblock(sockfd);
290 if (bind(sockfd, (struct sockaddr *)&server_addr,
291 sizeof(struct sockaddr_in)))
292 error(0, errno, "poller bind to port: %d\n", cfg_port);
294 if (listen(sockfd, 1))
295 error(1, errno, "poller listen");
297 epfd = epoll_create1(0);
298 if (ioctl(epfd, EPIOCSPARAMS, &epoll_params) == -1)
299 error(1, errno, "unable to set busy poll params");
301 epoll_ctl_add(epfd, sockfd, EPOLLIN | EPOLLOUT | EPOLLET);
303 for (;;) {
304 nfds = epoll_wait(epfd, events, cfg_max_events, -1);
305 for (i = 0; i < nfds; i++) {
306 if (events[i].data.fd == sockfd) {
307 conn = accept(sockfd, NULL, NULL);
308 if (conn == -1)
309 error(1, errno,
310 "accepting incoming connection failed");
312 setnonblock(conn);
313 epoll_ctl_add(epfd, conn,
314 EPOLLIN | EPOLLET | EPOLLRDHUP |
315 EPOLLHUP);
316 } else if (events[i].events & EPOLLIN) {
317 for (;;) {
318 readlen = read(events[i].data.fd, buf,
319 sizeof(buf));
320 if (readlen > 0)
321 write_chunk(outfile_fd, buf,
322 readlen);
323 else
324 break;
326 } else {
327 /* spurious event ? */
329 if (events[i].events & (EPOLLRDHUP | EPOLLHUP)) {
330 epoll_ctl(epfd, EPOLL_CTL_DEL,
331 events[i].data.fd, NULL);
332 close(events[i].data.fd);
333 close(outfile_fd);
334 return;
340 int main(int argc, char *argv[])
342 parse_opts(argc, argv);
343 setup_queue();
344 run_poller();
345 return 0;