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) * (PLT_MAX_RXTX_INTR_VEC_ID)) 18 19 static int 20 irq_get_info(struct plt_intr_handle *intr_handle) 21 { 22 struct vfio_irq_info irq = {.argsz = sizeof(irq)}; 23 int rc; 24 25 irq.index = VFIO_PCI_MSIX_IRQ_INDEX; 26 27 rc = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq); 28 if (rc < 0) { 29 plt_err("Failed to get IRQ info rc=%d errno=%d", rc, errno); 30 return rc; 31 } 32 33 plt_base_dbg("Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x", 34 irq.flags, irq.index, irq.count, PLT_MAX_RXTX_INTR_VEC_ID); 35 36 if (irq.count > PLT_MAX_RXTX_INTR_VEC_ID) { 37 plt_err("HW max=%d > PLT_MAX_RXTX_INTR_VEC_ID: %d", irq.count, 38 PLT_MAX_RXTX_INTR_VEC_ID); 39 intr_handle->max_intr = PLT_MAX_RXTX_INTR_VEC_ID; 40 } else { 41 intr_handle->max_intr = irq.count; 42 } 43 44 return 0; 45 } 46 47 static int 48 irq_config(struct plt_intr_handle *intr_handle, unsigned int vec) 49 { 50 char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; 51 struct vfio_irq_set *irq_set; 52 int32_t *fd_ptr; 53 int len, rc; 54 55 if (vec > intr_handle->max_intr) { 56 plt_err("vector=%d greater than max_intr=%d", vec, 57 intr_handle->max_intr); 58 return -EINVAL; 59 } 60 61 len = sizeof(struct vfio_irq_set) + sizeof(int32_t); 62 63 irq_set = (struct vfio_irq_set *)irq_set_buf; 64 irq_set->argsz = len; 65 66 irq_set->start = vec; 67 irq_set->count = 1; 68 irq_set->flags = 69 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; 70 irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; 71 72 /* Use vec fd to set interrupt vectors */ 73 fd_ptr = (int32_t *)&irq_set->data[0]; 74 fd_ptr[0] = intr_handle->efds[vec]; 75 76 rc = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); 77 if (rc) 78 plt_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc); 79 80 return rc; 81 } 82 83 static int 84 irq_init(struct plt_intr_handle *intr_handle) 85 { 86 char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; 87 struct vfio_irq_set *irq_set; 88 int32_t *fd_ptr; 89 int len, rc; 90 uint32_t i; 91 92 if (intr_handle->max_intr > PLT_MAX_RXTX_INTR_VEC_ID) { 93 plt_err("Max_intr=%d greater than PLT_MAX_RXTX_INTR_VEC_ID=%d", 94 intr_handle->max_intr, PLT_MAX_RXTX_INTR_VEC_ID); 95 return -ERANGE; 96 } 97 98 len = sizeof(struct vfio_irq_set) + 99 sizeof(int32_t) * intr_handle->max_intr; 100 101 irq_set = (struct vfio_irq_set *)irq_set_buf; 102 irq_set->argsz = len; 103 irq_set->start = 0; 104 irq_set->count = intr_handle->max_intr; 105 irq_set->flags = 106 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; 107 irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; 108 109 fd_ptr = (int32_t *)&irq_set->data[0]; 110 for (i = 0; i < irq_set->count; i++) 111 fd_ptr[i] = -1; 112 113 rc = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); 114 if (rc) 115 plt_err("Failed to set irqs vector rc=%d", rc); 116 117 return rc; 118 } 119 120 int 121 dev_irqs_disable(struct plt_intr_handle *intr_handle) 122 { 123 /* Clear max_intr to indicate re-init next time */ 124 intr_handle->max_intr = 0; 125 return plt_intr_disable(intr_handle); 126 } 127 128 int 129 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb, 130 void *data, unsigned int vec) 131 { 132 struct plt_intr_handle tmp_handle; 133 int rc; 134 135 /* If no max_intr read from VFIO */ 136 if (intr_handle->max_intr == 0) { 137 irq_get_info(intr_handle); 138 irq_init(intr_handle); 139 } 140 141 if (vec > intr_handle->max_intr || vec >= PLT_DIM(intr_handle->efds)) { 142 plt_err("Vector=%d greater than max_intr=%d or " 143 "max_efd=%" PRIu64, 144 vec, intr_handle->max_intr, PLT_DIM(intr_handle->efds)); 145 return -EINVAL; 146 } 147 148 tmp_handle = *intr_handle; 149 /* Create new eventfd for interrupt vector */ 150 tmp_handle.fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 151 if (tmp_handle.fd == -1) 152 return -ENODEV; 153 154 /* Register vector interrupt callback */ 155 rc = plt_intr_callback_register(&tmp_handle, cb, data); 156 if (rc) { 157 plt_err("Failed to register vector:0x%x irq callback.", vec); 158 return rc; 159 } 160 161 intr_handle->efds[vec] = tmp_handle.fd; 162 intr_handle->nb_efd = 163 (vec > intr_handle->nb_efd) ? vec : intr_handle->nb_efd; 164 if ((intr_handle->nb_efd + 1) > intr_handle->max_intr) 165 intr_handle->max_intr = intr_handle->nb_efd + 1; 166 167 plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec, 168 intr_handle->nb_efd, intr_handle->max_intr); 169 170 /* Enable MSIX vectors to VFIO */ 171 return irq_config(intr_handle, vec); 172 } 173 174 void 175 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb, 176 void *data, unsigned int vec) 177 { 178 struct plt_intr_handle tmp_handle; 179 uint8_t retries = 5; /* 5 ms */ 180 int rc; 181 182 if (vec > intr_handle->max_intr) { 183 plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec, 184 intr_handle->max_intr); 185 return; 186 } 187 188 tmp_handle = *intr_handle; 189 tmp_handle.fd = intr_handle->efds[vec]; 190 if (tmp_handle.fd == -1) 191 return; 192 193 do { 194 /* Un-register callback func from platform lib */ 195 rc = plt_intr_callback_unregister(&tmp_handle, cb, data); 196 /* Retry only if -EAGAIN */ 197 if (rc != -EAGAIN) 198 break; 199 plt_delay_ms(1); 200 retries--; 201 } while (retries); 202 203 if (rc < 0) { 204 plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc); 205 return; 206 } 207 208 plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec, 209 intr_handle->nb_efd, intr_handle->max_intr); 210 211 if (intr_handle->efds[vec] != -1) 212 close(intr_handle->efds[vec]); 213 /* Disable MSIX vectors from VFIO */ 214 intr_handle->efds[vec] = -1; 215 irq_config(intr_handle, vec); 216 } 217 218 #else 219 220 int 221 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb, 222 void *data, unsigned int vec) 223 { 224 PLT_SET_USED(intr_handle); 225 PLT_SET_USED(cb); 226 PLT_SET_USED(data); 227 PLT_SET_USED(vec); 228 229 return -ENOTSUP; 230 } 231 232 void 233 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb, 234 void *data, unsigned int vec) 235 { 236 PLT_SET_USED(intr_handle); 237 PLT_SET_USED(cb); 238 PLT_SET_USED(data); 239 PLT_SET_USED(vec); 240 } 241 242 int 243 dev_irqs_disable(struct plt_intr_handle *intr_handle) 244 { 245 PLT_SET_USED(intr_handle); 246 247 return -ENOTSUP; 248 } 249 250 #endif /* __linux__ */ 251