1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2021 Marvell.
11 #include <linux/vfio.h>
12 #include <sys/eventfd.h>
13 #include <sys/ioctl.h>
16 #define MSIX_IRQ_SET_BUF_LEN \
17 (sizeof(struct vfio_irq_set) + sizeof(int) * (PLT_MAX_RXTX_INTR_VEC_ID))
20 irq_get_info(struct plt_intr_handle *intr_handle)
22 struct vfio_irq_info irq = {.argsz = sizeof(irq)};
25 irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
27 vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
28 rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
30 plt_err("Failed to get IRQ info rc=%d errno=%d", rc, errno);
34 plt_base_dbg("Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x",
35 irq.flags, irq.index, irq.count, PLT_MAX_RXTX_INTR_VEC_ID);
37 if (irq.count > PLT_MAX_RXTX_INTR_VEC_ID) {
38 plt_err("HW max=%d > PLT_MAX_RXTX_INTR_VEC_ID: %d", irq.count,
39 PLT_MAX_RXTX_INTR_VEC_ID);
40 plt_intr_max_intr_set(intr_handle, PLT_MAX_RXTX_INTR_VEC_ID);
42 if (plt_intr_max_intr_set(intr_handle, irq.count))
50 irq_config(struct plt_intr_handle *intr_handle, unsigned int vec)
52 char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
53 struct vfio_irq_set *irq_set;
54 int len, rc, vfio_dev_fd;
57 if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
58 plt_err("vector=%d greater than max_intr=%d", vec,
59 plt_intr_max_intr_get(intr_handle));
63 len = sizeof(struct vfio_irq_set) + sizeof(int32_t);
65 irq_set = (struct vfio_irq_set *)irq_set_buf;
71 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
72 irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
74 /* Use vec fd to set interrupt vectors */
75 fd_ptr = (int32_t *)&irq_set->data[0];
76 fd_ptr[0] = plt_intr_efds_index_get(intr_handle, vec);
78 vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
79 rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
81 plt_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc);
87 irq_init(struct plt_intr_handle *intr_handle)
89 char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
90 struct vfio_irq_set *irq_set;
91 int len, rc, vfio_dev_fd;
95 if (plt_intr_max_intr_get(intr_handle) >
96 PLT_MAX_RXTX_INTR_VEC_ID) {
97 plt_err("Max_intr=%d greater than PLT_MAX_RXTX_INTR_VEC_ID=%d",
98 plt_intr_max_intr_get(intr_handle),
99 PLT_MAX_RXTX_INTR_VEC_ID);
103 len = sizeof(struct vfio_irq_set) +
104 sizeof(int32_t) * plt_intr_max_intr_get(intr_handle);
106 irq_set = (struct vfio_irq_set *)irq_set_buf;
107 irq_set->argsz = len;
109 irq_set->count = plt_intr_max_intr_get(intr_handle);
111 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
112 irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
114 fd_ptr = (int32_t *)&irq_set->data[0];
115 for (i = 0; i < irq_set->count; i++)
118 vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
119 rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
121 plt_err("Failed to set irqs vector rc=%d", rc);
127 dev_irqs_disable(struct plt_intr_handle *intr_handle)
129 /* Clear max_intr to indicate re-init next time */
130 plt_intr_max_intr_set(intr_handle, 0);
131 return plt_intr_disable(intr_handle);
135 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
136 void *data, unsigned int vec)
138 struct plt_intr_handle *tmp_handle;
139 uint32_t nb_efd, tmp_nb_efd;
142 /* If no max_intr read from VFIO */
143 if (plt_intr_max_intr_get(intr_handle) == 0) {
144 irq_get_info(intr_handle);
145 irq_init(intr_handle);
148 if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
149 plt_err("Vector=%d greater than max_intr=%d or ",
150 vec, plt_intr_max_intr_get(intr_handle));
154 tmp_handle = intr_handle;
155 /* Create new eventfd for interrupt vector */
156 fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
160 if (plt_intr_fd_set(tmp_handle, fd))
163 /* Register vector interrupt callback */
164 rc = plt_intr_callback_register(tmp_handle, cb, data);
166 plt_err("Failed to register vector:0x%x irq callback.", vec);
170 plt_intr_efds_index_set(intr_handle, vec, fd);
171 nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ?
172 vec : (uint32_t)plt_intr_nb_efd_get(intr_handle);
173 plt_intr_nb_efd_set(intr_handle, nb_efd);
175 tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1;
176 if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle))
177 plt_intr_max_intr_set(intr_handle, tmp_nb_efd);
178 plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
179 plt_intr_nb_efd_get(intr_handle),
180 plt_intr_max_intr_get(intr_handle));
182 /* Enable MSIX vectors to VFIO */
183 return irq_config(intr_handle, vec);
187 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
188 void *data, unsigned int vec)
190 struct plt_intr_handle *tmp_handle;
191 uint8_t retries = 5; /* 5 ms */
194 if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
195 plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec,
196 plt_intr_max_intr_get(intr_handle));
200 tmp_handle = intr_handle;
201 fd = plt_intr_efds_index_get(intr_handle, vec);
205 if (plt_intr_fd_set(tmp_handle, fd))
209 /* Un-register callback func from platform lib */
210 rc = plt_intr_callback_unregister(tmp_handle, cb, data);
211 /* Retry only if -EAGAIN */
219 plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
223 plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec,
224 plt_intr_nb_efd_get(intr_handle),
225 plt_intr_max_intr_get(intr_handle));
227 if (plt_intr_efds_index_get(intr_handle, vec) != -1)
228 close(plt_intr_efds_index_get(intr_handle, vec));
229 /* Disable MSIX vectors from VFIO */
230 plt_intr_efds_index_set(intr_handle, vec, -1);
232 irq_config(intr_handle, vec);
238 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
239 void *data, unsigned int vec)
241 PLT_SET_USED(intr_handle);
250 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
251 void *data, unsigned int vec)
253 PLT_SET_USED(intr_handle);
260 dev_irqs_disable(struct plt_intr_handle *intr_handle)
262 PLT_SET_USED(intr_handle);
267 #endif /* __linux__ */