101bc01e1SJerin Jacob /* SPDX-License-Identifier: BSD-3-Clause 201bc01e1SJerin Jacob * Copyright(C) 2021 Marvell. 301bc01e1SJerin Jacob */ 401bc01e1SJerin Jacob 501bc01e1SJerin Jacob #include "roc_api.h" 601bc01e1SJerin Jacob #include "roc_priv.h" 701bc01e1SJerin Jacob 801bc01e1SJerin Jacob #if defined(__linux__) 901bc01e1SJerin Jacob 1001bc01e1SJerin Jacob #include <inttypes.h> 1101bc01e1SJerin Jacob #include <linux/vfio.h> 1201bc01e1SJerin Jacob #include <sys/eventfd.h> 1301bc01e1SJerin Jacob #include <sys/ioctl.h> 1401bc01e1SJerin Jacob #include <unistd.h> 1501bc01e1SJerin Jacob 1601bc01e1SJerin Jacob #define MSIX_IRQ_SET_BUF_LEN \ 1739ac394aSHarman Kalra (sizeof(struct vfio_irq_set) + sizeof(int) * \ 18*20c29a0eSSunil Kumar Kori ((uint32_t)plt_intr_max_intr_get(intr_handle))) 1901bc01e1SJerin Jacob 2001bc01e1SJerin Jacob static int 2101bc01e1SJerin Jacob irq_get_info(struct plt_intr_handle *intr_handle) 2201bc01e1SJerin Jacob { 2301bc01e1SJerin Jacob struct vfio_irq_info irq = {.argsz = sizeof(irq)}; 24d61138d4SHarman Kalra int rc, vfio_dev_fd; 2501bc01e1SJerin Jacob 2601bc01e1SJerin Jacob irq.index = VFIO_PCI_MSIX_IRQ_INDEX; 2701bc01e1SJerin Jacob 28d61138d4SHarman Kalra vfio_dev_fd = plt_intr_dev_fd_get(intr_handle); 29d61138d4SHarman Kalra rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq); 3001bc01e1SJerin Jacob if (rc < 0) { 3101bc01e1SJerin Jacob plt_err("Failed to get IRQ info rc=%d errno=%d", rc, errno); 3201bc01e1SJerin Jacob return rc; 3301bc01e1SJerin Jacob } 3401bc01e1SJerin Jacob 3501bc01e1SJerin Jacob plt_base_dbg("Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x", 3601bc01e1SJerin Jacob irq.flags, irq.index, irq.count, PLT_MAX_RXTX_INTR_VEC_ID); 3701bc01e1SJerin Jacob 3839ac394aSHarman Kalra if (irq.count == 0) { 3901bc01e1SJerin Jacob plt_err("HW max=%d > PLT_MAX_RXTX_INTR_VEC_ID: %d", irq.count, 4001bc01e1SJerin Jacob PLT_MAX_RXTX_INTR_VEC_ID); 41d61138d4SHarman Kalra plt_intr_max_intr_set(intr_handle, PLT_MAX_RXTX_INTR_VEC_ID); 4201bc01e1SJerin Jacob } else { 43d61138d4SHarman Kalra if (plt_intr_max_intr_set(intr_handle, irq.count)) 44d61138d4SHarman Kalra return -1; 4501bc01e1SJerin Jacob } 4601bc01e1SJerin Jacob 4701bc01e1SJerin Jacob return 0; 4801bc01e1SJerin Jacob } 4901bc01e1SJerin Jacob 5001bc01e1SJerin Jacob static int 5101bc01e1SJerin Jacob irq_config(struct plt_intr_handle *intr_handle, unsigned int vec) 5201bc01e1SJerin Jacob { 5301bc01e1SJerin Jacob char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; 5401bc01e1SJerin Jacob struct vfio_irq_set *irq_set; 55d61138d4SHarman Kalra int len, rc, vfio_dev_fd; 5601bc01e1SJerin Jacob int32_t *fd_ptr; 5701bc01e1SJerin Jacob 58d61138d4SHarman Kalra if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) { 5901bc01e1SJerin Jacob plt_err("vector=%d greater than max_intr=%d", vec, 60d61138d4SHarman Kalra plt_intr_max_intr_get(intr_handle)); 6101bc01e1SJerin Jacob return -EINVAL; 6201bc01e1SJerin Jacob } 6301bc01e1SJerin Jacob 6401bc01e1SJerin Jacob len = sizeof(struct vfio_irq_set) + sizeof(int32_t); 6501bc01e1SJerin Jacob 6601bc01e1SJerin Jacob irq_set = (struct vfio_irq_set *)irq_set_buf; 6701bc01e1SJerin Jacob irq_set->argsz = len; 6801bc01e1SJerin Jacob 6901bc01e1SJerin Jacob irq_set->start = vec; 7001bc01e1SJerin Jacob irq_set->count = 1; 7101bc01e1SJerin Jacob irq_set->flags = 7201bc01e1SJerin Jacob VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; 7301bc01e1SJerin Jacob irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; 7401bc01e1SJerin Jacob 7501bc01e1SJerin Jacob /* Use vec fd to set interrupt vectors */ 7601bc01e1SJerin Jacob fd_ptr = (int32_t *)&irq_set->data[0]; 77d61138d4SHarman Kalra fd_ptr[0] = plt_intr_efds_index_get(intr_handle, vec); 7801bc01e1SJerin Jacob 79d61138d4SHarman Kalra vfio_dev_fd = plt_intr_dev_fd_get(intr_handle); 80d61138d4SHarman Kalra rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); 8101bc01e1SJerin Jacob if (rc) 8201bc01e1SJerin Jacob plt_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc); 8301bc01e1SJerin Jacob 8401bc01e1SJerin Jacob return rc; 8501bc01e1SJerin Jacob } 8601bc01e1SJerin Jacob 8701bc01e1SJerin Jacob static int 8801bc01e1SJerin Jacob irq_init(struct plt_intr_handle *intr_handle) 8901bc01e1SJerin Jacob { 9001bc01e1SJerin Jacob char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; 9101bc01e1SJerin Jacob struct vfio_irq_set *irq_set; 92d61138d4SHarman Kalra int len, rc, vfio_dev_fd; 9301bc01e1SJerin Jacob int32_t *fd_ptr; 9401bc01e1SJerin Jacob uint32_t i; 9501bc01e1SJerin Jacob 9601bc01e1SJerin Jacob len = sizeof(struct vfio_irq_set) + 97d61138d4SHarman Kalra sizeof(int32_t) * plt_intr_max_intr_get(intr_handle); 9801bc01e1SJerin Jacob 9901bc01e1SJerin Jacob irq_set = (struct vfio_irq_set *)irq_set_buf; 10001bc01e1SJerin Jacob irq_set->argsz = len; 10101bc01e1SJerin Jacob irq_set->start = 0; 102d61138d4SHarman Kalra irq_set->count = plt_intr_max_intr_get(intr_handle); 10301bc01e1SJerin Jacob irq_set->flags = 10401bc01e1SJerin Jacob VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; 10501bc01e1SJerin Jacob irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; 10601bc01e1SJerin Jacob 10701bc01e1SJerin Jacob fd_ptr = (int32_t *)&irq_set->data[0]; 10801bc01e1SJerin Jacob for (i = 0; i < irq_set->count; i++) 10901bc01e1SJerin Jacob fd_ptr[i] = -1; 11001bc01e1SJerin Jacob 111d61138d4SHarman Kalra vfio_dev_fd = plt_intr_dev_fd_get(intr_handle); 112d61138d4SHarman Kalra rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); 11301bc01e1SJerin Jacob if (rc) 11401bc01e1SJerin Jacob plt_err("Failed to set irqs vector rc=%d", rc); 11501bc01e1SJerin Jacob 11601bc01e1SJerin Jacob return rc; 11701bc01e1SJerin Jacob } 11801bc01e1SJerin Jacob 11901bc01e1SJerin Jacob int 12001bc01e1SJerin Jacob dev_irqs_disable(struct plt_intr_handle *intr_handle) 12101bc01e1SJerin Jacob { 12201bc01e1SJerin Jacob /* Clear max_intr to indicate re-init next time */ 123d61138d4SHarman Kalra plt_intr_max_intr_set(intr_handle, 0); 12401bc01e1SJerin Jacob return plt_intr_disable(intr_handle); 12501bc01e1SJerin Jacob } 12601bc01e1SJerin Jacob 12701bc01e1SJerin Jacob int 128993107f0SShijith Thotton dev_irq_reconfigure(struct plt_intr_handle *intr_handle, uint16_t max_intr) 129993107f0SShijith Thotton { 130993107f0SShijith Thotton /* Disable interrupts if enabled. */ 131993107f0SShijith Thotton if (plt_intr_max_intr_get(intr_handle)) 132993107f0SShijith Thotton dev_irqs_disable(intr_handle); 133993107f0SShijith Thotton 134993107f0SShijith Thotton plt_intr_max_intr_set(intr_handle, max_intr); 135993107f0SShijith Thotton return irq_init(intr_handle); 136993107f0SShijith Thotton } 137993107f0SShijith Thotton 138993107f0SShijith Thotton int 13901bc01e1SJerin Jacob dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb, 14001bc01e1SJerin Jacob void *data, unsigned int vec) 14101bc01e1SJerin Jacob { 142d61138d4SHarman Kalra struct plt_intr_handle *tmp_handle; 143d61138d4SHarman Kalra uint32_t nb_efd, tmp_nb_efd; 144d61138d4SHarman Kalra int rc, fd; 14501bc01e1SJerin Jacob 14601bc01e1SJerin Jacob /* If no max_intr read from VFIO */ 147d61138d4SHarman Kalra if (plt_intr_max_intr_get(intr_handle) == 0) { 14801bc01e1SJerin Jacob irq_get_info(intr_handle); 14901bc01e1SJerin Jacob irq_init(intr_handle); 15001bc01e1SJerin Jacob } 15101bc01e1SJerin Jacob 152d61138d4SHarman Kalra if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) { 153d61138d4SHarman Kalra plt_err("Vector=%d greater than max_intr=%d or ", 154d61138d4SHarman Kalra vec, plt_intr_max_intr_get(intr_handle)); 15501bc01e1SJerin Jacob return -EINVAL; 15601bc01e1SJerin Jacob } 15701bc01e1SJerin Jacob 158d61138d4SHarman Kalra tmp_handle = intr_handle; 15901bc01e1SJerin Jacob /* Create new eventfd for interrupt vector */ 160d61138d4SHarman Kalra fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 161d61138d4SHarman Kalra if (fd == -1) 16201bc01e1SJerin Jacob return -ENODEV; 16301bc01e1SJerin Jacob 164d61138d4SHarman Kalra if (plt_intr_fd_set(tmp_handle, fd)) 165d61138d4SHarman Kalra return -errno; 166d61138d4SHarman Kalra 16701bc01e1SJerin Jacob /* Register vector interrupt callback */ 168d61138d4SHarman Kalra rc = plt_intr_callback_register(tmp_handle, cb, data); 16901bc01e1SJerin Jacob if (rc) { 17001bc01e1SJerin Jacob plt_err("Failed to register vector:0x%x irq callback.", vec); 17101bc01e1SJerin Jacob return rc; 17201bc01e1SJerin Jacob } 17301bc01e1SJerin Jacob 17414f7e5d4SGowrishankar Muthukrishnan rc = plt_intr_efds_index_set(intr_handle, vec, fd); 17514f7e5d4SGowrishankar Muthukrishnan if (rc) 17614f7e5d4SGowrishankar Muthukrishnan return rc; 17714f7e5d4SGowrishankar Muthukrishnan 178d61138d4SHarman Kalra nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ? 179d61138d4SHarman Kalra vec : (uint32_t)plt_intr_nb_efd_get(intr_handle); 180d61138d4SHarman Kalra plt_intr_nb_efd_set(intr_handle, nb_efd); 18101bc01e1SJerin Jacob 182d61138d4SHarman Kalra tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1; 183d61138d4SHarman Kalra if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle)) 184d61138d4SHarman Kalra plt_intr_max_intr_set(intr_handle, tmp_nb_efd); 18501bc01e1SJerin Jacob plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec, 186d61138d4SHarman Kalra plt_intr_nb_efd_get(intr_handle), 187d61138d4SHarman Kalra plt_intr_max_intr_get(intr_handle)); 18801bc01e1SJerin Jacob 18901bc01e1SJerin Jacob /* Enable MSIX vectors to VFIO */ 19001bc01e1SJerin Jacob return irq_config(intr_handle, vec); 19101bc01e1SJerin Jacob } 19201bc01e1SJerin Jacob 19301bc01e1SJerin Jacob void 19401bc01e1SJerin Jacob dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb, 19501bc01e1SJerin Jacob void *data, unsigned int vec) 19601bc01e1SJerin Jacob { 197d61138d4SHarman Kalra struct plt_intr_handle *tmp_handle; 19801bc01e1SJerin Jacob uint8_t retries = 5; /* 5 ms */ 199d61138d4SHarman Kalra int rc, fd; 20001bc01e1SJerin Jacob 201d61138d4SHarman Kalra if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) { 20201bc01e1SJerin Jacob plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec, 203d61138d4SHarman Kalra plt_intr_max_intr_get(intr_handle)); 20401bc01e1SJerin Jacob return; 20501bc01e1SJerin Jacob } 20601bc01e1SJerin Jacob 207d61138d4SHarman Kalra tmp_handle = intr_handle; 208d61138d4SHarman Kalra fd = plt_intr_efds_index_get(intr_handle, vec); 209d61138d4SHarman Kalra if (fd == -1) 210d61138d4SHarman Kalra return; 211d61138d4SHarman Kalra 212d61138d4SHarman Kalra if (plt_intr_fd_set(tmp_handle, fd)) 21301bc01e1SJerin Jacob return; 21401bc01e1SJerin Jacob 21501bc01e1SJerin Jacob do { 21601bc01e1SJerin Jacob /* Un-register callback func from platform lib */ 217d61138d4SHarman Kalra rc = plt_intr_callback_unregister(tmp_handle, cb, data); 21801bc01e1SJerin Jacob /* Retry only if -EAGAIN */ 21901bc01e1SJerin Jacob if (rc != -EAGAIN) 22001bc01e1SJerin Jacob break; 22101bc01e1SJerin Jacob plt_delay_ms(1); 22201bc01e1SJerin Jacob retries--; 22301bc01e1SJerin Jacob } while (retries); 22401bc01e1SJerin Jacob 22501bc01e1SJerin Jacob if (rc < 0) { 22601bc01e1SJerin Jacob plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc); 22701bc01e1SJerin Jacob return; 22801bc01e1SJerin Jacob } 22901bc01e1SJerin Jacob 23001bc01e1SJerin Jacob plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec, 231d61138d4SHarman Kalra plt_intr_nb_efd_get(intr_handle), 232d61138d4SHarman Kalra plt_intr_max_intr_get(intr_handle)); 23301bc01e1SJerin Jacob 234d61138d4SHarman Kalra if (plt_intr_efds_index_get(intr_handle, vec) != -1) 235d61138d4SHarman Kalra close(plt_intr_efds_index_get(intr_handle, vec)); 23601bc01e1SJerin Jacob /* Disable MSIX vectors from VFIO */ 237d61138d4SHarman Kalra plt_intr_efds_index_set(intr_handle, vec, -1); 238d61138d4SHarman Kalra 23901bc01e1SJerin Jacob irq_config(intr_handle, vec); 24001bc01e1SJerin Jacob } 24101bc01e1SJerin Jacob 24201bc01e1SJerin Jacob #else 24301bc01e1SJerin Jacob 24401bc01e1SJerin Jacob int 24501bc01e1SJerin Jacob dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb, 24601bc01e1SJerin Jacob void *data, unsigned int vec) 24701bc01e1SJerin Jacob { 24801bc01e1SJerin Jacob PLT_SET_USED(intr_handle); 24901bc01e1SJerin Jacob PLT_SET_USED(cb); 25001bc01e1SJerin Jacob PLT_SET_USED(data); 25101bc01e1SJerin Jacob PLT_SET_USED(vec); 25201bc01e1SJerin Jacob 25301bc01e1SJerin Jacob return -ENOTSUP; 25401bc01e1SJerin Jacob } 25501bc01e1SJerin Jacob 25601bc01e1SJerin Jacob void 25701bc01e1SJerin Jacob dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb, 25801bc01e1SJerin Jacob void *data, unsigned int vec) 25901bc01e1SJerin Jacob { 26001bc01e1SJerin Jacob PLT_SET_USED(intr_handle); 26101bc01e1SJerin Jacob PLT_SET_USED(cb); 26201bc01e1SJerin Jacob PLT_SET_USED(data); 26301bc01e1SJerin Jacob PLT_SET_USED(vec); 26401bc01e1SJerin Jacob } 26501bc01e1SJerin Jacob 26601bc01e1SJerin Jacob int 26701bc01e1SJerin Jacob dev_irqs_disable(struct plt_intr_handle *intr_handle) 26801bc01e1SJerin Jacob { 26901bc01e1SJerin Jacob PLT_SET_USED(intr_handle); 27001bc01e1SJerin Jacob 27101bc01e1SJerin Jacob return -ENOTSUP; 27201bc01e1SJerin Jacob } 27301bc01e1SJerin Jacob 27401bc01e1SJerin Jacob #endif /* __linux__ */ 275