From: Jie Liu <[email protected]> This patch includes: - MSI-X vector allocation and mapping logic. - Support for rx_queue_intr_enable and rx_queue_intr_disable ops. - Interrupt handler to process admin and queue events. - Integration with EAL interrupt framework.
RX queue interrupts allow applications to use rte_eth_dev_rx_intr_wait() for power-efficient packet processing. Signed-off-by: Jie Liu <[email protected]> --- drivers/common/sxe2/sxe2_ioctl_chnl.c | 177 +++- drivers/common/sxe2/sxe2_ioctl_chnl_func.h | 18 + drivers/net/sxe2/meson.build | 1 + drivers/net/sxe2/sxe2_cmd_chnl.c | 42 + drivers/net/sxe2/sxe2_cmd_chnl.h | 4 + drivers/net/sxe2/sxe2_drv_cmd.h | 8 + drivers/net/sxe2/sxe2_ethdev.c | 93 +- drivers/net/sxe2/sxe2_ethdev.h | 6 + drivers/net/sxe2/sxe2_irq.c | 941 +++++++++++++++++++++ drivers/net/sxe2/sxe2_irq.h | 21 + drivers/net/sxe2/sxe2vf_regs.h | 82 ++ 11 files changed, 1389 insertions(+), 4 deletions(-) create mode 100644 drivers/net/sxe2/sxe2_irq.c create mode 100644 drivers/net/sxe2/sxe2vf_regs.h diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl.c b/drivers/common/sxe2/sxe2_ioctl_chnl.c index 2ffbeb9217..173d8d57ae 100644 --- a/drivers/common/sxe2/sxe2_ioctl_chnl.c +++ b/drivers/common/sxe2/sxe2_ioctl_chnl.c @@ -67,6 +67,7 @@ sxe2_drv_cmd_exec(struct sxe2_common_device *cdev, return ret; } + RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_open) int32_t sxe2_drv_dev_open(struct sxe2_common_device *cdev, struct rte_pci_device *pci_dev) @@ -87,7 +88,7 @@ sxe2_drv_dev_open(struct sxe2_common_device *cdev, struct rte_pci_device *pci_de if (fd < 0) { ret = -EBADF; PMD_LOG_ERR(COM, "Fail to open device:%s, ret=%d, err:%s", - drv_name, ret, strerror(errno)); + drv_name, ret, strerror(errno)); goto l_end; } @@ -159,6 +160,177 @@ sxe2_drv_dev_handshake(struct sxe2_common_device *cdev) return ret; } +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_rxq_irq_set) +int32_t +sxe2_drv_dev_rxq_irq_set(struct sxe2_common_device *cdev, + uint16_t base_irq, int32_t *efd, uint16_t nb_irq) +{ + struct sxe2_ioctl_irq_set cmd_params; + int32_t ret = 0; + int32_t cmd_fd = 0; + + if (cdev->config.kernel_reset) { + ret = -EPERM; + PMD_LOG_WARN(COM, "kernel reset, need restart app."); + goto l_end; + } + + cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev); + if (cmd_fd < 0) { + ret = -EBADF; + PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd); + goto l_end; + } + + PMD_LOG_DEBUG(COM, "Open fd=%d to set rxq irq, base_queue=%d, efds=%p, nb_irq=%d", + cmd_fd, base_irq, efd, nb_irq); + + memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_irq_set)); + cmd_params.base_irq_in_com = base_irq; + cmd_params.cnt = nb_irq; + cmd_params.event_fd = efd; + + pthread_mutex_lock(&cdev->config.lock); + ret = ioctl(cmd_fd, SXE2_COM_CMD_IO_IRQS_REQ, &cmd_params); + if (ret < 0) { + PMD_LOG_ERR(COM, "Failed to set io irqs, fd=%d, ret=%d, err:%s", + cmd_fd, ret, strerror(errno)); + pthread_mutex_unlock(&cdev->config.lock); + goto l_end; + } + pthread_mutex_unlock(&cdev->config.lock); + +l_end: + return ret; +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_other_irq_set) +int32_t +sxe2_drv_dev_other_irq_set(struct sxe2_common_device *cdev, + int32_t efd, uint64_t event) +{ + int32_t ret = 0; + int32_t cmd_fd = 0; + struct sxe2_ioctl_other_evt_set cmd_params; + + if (cdev->config.kernel_reset) { + ret = -EPERM; + PMD_LOG_WARN(COM, "kernel reset, need restart app."); + goto l_end; + } + + cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev); + if (cmd_fd < 0) { + ret = -EBADF; + PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd); + goto l_end; + } + + PMD_LOG_DEBUG(COM, "Open fd=%d to set other irq, efd=%d, event=%"PRIu64"", + cmd_fd, efd, event); + + memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_other_evt_set)); + cmd_params.eventfd = efd; + cmd_params.filter_table = event; + + pthread_mutex_lock(&cdev->config.lock); + ret = ioctl(cmd_fd, SXE2_COM_CMD_EVT_IRQ_REQ, &cmd_params); + if (ret < 0) { + PMD_LOG_ERR(COM, "Failed to set others evt, fd=%d, ret=%d, err:%s", + cmd_fd, ret, strerror(errno)); + ret = -EIO; + pthread_mutex_unlock(&cdev->config.lock); + goto l_end; + } + pthread_mutex_unlock(&cdev->config.lock); + +l_end: + return ret; +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_other_irq_get) +int32_t +sxe2_drv_dev_other_irq_get(struct sxe2_common_device *cdev, uint64_t *event) +{ + int32_t ret = 0; + int32_t cmd_fd = 0; + struct sxe2_ioctl_other_evt_get cmd_params; + + if (cdev->config.kernel_reset) { + ret = -EPERM; + PMD_LOG_WARN(COM, "kernel reset, need restart app."); + goto l_end; + } + + cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev); + if (cmd_fd < 0) { + ret = -EBADF; + PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd); + goto l_end; + } + + PMD_LOG_DEBUG(COM, "Open fd=%d to get other irq", cmd_fd); + + memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_other_evt_get)); + + pthread_mutex_lock(&cdev->config.lock); + ret = ioctl(cmd_fd, SXE2_COM_CMD_EVT_CAUSE_GET, &cmd_params); + if (ret < 0) { + PMD_LOG_ERR(COM, "Failed to set others evt, fd=%d, ret=%d, err:%s", + cmd_fd, ret, strerror(errno)); + ret = -EIO; + pthread_mutex_unlock(&cdev->config.lock); + goto l_end; + } + pthread_mutex_unlock(&cdev->config.lock); + *event = cmd_params.evt_cause; + +l_end: + return ret; +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_reset_irq_set) +int32_t +sxe2_drv_dev_reset_irq_set(struct sxe2_common_device *cdev, int32_t efd) +{ + int32_t ret = 0; + int32_t cmd_fd = 0; + struct sxe2_ioctl_reset_sub_set cmd_params; + + if (cdev->config.kernel_reset) { + ret = -EPERM; + PMD_LOG_WARN(COM, "kernel reset, need restart app."); + goto l_end; + } + + cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev); + if (cmd_fd < 0) { + ret = -EBADF; + PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd); + goto l_end; + } + + PMD_LOG_DEBUG(COM, "Open fd=%d to set reset irq, efd=%d", + cmd_fd, efd); + + memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_reset_sub_set)); + cmd_params.eventfd = efd; + + pthread_mutex_lock(&cdev->config.lock); + ret = ioctl(cmd_fd, SXE2_COM_CMD_RST_IRQ_REQ, &cmd_params); + if (ret < 0) { + PMD_LOG_ERR(COM, "Failed to set reset irqs, fd=%d, ret=%d, err:%s", + cmd_fd, ret, strerror(errno)); + ret = -EIO; + pthread_mutex_unlock(&cdev->config.lock); + goto l_end; + } + pthread_mutex_unlock(&cdev->config.lock); + +l_end: + return ret; +} + RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_mmap) void *sxe2_drv_dev_mmap(struct sxe2_common_device *cdev, uint8_t bar_idx, uint64_t len, uint64_t offset) @@ -223,7 +395,7 @@ sxe2_drv_dev_munmap(struct sxe2_common_device *cdev, void *virt, uint64_t len) RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_dma_map) int32_t sxe2_drv_dev_dma_map(struct sxe2_common_device *cdev, uint64_t vaddr, - uint64_t iova, uint64_t size) + uint64_t iova, uint64_t size) { struct sxe2_ioctl_iommu_dma_map cmd_params; enum rte_iova_mode iova_mode; @@ -322,4 +494,3 @@ sxe2_drv_dev_dma_unmap(struct sxe2_common_device *cdev, uint64_t iova) l_end: return ret; } - diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl_func.h b/drivers/common/sxe2/sxe2_ioctl_chnl_func.h index aed5a5b50d..f29194fc9e 100644 --- a/drivers/common/sxe2/sxe2_ioctl_chnl_func.h +++ b/drivers/common/sxe2/sxe2_ioctl_chnl_func.h @@ -29,6 +29,7 @@ int32_t sxe2_drv_dev_open(struct sxe2_common_device *cdev, struct rte_pci_device *pci_dev); + __rte_internal void sxe2_drv_dev_close(struct sxe2_common_device *cdev); @@ -37,6 +38,23 @@ __rte_internal int32_t sxe2_drv_dev_handshake(struct sxe2_common_device *cdev); +__rte_internal +int32_t +sxe2_drv_dev_rxq_irq_set(struct sxe2_common_device *cdev, uint16_t base_irq, + int32_t *efd, uint16_t nb_irq); + +__rte_internal +int32_t +sxe2_drv_dev_other_irq_set(struct sxe2_common_device *cdev, int32_t efd, uint64_t event); + +__rte_internal +int32_t +sxe2_drv_dev_other_irq_get(struct sxe2_common_device *cdev, uint64_t *event); + +__rte_internal +int32_t +sxe2_drv_dev_reset_irq_set(struct sxe2_common_device *cdev, int32_t fd); + __rte_internal void *sxe2_drv_dev_mmap(struct sxe2_common_device *cdev, uint8_t bar_idx, diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build index d860629def..c73e13bbad 100644 --- a/drivers/net/sxe2/meson.build +++ b/drivers/net/sxe2/meson.build @@ -68,6 +68,7 @@ sources += files( 'sxe2_security.c', 'sxe2_mp.c', 'sxe2_stats.c', + 'sxe2_irq.c', ) allow_internal_get_api = true \ No newline at end of file diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c index a1fc8a50e3..d1f15084ed 100644 --- a/drivers/net/sxe2/sxe2_cmd_chnl.c +++ b/drivers/net/sxe2/sxe2_cmd_chnl.c @@ -348,6 +348,48 @@ int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter) return ret; } +int32_t sxe2_drv_rxq_bind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx, uint16_t msix_idx) +{ + struct sxe2_common_device *cdev = adapter->cdev; + struct sxe2_drv_cmd_params param = {0}; + struct sxe2_drv_queue_irq_bind_req req = {0}; + int32_t ret = 0; + + req.msix_idx = msix_idx; + req.q_idx = rxq_idx; + req.itr_idx = 0; + req.bind = true; + + sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_EVT_IRQ_BAND_RXQ, + &req, sizeof(req), + NULL, 0); + ret = sxe2_drv_cmd_exec(cdev, ¶m); + if (ret) + PMD_DEV_LOG_ERR(adapter, DRV, "rxq bind irq failed, ret=%d", ret); + + return ret; +} + +int32_t sxe2_drv_rxq_unbind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx) +{ + struct sxe2_common_device *cdev = adapter->cdev; + struct sxe2_drv_cmd_params param = {0}; + struct sxe2_drv_queue_irq_bind_req req = {0}; + int32_t ret = 0; + + req.bind = false; + req.q_idx = rxq_idx; + + sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_EVT_IRQ_BAND_RXQ, + &req, sizeof(req), + NULL, 0); + ret = sxe2_drv_cmd_exec(cdev, ¶m); + if (ret) + PMD_DEV_LOG_ERR(adapter, DRV, "rxq unbind irq failed, ret=%d", ret); + + return ret; +} + int32_t sxe2_drv_get_mac_stats(struct sxe2_adapter *adapter) { int32_t ret = 0; diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h index ff73d2f901..c13653e8af 100644 --- a/drivers/net/sxe2/sxe2_cmd_chnl.h +++ b/drivers/net/sxe2/sxe2_cmd_chnl.h @@ -118,4 +118,8 @@ int32_t sxe2_drv_rss_hf_clear(struct sxe2_adapter *adapter); int32_t sxe2_drv_ptp_gettime(struct sxe2_adapter *adapter, struct sxe2_rx_queue *rxq); +int32_t sxe2_drv_rxq_bind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx, uint16_t msix_idx); + +int32_t sxe2_drv_rxq_unbind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx); + #endif /* __SXE2_CMD_CHNL_H__ */ diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h index a88e2b24bf..0b2a715000 100644 --- a/drivers/net/sxe2/sxe2_drv_cmd.h +++ b/drivers/net/sxe2/sxe2_drv_cmd.h @@ -215,6 +215,14 @@ struct sxe2_drv_q_switch_req { uint8_t rsv[2]; }; +struct sxe2_drv_queue_irq_bind_req { + __le16 q_idx; + __le16 msix_idx; + uint8_t itr_idx; + uint8_t bind; + uint8_t rsv[2]; +}; + struct sxe2_drv_vsi_create_req_resp { uint16_t vsi_id; uint16_t vsi_type; diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c index dbe1a2bce1..f3fee74ddf 100644 --- a/drivers/net/sxe2/sxe2_ethdev.c +++ b/drivers/net/sxe2/sxe2_ethdev.c @@ -22,6 +22,7 @@ #include <rte_eal_paging.h> #include "sxe2_ethdev.h" +#include "sxe2_irq.h" #include "sxe2_drv_cmd.h" #include "sxe2_cmd_chnl.h" #include "sxe2_tx.h" @@ -107,6 +108,9 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = { .rx_queue_release = sxe2_rx_queue_release, .tx_queue_setup = sxe2_tx_queue_setup, .tx_queue_release = sxe2_tx_queue_release, + .rx_queue_intr_enable = sxe2_rx_queue_intr_enable, + .rx_queue_intr_disable = sxe2_rx_queue_intr_disable, + .rxq_info_get = sxe2_rx_queue_info_get, .txq_info_get = sxe2_tx_queue_info_get, .rx_burst_mode_get = sxe2_rx_burst_mode_get, @@ -177,6 +181,8 @@ static int32_t sxe2_dev_stop(struct rte_eth_dev *dev) if (adapter->started == 0) goto l_end; + sxe2_rxq_intr_disable(dev); + sxe2_txqs_all_stop(dev); sxe2_rxqs_all_stop(dev); @@ -215,6 +221,12 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev) goto l_end; } + ret = sxe2_rxq_intr_enable(dev); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to enable rx queue intr"); + goto l_rxq_intr_err; + } + ret = sxe2_queues_start(dev); if (ret) { PMD_LOG_ERR(INIT, "enable queues failed"); @@ -224,7 +236,10 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev) dev->data->dev_started = 1; adapter->started = 1; goto l_end; + l_start_queues_err: + (void)sxe2_rxq_intr_disable(dev); +l_rxq_intr_err: (void)sxe2_filter_rule_stop(dev); l_end: return ret; @@ -615,6 +630,8 @@ static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter) sxe2_sw_queue_ctx_hw_cap_set(adapter, &dev_caps.queue_caps); + sxe2_sw_irq_ctx_hw_cap_set(adapter, &dev_caps.msix_caps); + sxe2_sw_rss_ctx_hw_cap_set(adapter, &dev_caps.rss_hash_caps); sxe2_sw_vsi_ctx_hw_cap_set(adapter, &dev_caps.vsi_caps); @@ -636,6 +653,41 @@ static int32_t sxe2_dev_caps_get(struct sxe2_adapter *adapter) return ret; } +uint32_t sxe2_pci_map_read_reg(struct sxe2_adapter *adapter, + enum sxe2_pci_map_resource res_type, uint16_t idx_in_func) +{ + void *reg_addr; + uint32_t value; + + reg_addr = sxe2_pci_map_addr_get(adapter, res_type, idx_in_func); + if (unlikely(reg_addr == NULL)) { + PMD_DEV_LOG_ERR(adapter, DRV, "reg addr:0x%p is error.", reg_addr); + value = SXE2_PCI_MAP_INVALID_VAL; + goto l_ret; + } + + value = SXE2_PCI_REG_READ(reg_addr); + +l_ret: + return value; +} + +void sxe2_pci_map_write_reg(struct sxe2_adapter *adapter, + enum sxe2_pci_map_resource res_type, uint16_t idx_in_func, uint32_t value) +{ + void *reg_addr; + + reg_addr = sxe2_pci_map_addr_get(adapter, res_type, idx_in_func); + if (unlikely(reg_addr == NULL)) { + PMD_DEV_LOG_ERR(adapter, DRV, "reg addr:0x%p is error.", reg_addr); + goto l_ret; + } + + SXE2_PCI_REG_WRITE_WC(reg_addr, value); +l_ret: + return; +} + int32_t sxe2_dev_pci_seg_map(struct sxe2_adapter *adapter, enum sxe2_pci_map_resource res_type, uint64_t org_len, @@ -715,6 +767,27 @@ static int32_t sxe2_hw_init(struct rte_eth_dev *dev) return ret; } +static int32_t sxe2_sw_init(struct rte_eth_dev *dev) +{ + int32_t ret = -1; + + PMD_INIT_FUNC_TRACE(); + + ret = sxe2_sw_irq_ctxt_init(dev); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to sw irq ctxt init, ret=[%d]", ret); + goto l_end; + } + +l_end: + return ret; +} + +static void sxe2_sw_uninit(struct rte_eth_dev *dev) +{ + sxe2_sw_irq_ctxt_uninit(dev); +} + int32_t sxe2_dev_pci_res_seg_map(struct sxe2_adapter *adapter, uint32_t res_type, uint32_t item_cnt, @@ -1065,6 +1138,18 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev, goto init_dev_info_err; } + ret = sxe2_sw_init(dev); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to initialize sw parameters, ret=[%d]", ret); + goto init_sw_err; + } + + ret = sxe2_intr_init(dev); + if (ret != 0) { + PMD_LOG_ERR(INIT, "Failed to initialize interrupt, ret:%d", ret); + goto init_irq_err; + } + ret = sxe2_eth_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize eth parameters, ret=%d", ret); @@ -1109,6 +1194,10 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev, init_rss_err: sxe2_security_uinit(dev); init_security_err: + sxe2_intr_uninit(dev); +init_irq_err: + sxe2_sw_uninit(dev); +init_sw_err: sxe2_eth_uinit(dev); init_eth_err: init_dev_info_err: @@ -1132,8 +1221,10 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev) (void)sxe2_sched_uinit(dev); sxe2_vsi_uninit(dev); sxe2_security_uinit(dev); - sxe2_dev_pci_map_uinit(dev); + sxe2_intr_uninit(dev); + sxe2_sw_uninit(dev); sxe2_eth_uinit(dev); + sxe2_dev_pci_map_uinit(dev); l_end: return 0; diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h index 32a67ed344..65ada44c12 100644 --- a/drivers/net/sxe2/sxe2_ethdev.h +++ b/drivers/net/sxe2/sxe2_ethdev.h @@ -354,6 +354,12 @@ int32_t sxe2_dev_pci_res_seg_map(struct sxe2_adapter *adapter, uint32_t item_cnt, uint32_t item_base); +void sxe2_pci_map_write_reg(struct sxe2_adapter *adapter, + enum sxe2_pci_map_resource res_type, uint16_t idx_in_func, uint32_t value); + +uint32_t sxe2_pci_map_read_reg(struct sxe2_adapter *adapter, + enum sxe2_pci_map_resource res_type, uint16_t idx_in_func); + void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type); int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev); diff --git a/drivers/net/sxe2/sxe2_irq.c b/drivers/net/sxe2/sxe2_irq.c new file mode 100644 index 0000000000..13619500ea --- /dev/null +++ b/drivers/net/sxe2/sxe2_irq.c @@ -0,0 +1,941 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd. + */ + +#include <stdint.h> +#include <sys/eventfd.h> +#include <unistd.h> +#include <ethdev_pci.h> +#include <ethdev_driver.h> +#include <rte_alarm.h> +#include <fcntl.h> +#include <rte_stdatomic.h> + +#include "sxe2_ethdev.h" +#include "sxe2_irq.h" +#include "sxe2_common_log.h" +#include "sxe2_queue.h" +#include "sxe2_drv_cmd.h" +#include "sxe2_ioctl_chnl_func.h" +#include "sxe2vf_regs.h" +#include "sxe2_host_regs.h" +#include "sxe2_cmd_chnl.h" + +#define SXE2_INT_EVENT_OICR_ALL (SXE2_PF_INT_OICR_SWINT | \ + SXE2_PF_INT_OICR_LAN_TX_ERR | \ + SXE2_PF_INT_OICR_LAN_RX_ERR | \ + SXE2_PF_INT_OICR_FW) + +#define MAX_EVENT_PENDING (16) + +struct sxe2_event_element { + TAILQ_ENTRY(sxe2_event_element) next; + struct rte_eth_dev *dev; +}; + +struct sxe2_event_handler { + RTE_ATOMIC(uint16_t)ndev; + rte_thread_t tid; + int32_t fd[2]; + rte_spinlock_t lock; + TAILQ_HEAD(event_list, sxe2_event_element) pending; +}; +static struct sxe2_event_handler event_handler = { + .fd = {-1, -1}, +}; +static volatile int32_t event_thread_run; + + +static void sxe2_event_irq_common_handler(struct sxe2_adapter *adapter, uint64_t oicr) +{ + struct rte_eth_dev *dev = &rte_eth_devices[adapter->dev_info.dev_data->port_id]; + + if (oicr & RTE_BIT32(SXE2_COM_EC_LINK_CHG)) { + PMD_DEV_LOG_INFO(adapter, DRV, "OICR=%" PRIu64, oicr); + (void)sxe2_drv_mac_link_status_get(adapter); + if (rte_eal_process_type() == RTE_PROC_PRIMARY) + rte_eth_dev_callback_process(dev, + RTE_ETH_EVENT_INTR_LSC, + NULL); + } +} + +static uint32_t sxe2_event_intr_handle(void *param __rte_unused) +{ + struct sxe2_event_handler *handler = &event_handler; + struct sxe2_adapter *adapter; + struct sxe2_event_element *pos; + struct sxe2_event_element *tmp; + int32_t ret = 0; + uint64_t oicr = 0; + TAILQ_HEAD(event_list, sxe2_event_element) pending; + int8_t unused[MAX_EVENT_PENDING]; + ssize_t nr; + + while (event_thread_run) { + nr = read(handler->fd[0], &unused, sizeof(unused)); + if (nr <= 0) + break; + + rte_spinlock_lock(&handler->lock); + TAILQ_INIT(&pending); + TAILQ_CONCAT(&pending, &handler->pending, next); + rte_spinlock_unlock(&handler->lock); + + TAILQ_FOREACH_SAFE(pos, &pending, next, tmp) { + TAILQ_REMOVE(&pending, pos, next); + adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(pos->dev); + + ret = sxe2_drv_dev_other_irq_get(adapter->cdev, &oicr); + sxe2_event_irq_common_handler(adapter, oicr); + + rte_free(pos); + } + } + + return ret; +} + +static int32_t sxe2_event_intr_handler_init(void) +{ + struct sxe2_event_handler *handler = &event_handler; + int32_t ret = 0; + int err = 0; + + PMD_INIT_FUNC_TRACE(); + if (rte_atomic_fetch_add_explicit(&handler->ndev, 1, rte_memory_order_acq_rel) >= 1) { + ret = 0; + PMD_LOG_DEBUG(INIT, "%s: ndev > 1", __func__); + goto l_end; + } + +#if defined(RTE_EXEC_ENV_IS_WINDOWS) && RTE_EXEC_ENV_IS_WINDOWS != 0 + err = _pipe(handler->fd, MAX_EVENT_PENDING, O_BINARY); +#else + err = pipe(handler->fd); +#endif + if (err != 0) { + ret = -ECHILD; + rte_atomic_fetch_sub_explicit(&handler->ndev, 1, rte_memory_order_release); + PMD_LOG_ERR(INIT, "%s: pipe failed", __func__); + goto l_end; + } + + event_thread_run = 1; + + TAILQ_INIT(&handler->pending); + rte_spinlock_init(&handler->lock); + + if (rte_thread_create_internal_control(&handler->tid, "sxe2-event", + sxe2_event_intr_handle, NULL)) { + PMD_LOG_ERR(INIT, "%s: thread create failed", __func__); + rte_atomic_fetch_sub_explicit(&handler->ndev, 1, rte_memory_order_release); + ret = -ECHILD; + goto l_end; + } + ret = 0; +l_end: + return ret; +} + +static void sxe2_event_intr_handler_uinit(void) +{ + struct sxe2_event_handler *handler = &event_handler; + struct sxe2_event_element *pos; + struct sxe2_event_element *tmp; + ssize_t nw = 0; + int8_t notify_byte = 0; + + PMD_INIT_FUNC_TRACE(); + if (rte_atomic_fetch_sub_explicit(&handler->ndev, 1, rte_memory_order_acq_rel) > 1) { + PMD_LOG_DEBUG(INIT, "event handler uinit, ndev > 0"); + return; + } + + event_thread_run = 0; + nw = write(handler->fd[1], ¬ify_byte, 1); + RTE_SET_USED(nw); + + (void)rte_thread_join(handler->tid, NULL); + + if (handler->fd[0] != -1) { + close(handler->fd[0]); + handler->fd[0] = -1; + } + if (handler->fd[1] != -1) { + close(handler->fd[1]); + handler->fd[1] = -1; + } + + rte_spinlock_lock(&handler->lock); + TAILQ_FOREACH_SAFE(pos, &handler->pending, next, tmp) { + TAILQ_REMOVE(&handler->pending, pos, next); + rte_free(pos); + } + rte_spinlock_unlock(&handler->lock); +} + +static void sxe2_event_intr_post(struct rte_eth_dev *dev) +{ + struct sxe2_event_handler *handler = &event_handler; + struct sxe2_event_element *elem = rte_malloc(NULL, sizeof(struct sxe2_event_element), 0); + int8_t notify_byte = 0; + ssize_t nw = 0; + + if (!elem) + goto l_end; + + elem->dev = dev; + + rte_spinlock_lock(&handler->lock); + TAILQ_INSERT_TAIL(&handler->pending, elem, next); + rte_spinlock_unlock(&handler->lock); + + nw = write(handler->fd[1], ¬ify_byte, 1); + RTE_SET_USED(nw); + +l_end: + return; +} + +static void sxe2_interrupt_handler_other(void *arg) +{ + struct rte_eth_dev *dev = (struct rte_eth_dev *)arg; + struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + int32_t eventfd = adapter->irq_ctxt.other_event_fd; + int32_t ret = 0; + uint64_t buf = 0; + + ret = read(eventfd, &buf, sizeof(buf)); + if (ret != sizeof(buf)) { + PMD_DEV_LOG_ERR(adapter, DRV, "read eventfd[%d] failed, ret:%d, errno:%d.", + eventfd, ret, errno); + } + + sxe2_event_intr_post(dev); +} + +static void sxe2_interrupt_handler_reset(void *arg) +{ + struct rte_eth_dev *dev = (struct rte_eth_dev *)arg; + struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + int32_t resetfd = adapter->irq_ctxt.reset_event_fd; + int32_t ret = 0; + uint64_t buf = 0; + + ret = read(resetfd, &buf, sizeof(buf)); + if (ret != sizeof(buf)) { + PMD_DEV_LOG_ERR(adapter, DRV, "read resetfd[%d] failed, ret:%d, errno:%d.", + resetfd, ret, errno); + } + + sxe2_drv_cmd_close(adapter->cdev); + + rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RMV, NULL); +} + +int32_t sxe2_sw_irq_ctxt_init(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + int32_t ret = 0; + + irq_ctxt->rxq_avail_cnt = irq_ctxt->max_cnt_hw; + irq_ctxt->rxq_base_idx_in_pf = irq_ctxt->base_idx_in_func; + irq_ctxt->reset_event_fd = -1; + irq_ctxt->other_event_fd = -1; + + return ret; +} + +void sxe2_sw_irq_ctxt_uninit(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + + memset(&adapter->irq_ctxt, 0, sizeof(adapter->irq_ctxt)); + adapter->irq_ctxt.reset_event_fd = -1; + adapter->irq_ctxt.other_event_fd = -1; +} + +void sxe2_sw_irq_ctx_hw_cap_set(struct sxe2_adapter *adapter, + struct sxe2_drv_msix_caps *msix_caps) +{ + adapter->irq_ctxt.max_cnt_hw = msix_caps->msix_vectors_cnt; + adapter->irq_ctxt.base_idx_in_func = msix_caps->base_idx_in_func; +} + +static int32_t sxe2_intr_handler_cfg(struct rte_intr_handle *handle, + int32_t fd, rte_intr_callback_fn cb, void *cb_arg) +{ + int32_t ret = 0; + + ret = rte_intr_fd_set(handle, fd); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to set intr_handle->fd, error %i (%s)", + errno, strerror(errno)); + goto err; + } + + ret = rte_intr_type_set(handle, RTE_INTR_HANDLE_EXT); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to set intr_handle->type, error %i (%s)", + errno, strerror(errno)); + goto err; + } + + ret = rte_intr_callback_register(handle, cb, cb_arg); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to initialize register intr callback, ret=%d", ret); + goto err; + } +err: + return ret; +} + +static struct rte_intr_handle * +sxe2_intr_handler_create(int32_t fd, rte_intr_callback_fn cb, void *cb_arg) +{ + struct rte_intr_handle *tmp_intr_handle = NULL; + int32_t ret = 0; + + tmp_intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE); + if (!tmp_intr_handle) { + PMD_LOG_ERR(INIT, "Failed to alloc memory for intr_handler, error %i (%s)", + errno, strerror(errno)); + goto err; + } + + ret = rte_intr_fd_set(tmp_intr_handle, fd); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to set intr_handle->fd, error %i (%s)", + errno, strerror(errno)); + goto err; + } + + ret = rte_intr_type_set(tmp_intr_handle, RTE_INTR_HANDLE_EXT); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to set intr_handle->type, error %i (%s)", + errno, strerror(errno)); + goto err; + } + + ret = rte_intr_callback_register(tmp_intr_handle, cb, cb_arg); + if (ret) { + PMD_LOG_ERR(INIT, "Failed to initialize register intr callback, ret=%d", ret); + goto err; + } + + return tmp_intr_handle; +err: + rte_intr_instance_free(tmp_intr_handle); + return NULL; +} + +static void sxe2_intr_handler_destroy(struct rte_intr_handle *intr_handle, + rte_intr_callback_fn cb, void *cb_arg) +{ + if (!intr_handle) + return; + + if (rte_intr_fd_get(intr_handle) >= 0) + (void)rte_intr_callback_unregister(intr_handle, cb, cb_arg); + rte_intr_instance_free(intr_handle); +} + +static int32_t sxe2_event_intr_fd_create(void) +{ + int32_t fd = 0; + + fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (fd < 0) { + PMD_LOG_ERR(INIT, "Can't setup eventfd, error %i (%s)", + errno, strerror(errno)); + goto err; + } + + return fd; +err: + return -EBADF; +} + +static void sxe2_event_intr_fd_destroy(int32_t fd) +{ + if (fd >= 0) + close(fd); +} + +static int32_t sxe2_other_intr_register(struct rte_eth_dev *dev, int32_t fd) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + int32_t ret = 0; + uint64_t event = RTE_BIT32(SXE2_COM_EC_LINK_CHG) | + RTE_BIT32(SXE2_COM_SW_MODE_LEGACY) | + RTE_BIT32(SXE2_COM_SW_MODE_SWITCHDEV) | + RTE_BIT32(SXE2_COM_FC_ST_CHANGE); + + ret = sxe2_drv_dev_other_irq_set(adapter->cdev, fd, event); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set other irq, ret=%d", ret); + goto l_end; + } + +l_end: + return ret; +} + +static void sxe2_other_intr_unregister(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + int32_t ret = 0; + + ret = sxe2_drv_dev_other_irq_set(adapter->cdev, -1, 0); + if (ret) + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set other irq, ret=%d", ret); +} + +static int32_t sxe2_reset_intr_register(struct rte_eth_dev *dev, int32_t fd) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + int32_t ret = 0; + + ret = sxe2_drv_dev_reset_irq_set(adapter->cdev, fd); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set reset irq, ret=%d", ret); + goto l_end; + } + +l_end: + return ret; +} + +static void sxe2_reset_intr_unregister(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + int32_t ret = 0; + + ret = sxe2_drv_dev_reset_irq_set(adapter->cdev, -1); + if (ret) + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set reset irq, ret=%d", ret); +} + +int32_t sxe2_intr_init(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct rte_pci_device *pci_dev = SXE2_DEV_TO_PCI(dev); + struct rte_intr_handle *reset_handle = NULL; + int32_t ofd = -1; + int32_t rfd = -1; + int32_t ret = 0; + + PMD_INIT_FUNC_TRACE(); + + ofd = sxe2_event_intr_fd_create(); + if (ofd < 0) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to create event intr fd"); + ret = -EBADF; + goto l_end; + } + + ret = sxe2_intr_handler_cfg(pci_dev->intr_handle, + ofd, sxe2_interrupt_handler_other, dev); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to create intr handler"); + goto l_err_create_other_handler; + } + + ret = sxe2_event_intr_handler_init(); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Event handler init failed, ret=%d", ret); + goto l_err_event_intr_handler_init; + } + + ret = sxe2_other_intr_register(dev, ofd); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to register other intr, ret=%d", ret); + goto l_err_register_other_intr; + } + adapter->irq_ctxt.other_event_fd = ofd; + + rfd = sxe2_event_intr_fd_create(); + if (rfd < 0) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to create event intr fd"); + ret = -EBADF; + goto l_err_create_reset_fd; + } + + reset_handle = sxe2_intr_handler_create(rfd, sxe2_interrupt_handler_reset, dev); + if (!reset_handle) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to create intr handler"); + ret = -ENOMEM; + goto l_err_create_reset_handler; + } + adapter->irq_ctxt.reset_handle = reset_handle; + + ret = sxe2_reset_intr_register(dev, rfd); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to register reset intr, ret=%d", ret); + goto l_err_register_reset_intr; + } + adapter->irq_ctxt.reset_event_fd = rfd; + + goto l_end; +l_err_register_reset_intr: + sxe2_intr_handler_destroy(reset_handle, sxe2_interrupt_handler_reset, dev); + adapter->irq_ctxt.reset_handle = NULL; +l_err_create_reset_handler: + sxe2_event_intr_fd_destroy(rfd); +l_err_create_reset_fd: + sxe2_other_intr_unregister(dev); + adapter->irq_ctxt.other_event_fd = -1; +l_err_register_other_intr: + sxe2_event_intr_handler_uinit(); +l_err_event_intr_handler_init: + sxe2_intr_handler_destroy(pci_dev->intr_handle, + sxe2_interrupt_handler_other, dev); + pci_dev->intr_handle = NULL; +l_err_create_other_handler: + sxe2_event_intr_fd_destroy(ofd); +l_end: + return ret; +} + +void sxe2_intr_uninit(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct rte_pci_device *pci_dev = SXE2_DEV_TO_PCI(dev); + + sxe2_reset_intr_unregister(dev); + sxe2_intr_handler_destroy(adapter->irq_ctxt.reset_handle, + sxe2_interrupt_handler_reset, dev); + sxe2_event_intr_fd_destroy(adapter->irq_ctxt.reset_event_fd); + sxe2_other_intr_unregister(dev); + sxe2_event_intr_handler_uinit(); + sxe2_intr_handler_destroy(pci_dev->intr_handle, + sxe2_interrupt_handler_other, dev); + sxe2_event_intr_fd_destroy(adapter->irq_ctxt.other_event_fd); + + adapter->irq_ctxt.other_event_fd = -1; + adapter->irq_ctxt.reset_event_fd = -1; + pci_dev->intr_handle = NULL; + adapter->irq_ctxt.reset_handle = NULL; +} + +static int32_t sxe2_rxq_intr_efd_alloc(struct rte_eth_dev *dev, int32_t *efd) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + int32_t ret = 0; + int32_t fd = 0; + + fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (fd < 0) { + PMD_DEV_LOG_ERR(adapter, INIT, "Can't setup eventfd, error %i (%s)", + errno, strerror(errno)); + ret = -EBADF; + goto l_end; + } + + *efd = fd; + +l_end: + return ret; +} + +static void sxe2_rxq_intr_efd_free(int32_t efd) +{ + close(efd); +} + +static void sxe2_pci_hw_int_itr_set(struct sxe2_adapter *adapter, uint16_t msix_idx, uint16_t itr) +{ + sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_ITR, msix_idx, itr); +} + +static void sxe2_pci_hw_irq_disable(struct sxe2_adapter *adapter, uint16_t irq_idx) +{ + uint32_t value = (SXE2_ITR_IDX_NONE << SXE2_VF_DYN_CTL_ITR_IDX_S); + + sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx, value); +} + +static void sxe2_pci_hw_irq_enable(struct sxe2_adapter *adapter, uint16_t irq_idx) +{ + uint32_t value = SXE2_VF_DYN_CTL_INTENABLE | + SXE2_VF_DYN_CTL_CLEARPBA | + (SXE2_ITR_IDX_NONE << SXE2_VF_DYN_CTL_ITR_IDX_S); + + sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx, value); +} + +static uint32_t sxe2_pci_hw_irq_dyn_ctl_read(struct sxe2_adapter *adapter, uint16_t irq_idx) +{ + return sxe2_pci_map_read_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx); +} + +static void sxe2_pci_hw_msix_disable(struct sxe2_adapter *adapter, uint16_t irq_idx) +{ + sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_MSIX, + irq_idx, SXE2VF_BAR4_MSIX_DISABLE); +} + +static void sxe2_pci_hw_msix_enable(struct sxe2_adapter *adapter, uint16_t irq_idx) +{ + sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_MSIX, + irq_idx, SXE2VF_BAR4_MSIX_ENABLE); +} + +static void sxe2_pci_hw_irq_trigger(struct sxe2_adapter *adapter, uint16_t irq_idx) +{ + sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx, + (SXE2VF_ITR_IDX_NONE << SXE2VF_DYN_CTL_ITR_IDX_SHIFT) | + SXE2VF_DYN_CTL_SWINT_TRIG | SXE2VF_DYN_CTL_INTENABLE_MSK); +} + +static void sxe2_pci_hw_irq_clear_pba(struct sxe2_adapter *adapter, uint16_t irq_idx) +{ + sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx, + (SXE2VF_ITR_IDX_NONE << SXE2VF_DYN_CTL_ITR_IDX_SHIFT) | + SXE2VF_DYN_CTL_CLEARPBA | SXE2VF_DYN_CTL_INTENABLE_MSK); +} + +static void sxe2_rxq_msix_cfg_unmap(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + uint16_t rxq_cnt = adapter->q_ctxt.qp_cnt_assign; + uint16_t i = 0; + + for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++) + sxe2_pci_hw_irq_disable(adapter, irq_ctxt->rxq_msix_idx[i]); + + for (i = 0; i < rxq_cnt; i++) + (void)sxe2_drv_rxq_unbind_irq(adapter, i); +} + +static int32_t sxe2_rxq_msix_cfg_map(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + int32_t ret = 0; + uint32_t val; + uint16_t rxq_cnt = dev->data->nb_rx_queues; + uint16_t i = 0; + uint8_t rx_low_latency = adapter->devargs.rx_low_latency; + + for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++) { + sxe2_pci_hw_irq_disable(adapter, irq_ctxt->rxq_msix_idx[i]); + if (rx_low_latency) { + sxe2_pci_hw_int_itr_set(adapter, irq_ctxt->rxq_msix_idx[i], + SXE2_ITR_INTERVAL_LOW); + } else { + sxe2_pci_hw_int_itr_set(adapter, irq_ctxt->rxq_msix_idx[i], + SXE2_ITR_INTERVAL_NORMAL); + } + } + + for (i = 0; i < rxq_cnt; i++) { + ret = sxe2_drv_rxq_bind_irq(adapter, i, irq_ctxt->rxq_msix_idx[i]); + if (ret != 0) { + PMD_DEV_LOG_ERR(adapter, INIT, "RXQ[%u] bind IRQ[%u] failed.", + i, irq_ctxt->rxq_msix_idx[i]); + goto l_end; + } + } + + for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++) + sxe2_pci_hw_irq_enable(adapter, irq_ctxt->rxq_msix_idx[i]); + + for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++) { + val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, i); + if ((val & SXE2VF_DYN_CTL_INTENABLE) == 0) + continue; + + sxe2_pci_hw_msix_disable(adapter, i); + sxe2_pci_hw_irq_trigger(adapter, i); + val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, i); + sxe2_pci_hw_irq_clear_pba(adapter, i); + val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, i); + sxe2_pci_hw_msix_enable(adapter, i); + } + +l_end: + if (ret != 0) + sxe2_rxq_msix_cfg_unmap(dev); + return ret; +} + +static int32_t sxe2_rxq_map_msix_intr(struct rte_eth_dev *dev, + uint16_t msix_base __rte_unused, uint16_t nb_msix, + uint16_t base_queue, uint16_t nb_queue) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + uint32_t *msix_tbl = NULL; + int32_t ret = 0; + uint16_t i; + + if (!nb_queue || !nb_msix || nb_queue < nb_msix) { + PMD_DEV_LOG_ERR(adapter, INIT, "Queue num[%u] or msix num[%u] is invalid.", + nb_queue, nb_msix); + ret = -EINVAL; + goto l_end; + } + + msix_tbl = rte_zmalloc(NULL, sizeof(uint32_t) * nb_queue, 0); + if (!msix_tbl) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to alloc msix_tbl memory."); + ret = -ENOMEM; + goto l_end; + } + for (i = 0; i < nb_queue; i++) { + msix_tbl[i] = i % nb_msix; + PMD_DEV_LOG_INFO(adapter, INIT, "Queue %u is binding to vect %u", + base_queue + i, msix_tbl[i]); + } + + irq_ctxt->rxq_irq_cnt = nb_msix; + irq_ctxt->rxq_msix_idx = msix_tbl; + +l_end: + return ret; +} + +static void sxe2_rxq_unmap_msix_intr(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + + rte_free(irq_ctxt->rxq_msix_idx); + irq_ctxt->rxq_msix_idx = NULL; + irq_ctxt->rxq_irq_cnt = 0; +} + +static int32_t sxe2_rxq_intr_register(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + struct rte_intr_handle *intr_handle = dev->intr_handle; + int32_t *efd_tbl = NULL; + uint16_t rxq_cnt = dev->data->nb_rx_queues; + uint16_t nb_msix = irq_ctxt->rxq_irq_cnt; + uint16_t i; + int32_t ret = 0; + + if (rte_intr_type_set(intr_handle, RTE_INTR_HANDLE_EXT)) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set intr_handle->type, error %i (%s)", + errno, strerror(errno)); + ret = -EPERM; + goto l_end; + } + + efd_tbl = rte_zmalloc(NULL, sizeof(int32_t) * nb_msix, 0); + if (!efd_tbl) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to alloc efd_tbl memory."); + ret = -ENOMEM; + goto l_end; + } + + for (i = 0; i < nb_msix; i++) { + ret = sxe2_rxq_intr_efd_alloc(dev, &efd_tbl[i]); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to alloc efd_tbl, ret=%d", ret); + goto l_free_efd_tbl; + } + } + + if (rte_intr_vec_list_alloc(intr_handle, "sxe2 rxq int", rxq_cnt)) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to allocate %d rx_queues intr_vec", + rxq_cnt); + ret = -ENOMEM; + goto l_free_efd_tbl; + } + + for (i = 0; i < rxq_cnt; i++) { + ret = rte_intr_vec_list_index_set(intr_handle, i, + irq_ctxt->rxq_msix_idx[i] + RTE_INTR_VEC_RXTX_OFFSET); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set msix_tbl, ret=%d", ret); + goto l_free_efd_tbl; + } + } + + for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++) { + ret = rte_intr_efds_index_set(intr_handle, i, efd_tbl[i]); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set efd_tbl, ret=%d", ret); + goto l_free_efd_tbl; + } + } + + if (rte_intr_nb_efd_set(intr_handle, rxq_cnt)) { + PMD_DEV_LOG_ERR(adapter, INIT, "Set intr nb efd failed, error %i (%s)", + errno, strerror(errno)); + ret = -EPERM; + goto l_free_efd_tbl; + } + + ret = sxe2_drv_dev_rxq_irq_set(adapter->cdev, 0, efd_tbl, nb_msix); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set rxq irq, ret=%d", ret); + goto l_free_efd_tbl; + } + irq_ctxt->rxq_event_fd = efd_tbl; + + goto l_end; + +l_free_efd_tbl: + if (efd_tbl) { + for (i = 0; i < nb_msix; i++) + if (efd_tbl[i] >= 0) + sxe2_rxq_intr_efd_free(efd_tbl[i]); + rte_free(efd_tbl); + } + irq_ctxt->rxq_event_fd = NULL; + + rte_intr_vec_list_free(intr_handle); +l_end: + return ret; +} + +static void sxe2_rxq_intr_unregister(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + struct rte_intr_handle *intr_handle = dev->intr_handle; + int32_t efd = -1; + uint16_t msix_cnt = irq_ctxt->rxq_irq_cnt; + uint16_t i; + + if (irq_ctxt->rxq_event_fd) { + for (i = 0; i < msix_cnt; i++) { + (void)sxe2_drv_dev_rxq_irq_set(adapter->cdev, i, &efd, 1); + sxe2_rxq_intr_efd_free(irq_ctxt->rxq_event_fd[i]); + } + } + rte_free(irq_ctxt->rxq_event_fd); + irq_ctxt->rxq_event_fd = NULL; + + rte_intr_vec_list_free(intr_handle); + + rte_intr_nb_efd_set(intr_handle, 0); + rte_intr_max_intr_set(intr_handle, 0); +} + +int32_t sxe2_rxq_intr_enable(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + uint16_t msix_vect = adapter->irq_ctxt.rxq_base_idx_in_pf; + uint16_t msix_cnt = adapter->irq_ctxt.rxq_avail_cnt; + uint16_t rxq_cnt = dev->data->nb_rx_queues; + uint16_t rxq_base = adapter->q_ctxt.base_idx_in_pf; + int32_t ret = 0; + + if (!rxq_cnt) + goto l_end; + + msix_cnt = RTE_MIN(msix_cnt, rxq_cnt); + + ret = sxe2_rxq_map_msix_intr(dev, msix_vect, msix_cnt, rxq_base, rxq_cnt); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to rxq[%d] map msix[%d] intr, cnt=%d, ret=%d", + rxq_base, msix_vect, rxq_cnt, ret); + goto l_end; + } + + if (dev->data->dev_conf.intr_conf.rxq) { + ret = sxe2_rxq_intr_register(dev); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to register rxq[%d] intr, ret=%d", + rxq_base, ret); + goto l_err_unmap; + } + } + + ret = sxe2_rxq_msix_cfg_map(dev); + if (ret) { + PMD_DEV_LOG_ERR(adapter, INIT, "Failed to rxq[%d] map msix[%d] intr, ret=%d", + rxq_base, msix_vect, ret); + goto l_err_unregister; + } + + goto l_end; +l_err_unregister: + if (dev->data->dev_conf.intr_conf.rxq) + sxe2_rxq_intr_unregister(dev); +l_err_unmap: + sxe2_rxq_unmap_msix_intr(dev); +l_end: + return ret; +} + +void sxe2_rxq_intr_disable(struct rte_eth_dev *dev) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + + if (!irq_ctxt->rxq_irq_cnt) + goto l_end; + + sxe2_rxq_msix_cfg_unmap(dev); + + if (dev->data->dev_conf.intr_conf.rxq) + sxe2_rxq_intr_unregister(dev); + + sxe2_rxq_unmap_msix_intr(dev); + +l_end: + return; +} + +int32_t sxe2_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt; + uint64_t buf; + uint16_t irq_idx = irq_ctxt->rxq_msix_idx[queue_id]; + size_t read_ret; + + read_ret = read(irq_ctxt->rxq_event_fd[irq_idx], &buf, sizeof(buf)); + (void)read_ret; + sxe2_pci_hw_irq_enable(adapter, irq_idx); + return 0; +} + +int32_t sxe2_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id) +{ + struct sxe2_adapter *adapter = + SXE2_DEV_PRIVATE_TO_ADAPTER(dev); + uint32_t val; + int32_t ret = 0; + uint16_t irq_idx = adapter->irq_ctxt.rxq_msix_idx[queue_id]; + + val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, irq_idx); + if ((val & SXE2VF_DYN_CTL_INTENABLE) == 0) { + PMD_DEV_LOG_DEBUG(adapter, INIT, "rxq [%d] interrupt is disabled.", queue_id); + goto l_end; + } + + sxe2_pci_hw_msix_disable(adapter, irq_idx); + sxe2_pci_hw_irq_trigger(adapter, irq_idx); + val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, irq_idx); + sxe2_pci_hw_irq_clear_pba(adapter, irq_idx); + val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, irq_idx); + sxe2_pci_hw_msix_enable(adapter, irq_idx); +l_end: + return ret; +} diff --git a/drivers/net/sxe2/sxe2_irq.h b/drivers/net/sxe2/sxe2_irq.h index bb96c6d842..c898c16f84 100644 --- a/drivers/net/sxe2/sxe2_irq.h +++ b/drivers/net/sxe2/sxe2_irq.h @@ -45,4 +45,25 @@ struct sxe2_irq_context { int32_t *rxq_event_fd; }; +uint32_t sxe2_drv_dev_other_cause_get(struct sxe2_adapter *adapter); + +int32_t sxe2_intr_init(struct rte_eth_dev *dev); + +void sxe2_intr_uninit(struct rte_eth_dev *dev); + +int32_t sxe2_sw_irq_ctxt_init(struct rte_eth_dev *dev); + +void sxe2_sw_irq_ctxt_uninit(struct rte_eth_dev *dev); + +void sxe2_sw_irq_ctx_hw_cap_set(struct sxe2_adapter *adapter, + struct sxe2_drv_msix_caps *msix_caps); + +int32_t sxe2_rxq_intr_enable(struct rte_eth_dev *dev); + +void sxe2_rxq_intr_disable(struct rte_eth_dev *dev); + +int32_t sxe2_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id); + +int32_t sxe2_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id); + #endif /* __SXE2_IRQ_H__ */ diff --git a/drivers/net/sxe2/sxe2vf_regs.h b/drivers/net/sxe2/sxe2vf_regs.h new file mode 100644 index 0000000000..503c7ce04f --- /dev/null +++ b/drivers/net/sxe2/sxe2vf_regs.h @@ -0,0 +1,82 @@ + +#ifndef __SXE2VF_REGS_H__ +#define __SXE2VF_REGS_H__ + +#define SXE2VF_MBX_Q_LEN_M 0x3FF +#define SXE2VF_MBX_Q_LEN_VFE_M RTE_BIT32(28) + +#define SXE2VF_MBX_Q_LEN_OVFL_M RTE_BIT32(29) +#define SXE2VF_MBX_Q_LEN_CRIT_M RTE_BIT32(30) +#define SXE2VF_MBX_Q_LEN_ENA_M RTE_BIT32(31) + +#define SXE2VF_MBX_RQ_HEAD (0x00008000) +#define SXE2VF_MBX_RQ_TAIL (0x00008400) +#define SXE2VF_MBX_RQ_LEN (0x00007C00) +#define SXE2VF_MBX_RQ_BAH (0x00007800) +#define SXE2VF_MBX_RQ_BAL (0x00007400) + +#define SXE2VF_MBX_TQ_HEAD (0x00006C00) +#define SXE2VF_MBX_TQ_TAIL (0x00007000) +#define SXE2VF_MBX_TQ_LEN (0x00006800) +#define SXE2VF_MBX_TQ_BAH (0x00006400) +#define SXE2VF_MBX_TQ_BAL (0x00006000) + +#define SXE2VF_RXQ_TAIL(_QRX) (0x2000 + ((_QRX) * 4)) +#define SXE2VF_TXQ_TAIL(_QRX) (0x1000 + ((_QRX) * 4)) + +#define SXE2VF_INT_BASE 0x00002800 + +#define SXE2VF_DYN_CTL0 (SXE2VF_INT_BASE + 0x0) + +#define SXE2VF_DYN_CTL(_idx) (SXE2VF_INT_BASE + 0x4 + ((_idx) * 4)) +#define SXE2VF_VF_DYN_CTL(_idx) (SXE2VF_INT_BASE + ((_idx) * 4)) + +#define SXE2VF_BAR4_MSIX_BASE 0 +#define SXE2VF_BAR4_MSIX_CTL(_idx) (SXE2VF_BAR4_MSIX_BASE + 0xC + ((_idx) * 0x10)) +#define SXE2VF_BAR4_MSIX_ENABLE 0 +#define SXE2VF_BAR4_MSIX_DISABLE 1 + +#define SXE2VF_DYN_CTL_INTENABLE RTE_BIT32(0) +#define SXE2VF_DYN_CTL_CLEARPBA RTE_BIT32(1) +#define SXE2VF_DYN_CTL_SWINT_TRIG RTE_BIT32(2) +#define SXE2VF_DYN_CTL_SW_ITR_IDX_ENABLE RTE_BIT32(24) + +#define SXE2VF_DYN_CTL_INTENABLE_MSK \ + RTE_BIT32(31) + +#define SXE2VF_DYN_CTL_ITR_IDX_SHIFT 3 + +enum sxe2vf_itr_idx { + SXE2VF_ITR_IDX_0 = 0, + SXE2VF_ITR_IDX_1, + SXE2VF_ITR_IDX_2, + SXE2VF_ITR_IDX_NONE, +}; + +#define SXE2VF_INT_ITR0 (0x00002800 + 65 * 0x4) +#define SXE2VF_INT_ITR(_i, _irq_idx) (SXE2VF_INT_ITR0 + \ + 0x4 + (_i) * 0x104 + ((_irq_idx) * 4)) +#define SXE2VF_VF_INT_ITR(_itr_idx, _irq_idx) (0x00002800 + \ + (0x104 * (_itr_idx)) + ((_irq_idx) * 4)) +#define SXE2VF_PFG_INT_CTL_ITR_GRAN_0 (2) + +#define SXE2VF_PCIE_SYS_READY 0x38c +#define SXE2VF_PCIE_SYS_READY_CORER_ASSERT RTE_BIT32(0) +#define SXE2VF_PCIE_SYS_READY_STOP_DROP_DONE RTE_BIT32(2) +#define SXE2VF_PCIE_SYS_READY_R5 RTE_BIT32(3) +#define SXE2VF_PCIE_SYS_READY_STOP_DROP RTE_BIT32(16) + +#define SXE2VF_PCIE_DEV_CTRL_DEV_STATUS 0x78 +#define SXE2VF_PCIE_DEV_CTRL_DEV_STATUS_TRANS_PENDING RTE_BIT32(21) + +#define SXE2VF_VF_VRC_VFGEN_RSTAT (0x5800) +#define SXE2VF_VF_VRC_VFGEN_VFRSTAT GENMASK(1, 0) +#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_VFR (0) +#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_COMPLETE (RTE_BIT32(0)) +#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_VF_ACTIVE (RTE_BIT32(1)) + +#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_FORVF_VFR (1) +#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_FORVF_MASK \ + (RTE_BIT32(10)) + +#endif /* SXE2VF_VF_INT_ITR */ -- 2.47.3

