xref: /dpdk/drivers/common/cnxk/roc_irq.c (revision 20c29a0e4602b9c7be5ea299457f909846c3785d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4 
5 #include "roc_api.h"
6 #include "roc_priv.h"
7 
8 #if defined(__linux__)
9 
10 #include <inttypes.h>
11 #include <linux/vfio.h>
12 #include <sys/eventfd.h>
13 #include <sys/ioctl.h>
14 #include <unistd.h>
15 
16 #define MSIX_IRQ_SET_BUF_LEN                                                   \
17 	(sizeof(struct vfio_irq_set) + sizeof(int) *			       \
18 			((uint32_t)plt_intr_max_intr_get(intr_handle)))
19 
20 static int
21 irq_get_info(struct plt_intr_handle *intr_handle)
22 {
23 	struct vfio_irq_info irq = {.argsz = sizeof(irq)};
24 	int rc, vfio_dev_fd;
25 
26 	irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
27 
28 	vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
29 	rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
30 	if (rc < 0) {
31 		plt_err("Failed to get IRQ info rc=%d errno=%d", rc, errno);
32 		return rc;
33 	}
34 
35 	plt_base_dbg("Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x",
36 		     irq.flags, irq.index, irq.count, PLT_MAX_RXTX_INTR_VEC_ID);
37 
38 	if (irq.count == 0) {
39 		plt_err("HW max=%d > PLT_MAX_RXTX_INTR_VEC_ID: %d", irq.count,
40 			PLT_MAX_RXTX_INTR_VEC_ID);
41 		plt_intr_max_intr_set(intr_handle, PLT_MAX_RXTX_INTR_VEC_ID);
42 	} else {
43 		if (plt_intr_max_intr_set(intr_handle, irq.count))
44 			return -1;
45 	}
46 
47 	return 0;
48 }
49 
50 static int
51 irq_config(struct plt_intr_handle *intr_handle, unsigned int vec)
52 {
53 	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
54 	struct vfio_irq_set *irq_set;
55 	int len, rc, vfio_dev_fd;
56 	int32_t *fd_ptr;
57 
58 	if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
59 		plt_err("vector=%d greater than max_intr=%d", vec,
60 			plt_intr_max_intr_get(intr_handle));
61 		return -EINVAL;
62 	}
63 
64 	len = sizeof(struct vfio_irq_set) + sizeof(int32_t);
65 
66 	irq_set = (struct vfio_irq_set *)irq_set_buf;
67 	irq_set->argsz = len;
68 
69 	irq_set->start = vec;
70 	irq_set->count = 1;
71 	irq_set->flags =
72 		VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
73 	irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
74 
75 	/* Use vec fd to set interrupt vectors */
76 	fd_ptr = (int32_t *)&irq_set->data[0];
77 	fd_ptr[0] = plt_intr_efds_index_get(intr_handle, vec);
78 
79 	vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
80 	rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
81 	if (rc)
82 		plt_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc);
83 
84 	return rc;
85 }
86 
87 static int
88 irq_init(struct plt_intr_handle *intr_handle)
89 {
90 	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
91 	struct vfio_irq_set *irq_set;
92 	int len, rc, vfio_dev_fd;
93 	int32_t *fd_ptr;
94 	uint32_t i;
95 
96 	len = sizeof(struct vfio_irq_set) +
97 	      sizeof(int32_t) * plt_intr_max_intr_get(intr_handle);
98 
99 	irq_set = (struct vfio_irq_set *)irq_set_buf;
100 	irq_set->argsz = len;
101 	irq_set->start = 0;
102 	irq_set->count = plt_intr_max_intr_get(intr_handle);
103 	irq_set->flags =
104 		VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
105 	irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
106 
107 	fd_ptr = (int32_t *)&irq_set->data[0];
108 	for (i = 0; i < irq_set->count; i++)
109 		fd_ptr[i] = -1;
110 
111 	vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
112 	rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
113 	if (rc)
114 		plt_err("Failed to set irqs vector rc=%d", rc);
115 
116 	return rc;
117 }
118 
119 int
120 dev_irqs_disable(struct plt_intr_handle *intr_handle)
121 {
122 	/* Clear max_intr to indicate re-init next time */
123 	plt_intr_max_intr_set(intr_handle, 0);
124 	return plt_intr_disable(intr_handle);
125 }
126 
127 int
128 dev_irq_reconfigure(struct plt_intr_handle *intr_handle, uint16_t max_intr)
129 {
130 	/* Disable interrupts if enabled. */
131 	if (plt_intr_max_intr_get(intr_handle))
132 		dev_irqs_disable(intr_handle);
133 
134 	plt_intr_max_intr_set(intr_handle, max_intr);
135 	return irq_init(intr_handle);
136 }
137 
138 int
139 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
140 		 void *data, unsigned int vec)
141 {
142 	struct plt_intr_handle *tmp_handle;
143 	uint32_t nb_efd, tmp_nb_efd;
144 	int rc, fd;
145 
146 	/* If no max_intr read from VFIO */
147 	if (plt_intr_max_intr_get(intr_handle) == 0) {
148 		irq_get_info(intr_handle);
149 		irq_init(intr_handle);
150 	}
151 
152 	if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
153 		plt_err("Vector=%d greater than max_intr=%d or ",
154 			vec, plt_intr_max_intr_get(intr_handle));
155 		return -EINVAL;
156 	}
157 
158 	tmp_handle = intr_handle;
159 	/* Create new eventfd for interrupt vector */
160 	fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
161 	if (fd == -1)
162 		return -ENODEV;
163 
164 	if (plt_intr_fd_set(tmp_handle, fd))
165 		return -errno;
166 
167 	/* Register vector interrupt callback */
168 	rc = plt_intr_callback_register(tmp_handle, cb, data);
169 	if (rc) {
170 		plt_err("Failed to register vector:0x%x irq callback.", vec);
171 		return rc;
172 	}
173 
174 	rc = plt_intr_efds_index_set(intr_handle, vec, fd);
175 	if (rc)
176 		return rc;
177 
178 	nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ?
179 		vec : (uint32_t)plt_intr_nb_efd_get(intr_handle);
180 	plt_intr_nb_efd_set(intr_handle, nb_efd);
181 
182 	tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1;
183 	if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle))
184 		plt_intr_max_intr_set(intr_handle, tmp_nb_efd);
185 	plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
186 		     plt_intr_nb_efd_get(intr_handle),
187 		     plt_intr_max_intr_get(intr_handle));
188 
189 	/* Enable MSIX vectors to VFIO */
190 	return irq_config(intr_handle, vec);
191 }
192 
193 void
194 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
195 		   void *data, unsigned int vec)
196 {
197 	struct plt_intr_handle *tmp_handle;
198 	uint8_t retries = 5; /* 5 ms */
199 	int rc, fd;
200 
201 	if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
202 		plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec,
203 			plt_intr_max_intr_get(intr_handle));
204 		return;
205 	}
206 
207 	tmp_handle = intr_handle;
208 	fd = plt_intr_efds_index_get(intr_handle, vec);
209 	if (fd == -1)
210 		return;
211 
212 	if (plt_intr_fd_set(tmp_handle, fd))
213 		return;
214 
215 	do {
216 		/* Un-register callback func from platform lib */
217 		rc = plt_intr_callback_unregister(tmp_handle, cb, data);
218 		/* Retry only if -EAGAIN */
219 		if (rc != -EAGAIN)
220 			break;
221 		plt_delay_ms(1);
222 		retries--;
223 	} while (retries);
224 
225 	if (rc < 0) {
226 		plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
227 		return;
228 	}
229 
230 	plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec,
231 		     plt_intr_nb_efd_get(intr_handle),
232 		     plt_intr_max_intr_get(intr_handle));
233 
234 	if (plt_intr_efds_index_get(intr_handle, vec) != -1)
235 		close(plt_intr_efds_index_get(intr_handle, vec));
236 	/* Disable MSIX vectors from VFIO */
237 	plt_intr_efds_index_set(intr_handle, vec, -1);
238 
239 	irq_config(intr_handle, vec);
240 }
241 
242 #else
243 
244 int
245 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
246 		 void *data, unsigned int vec)
247 {
248 	PLT_SET_USED(intr_handle);
249 	PLT_SET_USED(cb);
250 	PLT_SET_USED(data);
251 	PLT_SET_USED(vec);
252 
253 	return -ENOTSUP;
254 }
255 
256 void
257 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
258 		   void *data, unsigned int vec)
259 {
260 	PLT_SET_USED(intr_handle);
261 	PLT_SET_USED(cb);
262 	PLT_SET_USED(data);
263 	PLT_SET_USED(vec);
264 }
265 
266 int
267 dev_irqs_disable(struct plt_intr_handle *intr_handle)
268 {
269 	PLT_SET_USED(intr_handle);
270 
271 	return -ENOTSUP;
272 }
273 
274 #endif /* __linux__ */
275