Branch data Line data Source code
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 : 0 : irq_get_info(struct plt_intr_handle *intr_handle)
22 : : {
23 : 0 : struct vfio_irq_info irq = {.argsz = sizeof(irq)};
24 : : int rc, vfio_dev_fd;
25 : :
26 : 0 : irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
27 : :
28 : 0 : vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
29 : 0 : rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
30 [ # # ]: 0 : if (rc < 0) {
31 : 0 : plt_err("Failed to get IRQ info rc=%d errno=%d", rc, errno);
32 : 0 : return rc;
33 : : }
34 : :
35 : 0 : 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 [ # # ]: 0 : if (irq.count == 0) {
39 : 0 : plt_err("HW max=%d > PLT_MAX_RXTX_INTR_VEC_ID: %d", irq.count,
40 : : PLT_MAX_RXTX_INTR_VEC_ID);
41 : 0 : plt_intr_max_intr_set(intr_handle, PLT_MAX_RXTX_INTR_VEC_ID);
42 : : } else {
43 [ # # ]: 0 : if (plt_intr_max_intr_set(intr_handle, irq.count))
44 : 0 : return -1;
45 : : }
46 : :
47 : : return 0;
48 : : }
49 : :
50 : : static int
51 : 0 : irq_config(struct plt_intr_handle *intr_handle, unsigned int vec)
52 : 0 : {
53 : 0 : 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 [ # # ]: 0 : if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
59 : 0 : plt_err("vector=%d greater than max_intr=%d", vec,
60 : : plt_intr_max_intr_get(intr_handle));
61 : 0 : 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 : 0 : irq_set->argsz = len;
68 : :
69 : 0 : irq_set->start = vec;
70 : 0 : irq_set->count = 1;
71 : 0 : irq_set->flags =
72 : : VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
73 : 0 : 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 : 0 : fd_ptr[0] = plt_intr_efds_index_get(intr_handle, vec);
78 : :
79 : 0 : vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
80 : 0 : rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
81 [ # # ]: 0 : if (rc)
82 : 0 : plt_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc);
83 : :
84 : : return rc;
85 : : }
86 : :
87 : : static int
88 : 0 : irq_init(struct plt_intr_handle *intr_handle)
89 : 0 : {
90 : 0 : 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 : 0 : len = sizeof(struct vfio_irq_set) +
97 : 0 : sizeof(int32_t) * plt_intr_max_intr_get(intr_handle);
98 : :
99 : : irq_set = (struct vfio_irq_set *)irq_set_buf;
100 : 0 : irq_set->argsz = len;
101 : 0 : irq_set->start = 0;
102 : 0 : irq_set->count = plt_intr_max_intr_get(intr_handle);
103 : 0 : irq_set->flags =
104 : : VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
105 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
106 : :
107 : 0 : fd_ptr = (int32_t *)&irq_set->data[0];
108 [ # # ]: 0 : for (i = 0; i < irq_set->count; i++)
109 : 0 : fd_ptr[i] = -1;
110 : :
111 : 0 : vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
112 : 0 : rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
113 [ # # ]: 0 : if (rc)
114 : 0 : plt_err("Failed to set irqs vector rc=%d", rc);
115 : :
116 : 0 : return rc;
117 : : }
118 : :
119 : : int
120 : 0 : dev_irqs_disable(struct plt_intr_handle *intr_handle)
121 : : {
122 : : /* Clear max_intr to indicate re-init next time */
123 : 0 : plt_intr_max_intr_set(intr_handle, 0);
124 : 0 : return plt_intr_disable(intr_handle);
125 : : }
126 : :
127 : : int
128 : 0 : dev_irq_reconfigure(struct plt_intr_handle *intr_handle, uint16_t max_intr)
129 : : {
130 : : /* Disable interrupts if enabled. */
131 [ # # ]: 0 : if (plt_intr_max_intr_get(intr_handle))
132 : 0 : dev_irqs_disable(intr_handle);
133 : :
134 : 0 : plt_intr_max_intr_set(intr_handle, max_intr);
135 : 0 : return irq_init(intr_handle);
136 : : }
137 : :
138 : : int
139 : 0 : 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 [ # # ]: 0 : if (plt_intr_max_intr_get(intr_handle) == 0) {
148 : 0 : irq_get_info(intr_handle);
149 : 0 : irq_init(intr_handle);
150 : : }
151 : :
152 [ # # ]: 0 : if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
153 : 0 : plt_err("Vector=%d greater than max_intr=%d or ",
154 : : vec, plt_intr_max_intr_get(intr_handle));
155 : 0 : return -EINVAL;
156 : : }
157 : :
158 : : tmp_handle = intr_handle;
159 : : /* Create new eventfd for interrupt vector */
160 : 0 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
161 [ # # ]: 0 : if (fd == -1)
162 : : return -ENODEV;
163 : :
164 [ # # ]: 0 : if (plt_intr_fd_set(tmp_handle, fd))
165 : 0 : return -errno;
166 : :
167 : : /* Register vector interrupt callback */
168 : 0 : rc = plt_intr_callback_register(tmp_handle, cb, data);
169 [ # # ]: 0 : if (rc) {
170 : 0 : plt_err("Failed to register vector:0x%x irq callback.", vec);
171 : 0 : return rc;
172 : : }
173 : :
174 : 0 : rc = plt_intr_efds_index_set(intr_handle, vec, fd);
175 [ # # ]: 0 : if (rc)
176 : : return rc;
177 : :
178 : 0 : nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ?
179 [ # # ]: 0 : vec : (uint32_t)plt_intr_nb_efd_get(intr_handle);
180 : 0 : plt_intr_nb_efd_set(intr_handle, nb_efd);
181 : :
182 : 0 : tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1;
183 [ # # ]: 0 : if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle))
184 : 0 : plt_intr_max_intr_set(intr_handle, tmp_nb_efd);
185 : 0 : 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 : 0 : return irq_config(intr_handle, vec);
191 : : }
192 : :
193 : : void
194 : 0 : 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 [ # # ]: 0 : if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
202 : 0 : plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec,
203 : : plt_intr_max_intr_get(intr_handle));
204 : 0 : return;
205 : : }
206 : :
207 : : tmp_handle = intr_handle;
208 : 0 : fd = plt_intr_efds_index_get(intr_handle, vec);
209 [ # # ]: 0 : if (fd == -1)
210 : : return;
211 : :
212 [ # # ]: 0 : if (plt_intr_fd_set(tmp_handle, fd))
213 : : return;
214 : :
215 : : do {
216 : : /* Un-register callback func from platform lib */
217 : 0 : rc = plt_intr_callback_unregister(tmp_handle, cb, data);
218 : : /* Retry only if -EAGAIN */
219 [ # # ]: 0 : if (rc != -EAGAIN)
220 : : break;
221 : : plt_delay_ms(1);
222 : 0 : retries--;
223 [ # # ]: 0 : } while (retries);
224 : :
225 [ # # ]: 0 : if (rc < 0) {
226 : 0 : plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
227 : 0 : return;
228 : : }
229 : :
230 : 0 : 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 [ # # ]: 0 : if (plt_intr_efds_index_get(intr_handle, vec) != -1)
235 : 0 : close(plt_intr_efds_index_get(intr_handle, vec));
236 : : /* Disable MSIX vectors from VFIO */
237 : 0 : plt_intr_efds_index_set(intr_handle, vec, -1);
238 : :
239 : 0 : 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__ */
|