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) * \
18 (plt_intr_max_intr_get(intr_handle)))
21 irq_get_info(struct plt_intr_handle *intr_handle)
23 struct vfio_irq_info irq = {.argsz = sizeof(irq)};
26 irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
28 vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
29 rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
31 plt_err("Failed to get IRQ info rc=%d errno=%d", rc, errno);
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);
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);
43 if (plt_intr_max_intr_set(intr_handle, irq.count))
51 irq_config(struct plt_intr_handle *intr_handle, unsigned int vec)
53 char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
54 struct vfio_irq_set *irq_set;
55 int len, rc, vfio_dev_fd;
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));
64 len = sizeof(struct vfio_irq_set) + sizeof(int32_t);
66 irq_set = (struct vfio_irq_set *)irq_set_buf;
72 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
73 irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
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);
79 vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
80 rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
82 plt_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc);
88 irq_init(struct plt_intr_handle *intr_handle)
90 char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
91 struct vfio_irq_set *irq_set;
92 int len, rc, vfio_dev_fd;
96 len = sizeof(struct vfio_irq_set) +
97 sizeof(int32_t) * plt_intr_max_intr_get(intr_handle);
99 irq_set = (struct vfio_irq_set *)irq_set_buf;
100 irq_set->argsz = len;
102 irq_set->count = plt_intr_max_intr_get(intr_handle);
104 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
105 irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
107 fd_ptr = (int32_t *)&irq_set->data[0];
108 for (i = 0; i < irq_set->count; i++)
111 vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
112 rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
114 plt_err("Failed to set irqs vector rc=%d", rc);
120 dev_irqs_disable(struct plt_intr_handle *intr_handle)
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);
128 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
129 void *data, unsigned int vec)
131 struct plt_intr_handle *tmp_handle;
132 uint32_t nb_efd, tmp_nb_efd;
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);
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));
147 tmp_handle = intr_handle;
148 /* Create new eventfd for interrupt vector */
149 fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
153 if (plt_intr_fd_set(tmp_handle, fd))
156 /* Register vector interrupt callback */
157 rc = plt_intr_callback_register(tmp_handle, cb, data);
159 plt_err("Failed to register vector:0x%x irq callback.", vec);
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);
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));
175 /* Enable MSIX vectors to VFIO */
176 return irq_config(intr_handle, vec);
180 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
181 void *data, unsigned int vec)
183 struct plt_intr_handle *tmp_handle;
184 uint8_t retries = 5; /* 5 ms */
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));
193 tmp_handle = intr_handle;
194 fd = plt_intr_efds_index_get(intr_handle, vec);
198 if (plt_intr_fd_set(tmp_handle, fd))
202 /* Un-register callback func from platform lib */
203 rc = plt_intr_callback_unregister(tmp_handle, cb, data);
204 /* Retry only if -EAGAIN */
212 plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
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));
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);
225 irq_config(intr_handle, vec);
231 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
232 void *data, unsigned int vec)
234 PLT_SET_USED(intr_handle);
243 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
244 void *data, unsigned int vec)
246 PLT_SET_USED(intr_handle);
253 dev_irqs_disable(struct plt_intr_handle *intr_handle)
255 PLT_SET_USED(intr_handle);
260 #endif /* __linux__ */