/* set up interrupt support (but not enable interrupts) */ static int pci_vfio_setup_interrupts(struct rte_pci_device *dev, int vfio_dev_fd) { int i, ret, intr_idx; /* default to invalid index */ intr_idx = VFIO_PCI_NUM_IRQS; /* get interrupt type from internal config (MSI-X by default, can be * overriden from the command line */ switch (internal_config.vfio_intr_mode) { case RTE_INTR_MODE_MSIX: intr_idx = VFIO_PCI_MSIX_IRQ_INDEX; break; case RTE_INTR_MODE_MSI: intr_idx = VFIO_PCI_MSI_IRQ_INDEX; break; case RTE_INTR_MODE_LEGACY: intr_idx = VFIO_PCI_INTX_IRQ_INDEX; break; /* don't do anything if we want to automatically determine interrupt type */ case RTE_INTR_MODE_NONE: break; default: RTE_LOG(ERR, EAL, " unknown default interrupt type! "); return -1; } /* start from MSI-X interrupt type */ for (i = VFIO_PCI_MSIX_IRQ_INDEX; i >= 0; i--) { struct vfio_irq_info irq = { .argsz = sizeof(irq) }; int fd = -1; /* skip interrupt modes we don't want */ if (internal_config.vfio_intr_mode != RTE_INTR_MODE_NONE && i != intr_idx) continue; irq.index = i; ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq); if (ret < 0) { RTE_LOG(ERR, EAL, " cannot get IRQ info, " "error %i (%s) ", errno, strerror(errno)); return -1; } /* if this vector cannot be used with eventfd, fail if we explicitly * specified interrupt type, otherwise continue */ if ((irq.flags & VFIO_IRQ_INFO_EVENTFD) == 0) { if (internal_config.vfio_intr_mode != RTE_INTR_MODE_NONE) { RTE_LOG(ERR, EAL, " interrupt vector does not support eventfd! "); return -1; } else continue; } /* set up an eventfd for interrupts */ fd = eventfd(0, 0); if (fd < 0) { RTE_LOG(ERR, EAL, " cannot set up eventfd, " "error %i (%s) ", errno, strerror(errno)); return -1; } dev->intr_handle.fd = fd; dev->intr_handle.vfio_dev_fd = vfio_dev_fd; switch (i) { case VFIO_PCI_MSIX_IRQ_INDEX: internal_config.vfio_intr_mode = RTE_INTR_MODE_MSIX; dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_MSIX; break; case VFIO_PCI_MSI_IRQ_INDEX: internal_config.vfio_intr_mode = RTE_INTR_MODE_MSI; dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_MSI; break; case VFIO_PCI_INTX_IRQ_INDEX: internal_config.vfio_intr_mode = RTE_INTR_MODE_LEGACY; dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_LEGACY; break; default: RTE_LOG(ERR, EAL, " unknown interrupt type! "); return -1; } return 0; } /* if we're here, we haven't found a suitable interrupt vector */ return -1; }
// 查询eventfd的支持情况 ioctl(s->device, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) // 将eventfd的fd传递到内核态 *irq_set = (struct vfio_irq_set) { .argsz = irq_set_size, .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER, .index = irq_info.index, .start = 0, .count = 1, }; *(int *)&irq_set->data = event_notifier_get_fd(e); r = ioctl(s->device, VFIO_DEVICE_SET_IRQS, irq_set);
static int uio_intr_enable(const struct rte_intr_handle *intr_handle) { const int value = 1; if (write(intr_handle->fd, &value, sizeof(value)) < 0) { RTE_LOG(ERR, EAL, "Error enabling interrupts for fd %d (%s) ", intr_handle->fd, strerror(errno)); return -1; } return 0; }
ixgbe_configure_msix(struct rte_eth_dev *dev) /* set up to autoclear timer, and the vectors */ mask = IXGBE_EIMS_ENABLE_MASK; mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_MAILBOX | IXGBE_EIMS_LSC); IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); static int ixgbe_dev_start(struct rte_eth_dev *dev) { /* confiugre msix for sleep until rx interrupt */ ixgbe_configure_msix(dev); /* initialize transmission unit */ ixgbe_dev_tx_init(dev); /* This can fail when allocating mbufs for descriptor rings */ err = ixgbe_dev_rx_init(dev);
static struct rte_pci_driver rte_ixgbe_pmd = { .id_table = pci_id_ixgbe_map, .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, .probe = eth_ixgbe_pci_probe, .remove = eth_ixgbe_pci_remove, } eth_ixgbe_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, struct rte_pci_device *pci_dev) { retval = rte_eth_dev_create(&pci_dev->device, pci_dev->device.name, sizeof(struct ixgbe_adapter), eth_dev_pci_specific_init, pci_dev, eth_ixgbe_dev_init, NULL);
eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) { /* enable uio/vfio intr/eventfd mapping */ rte_intr_enable(intr_handle); /* enable support intr */ ixgbe_enable_intr(eth_dev); }
static inline void ixgbe_enable_intr(struct rte_eth_dev *dev) { struct ixgbe_interrupt *intr = IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); IXGBE_WRITE_REG(hw, IXGBE_EIMS, intr->mask); IXGBE_WRITE_FLUSH(hw); }