xref: /dpdk/drivers/common/cnxk/roc_irq.c (revision f8dbaebbf1c9efcbb2e2354b341ed62175466a57)
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 			(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_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
129 		 void *data, unsigned int vec)
130 {
131 	struct plt_intr_handle *tmp_handle;
132 	uint32_t nb_efd, tmp_nb_efd;
133 	int rc, fd;
134 
135 	/* If no max_intr read from VFIO */
136 	if (plt_intr_max_intr_get(intr_handle) == 0) {
137 		irq_get_info(intr_handle);
138 		irq_init(intr_handle);
139 	}
140 
141 	if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
142 		plt_err("Vector=%d greater than max_intr=%d or ",
143 			vec, plt_intr_max_intr_get(intr_handle));
144 		return -EINVAL;
145 	}
146 
147 	tmp_handle = intr_handle;
148 	/* Create new eventfd for interrupt vector */
149 	fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
150 	if (fd == -1)
151 		return -ENODEV;
152 
153 	if (plt_intr_fd_set(tmp_handle, fd))
154 		return -errno;
155 
156 	/* Register vector interrupt callback */
157 	rc = plt_intr_callback_register(tmp_handle, cb, data);
158 	if (rc) {
159 		plt_err("Failed to register vector:0x%x irq callback.", vec);
160 		return rc;
161 	}
162 
163 	plt_intr_efds_index_set(intr_handle, vec, fd);
164 	nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ?
165 		vec : (uint32_t)plt_intr_nb_efd_get(intr_handle);
166 	plt_intr_nb_efd_set(intr_handle, nb_efd);
167 
168 	tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1;
169 	if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle))
170 		plt_intr_max_intr_set(intr_handle, tmp_nb_efd);
171 	plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
172 		     plt_intr_nb_efd_get(intr_handle),
173 		     plt_intr_max_intr_get(intr_handle));
174 
175 	/* Enable MSIX vectors to VFIO */
176 	return irq_config(intr_handle, vec);
177 }
178 
179 void
180 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
181 		   void *data, unsigned int vec)
182 {
183 	struct plt_intr_handle *tmp_handle;
184 	uint8_t retries = 5; /* 5 ms */
185 	int rc, fd;
186 
187 	if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
188 		plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec,
189 			plt_intr_max_intr_get(intr_handle));
190 		return;
191 	}
192 
193 	tmp_handle = intr_handle;
194 	fd = plt_intr_efds_index_get(intr_handle, vec);
195 	if (fd == -1)
196 		return;
197 
198 	if (plt_intr_fd_set(tmp_handle, fd))
199 		return;
200 
201 	do {
202 		/* Un-register callback func from platform lib */
203 		rc = plt_intr_callback_unregister(tmp_handle, cb, data);
204 		/* Retry only if -EAGAIN */
205 		if (rc != -EAGAIN)
206 			break;
207 		plt_delay_ms(1);
208 		retries--;
209 	} while (retries);
210 
211 	if (rc < 0) {
212 		plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
213 		return;
214 	}
215 
216 	plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec,
217 		     plt_intr_nb_efd_get(intr_handle),
218 		     plt_intr_max_intr_get(intr_handle));
219 
220 	if (plt_intr_efds_index_get(intr_handle, vec) != -1)
221 		close(plt_intr_efds_index_get(intr_handle, vec));
222 	/* Disable MSIX vectors from VFIO */
223 	plt_intr_efds_index_set(intr_handle, vec, -1);
224 
225 	irq_config(intr_handle, vec);
226 }
227 
228 #else
229 
230 int
231 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
232 		 void *data, unsigned int vec)
233 {
234 	PLT_SET_USED(intr_handle);
235 	PLT_SET_USED(cb);
236 	PLT_SET_USED(data);
237 	PLT_SET_USED(vec);
238 
239 	return -ENOTSUP;
240 }
241 
242 void
243 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
244 		   void *data, unsigned int vec)
245 {
246 	PLT_SET_USED(intr_handle);
247 	PLT_SET_USED(cb);
248 	PLT_SET_USED(data);
249 	PLT_SET_USED(vec);
250 }
251 
252 int
253 dev_irqs_disable(struct plt_intr_handle *intr_handle)
254 {
255 	PLT_SET_USED(intr_handle);
256 
257 	return -ENOTSUP;
258 }
259 
260 #endif /* __linux__ */
261