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 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_reconfigure(struct plt_intr_handle *intr_handle, uint16_t max_intr) 129 { 130 /* Disable interrupts if enabled. */ 131 if (plt_intr_max_intr_get(intr_handle)) 132 dev_irqs_disable(intr_handle); 133 134 plt_intr_max_intr_set(intr_handle, max_intr); 135 return irq_init(intr_handle); 136 } 137 138 int 139 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 if (plt_intr_max_intr_get(intr_handle) == 0) { 148 irq_get_info(intr_handle); 149 irq_init(intr_handle); 150 } 151 152 if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) { 153 plt_err("Vector=%d greater than max_intr=%d or ", 154 vec, plt_intr_max_intr_get(intr_handle)); 155 return -EINVAL; 156 } 157 158 tmp_handle = intr_handle; 159 /* Create new eventfd for interrupt vector */ 160 fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 161 if (fd == -1) 162 return -ENODEV; 163 164 if (plt_intr_fd_set(tmp_handle, fd)) 165 return -errno; 166 167 /* Register vector interrupt callback */ 168 rc = plt_intr_callback_register(tmp_handle, cb, data); 169 if (rc) { 170 plt_err("Failed to register vector:0x%x irq callback.", vec); 171 return rc; 172 } 173 174 rc = plt_intr_efds_index_set(intr_handle, vec, fd); 175 if (rc) 176 return rc; 177 178 nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ? 179 vec : (uint32_t)plt_intr_nb_efd_get(intr_handle); 180 plt_intr_nb_efd_set(intr_handle, nb_efd); 181 182 tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1; 183 if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle)) 184 plt_intr_max_intr_set(intr_handle, tmp_nb_efd); 185 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 return irq_config(intr_handle, vec); 191 } 192 193 void 194 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 if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) { 202 plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec, 203 plt_intr_max_intr_get(intr_handle)); 204 return; 205 } 206 207 tmp_handle = intr_handle; 208 fd = plt_intr_efds_index_get(intr_handle, vec); 209 if (fd == -1) 210 return; 211 212 if (plt_intr_fd_set(tmp_handle, fd)) 213 return; 214 215 do { 216 /* Un-register callback func from platform lib */ 217 rc = plt_intr_callback_unregister(tmp_handle, cb, data); 218 /* Retry only if -EAGAIN */ 219 if (rc != -EAGAIN) 220 break; 221 plt_delay_ms(1); 222 retries--; 223 } while (retries); 224 225 if (rc < 0) { 226 plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc); 227 return; 228 } 229 230 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 if (plt_intr_efds_index_get(intr_handle, vec) != -1) 235 close(plt_intr_efds_index_get(intr_handle, vec)); 236 /* Disable MSIX vectors from VFIO */ 237 plt_intr_efds_index_set(intr_handle, vec, -1); 238 239 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__ */ 275