1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2017 - Cambridge Greys Ltd
4*4882a593Smuzhiyun * Copyright (C) 2011 - 2014 Cisco Systems Inc
5*4882a593Smuzhiyun * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <stdlib.h>
9*4882a593Smuzhiyun #include <errno.h>
10*4882a593Smuzhiyun #include <sys/epoll.h>
11*4882a593Smuzhiyun #include <signal.h>
12*4882a593Smuzhiyun #include <string.h>
13*4882a593Smuzhiyun #include <irq_user.h>
14*4882a593Smuzhiyun #include <os.h>
15*4882a593Smuzhiyun #include <um_malloc.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /* Epoll support */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun static int epollfd = -1;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define MAX_EPOLL_EVENTS 64
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun static struct epoll_event epoll_events[MAX_EPOLL_EVENTS];
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /* Helper to return an Epoll data pointer from an epoll event structure.
26*4882a593Smuzhiyun * We need to keep this one on the userspace side to keep includes separate
27*4882a593Smuzhiyun */
28*4882a593Smuzhiyun
os_epoll_get_data_pointer(int index)29*4882a593Smuzhiyun void *os_epoll_get_data_pointer(int index)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun return epoll_events[index].data.ptr;
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /* Helper to compare events versus the events in the epoll structure.
35*4882a593Smuzhiyun * Same as above - needs to be on the userspace side
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun
os_epoll_triggered(int index,int events)39*4882a593Smuzhiyun int os_epoll_triggered(int index, int events)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun return epoll_events[index].events & events;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun /* Helper to set the event mask.
44*4882a593Smuzhiyun * The event mask is opaque to the kernel side, because it does not have
45*4882a593Smuzhiyun * access to the right includes/defines for EPOLL constants.
46*4882a593Smuzhiyun */
47*4882a593Smuzhiyun
os_event_mask(int irq_type)48*4882a593Smuzhiyun int os_event_mask(int irq_type)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun if (irq_type == IRQ_READ)
51*4882a593Smuzhiyun return EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
52*4882a593Smuzhiyun if (irq_type == IRQ_WRITE)
53*4882a593Smuzhiyun return EPOLLOUT;
54*4882a593Smuzhiyun return 0;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /*
58*4882a593Smuzhiyun * Initial Epoll Setup
59*4882a593Smuzhiyun */
os_setup_epoll(void)60*4882a593Smuzhiyun int os_setup_epoll(void)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun epollfd = epoll_create(MAX_EPOLL_EVENTS);
63*4882a593Smuzhiyun return epollfd;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /*
67*4882a593Smuzhiyun * Helper to run the actual epoll_wait
68*4882a593Smuzhiyun */
os_waiting_for_events_epoll(void)69*4882a593Smuzhiyun int os_waiting_for_events_epoll(void)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun int n, err;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun n = epoll_wait(epollfd,
74*4882a593Smuzhiyun (struct epoll_event *) &epoll_events, MAX_EPOLL_EVENTS, 0);
75*4882a593Smuzhiyun if (n < 0) {
76*4882a593Smuzhiyun err = -errno;
77*4882a593Smuzhiyun if (errno != EINTR)
78*4882a593Smuzhiyun printk(
79*4882a593Smuzhiyun UM_KERN_ERR "os_waiting_for_events:"
80*4882a593Smuzhiyun " epoll returned %d, error = %s\n", n,
81*4882a593Smuzhiyun strerror(errno)
82*4882a593Smuzhiyun );
83*4882a593Smuzhiyun return err;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun return n;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /*
90*4882a593Smuzhiyun * Helper to add a fd to epoll
91*4882a593Smuzhiyun */
os_add_epoll_fd(int events,int fd,void * data)92*4882a593Smuzhiyun int os_add_epoll_fd(int events, int fd, void *data)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun struct epoll_event event;
95*4882a593Smuzhiyun int result;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun event.data.ptr = data;
98*4882a593Smuzhiyun event.events = events | EPOLLET;
99*4882a593Smuzhiyun result = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
100*4882a593Smuzhiyun if ((result) && (errno == EEXIST))
101*4882a593Smuzhiyun result = os_mod_epoll_fd(events, fd, data);
102*4882a593Smuzhiyun if (result)
103*4882a593Smuzhiyun printk("epollctl add err fd %d, %s\n", fd, strerror(errno));
104*4882a593Smuzhiyun return result;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /*
108*4882a593Smuzhiyun * Helper to mod the fd event mask and/or data backreference
109*4882a593Smuzhiyun */
os_mod_epoll_fd(int events,int fd,void * data)110*4882a593Smuzhiyun int os_mod_epoll_fd(int events, int fd, void *data)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun struct epoll_event event;
113*4882a593Smuzhiyun int result;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun event.data.ptr = data;
116*4882a593Smuzhiyun event.events = events;
117*4882a593Smuzhiyun result = epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
118*4882a593Smuzhiyun if (result)
119*4882a593Smuzhiyun printk(UM_KERN_ERR
120*4882a593Smuzhiyun "epollctl mod err fd %d, %s\n", fd, strerror(errno));
121*4882a593Smuzhiyun return result;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /*
125*4882a593Smuzhiyun * Helper to delete the epoll fd
126*4882a593Smuzhiyun */
os_del_epoll_fd(int fd)127*4882a593Smuzhiyun int os_del_epoll_fd(int fd)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun struct epoll_event event;
130*4882a593Smuzhiyun int result;
131*4882a593Smuzhiyun /* This is quiet as we use this as IO ON/OFF - so it is often
132*4882a593Smuzhiyun * invoked on a non-existent fd
133*4882a593Smuzhiyun */
134*4882a593Smuzhiyun result = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &event);
135*4882a593Smuzhiyun return result;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
os_set_ioignore(void)138*4882a593Smuzhiyun void os_set_ioignore(void)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun signal(SIGIO, SIG_IGN);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
os_close_epoll_fd(void)143*4882a593Smuzhiyun void os_close_epoll_fd(void)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun /* Needed so we do not leak an fd when rebooting */
146*4882a593Smuzhiyun os_close_file(epollfd);
147*4882a593Smuzhiyun }
148