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 rc = plt_intr_efds_index_set(intr_handle, vec, fd);
167 nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ?
168 vec : (uint32_t)plt_intr_nb_efd_get(intr_handle);
169 plt_intr_nb_efd_set(intr_handle, nb_efd);
171 tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1;
172 if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle))
173 plt_intr_max_intr_set(intr_handle, tmp_nb_efd);
174 plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
175 plt_intr_nb_efd_get(intr_handle),
176 plt_intr_max_intr_get(intr_handle));
178 /* Enable MSIX vectors to VFIO */
179 return irq_config(intr_handle, vec);
183 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
184 void *data, unsigned int vec)
186 struct plt_intr_handle *tmp_handle;
187 uint8_t retries = 5; /* 5 ms */
190 if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
191 plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec,
192 plt_intr_max_intr_get(intr_handle));
196 tmp_handle = intr_handle;
197 fd = plt_intr_efds_index_get(intr_handle, vec);
201 if (plt_intr_fd_set(tmp_handle, fd))
205 /* Un-register callback func from platform lib */
206 rc = plt_intr_callback_unregister(tmp_handle, cb, data);
207 /* Retry only if -EAGAIN */
215 plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
219 plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec,
220 plt_intr_nb_efd_get(intr_handle),
221 plt_intr_max_intr_get(intr_handle));
223 if (plt_intr_efds_index_get(intr_handle, vec) != -1)
224 close(plt_intr_efds_index_get(intr_handle, vec));
225 /* Disable MSIX vectors from VFIO */
226 plt_intr_efds_index_set(intr_handle, vec, -1);
228 irq_config(intr_handle, vec);
234 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
235 void *data, unsigned int vec)
237 PLT_SET_USED(intr_handle);
246 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
247 void *data, unsigned int vec)
249 PLT_SET_USED(intr_handle);
256 dev_irqs_disable(struct plt_intr_handle *intr_handle)
258 PLT_SET_USED(intr_handle);
263 #endif /* __linux__ */