xref: /OK3568_Linux_fs/kernel/arch/um/os-Linux/irq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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