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