;
[Features]
Link status = Y
+Rx interrupt = Y
MTU update = Y
Jumbo frame = Y
Promiscuous mode = Y
;
[Features]
Link status = Y
+Rx interrupt = Y
MTU update = Y
Jumbo frame = Y
Unicast MAC filter = Y
- Port hardware statistics
- Jumbo frames
- Link state information
+- Interrupt mode for RX
- VLAN stripping
- NUMA support
A new API has been added to wait for a memory location to be updated with a
16-bit, 32-bit, 64-bit value.
+* **Updated Hisilicon hns3 driver.**
+
+ Updated Hisilicon hns3 driver with new features and improvements, including:
+
+ * Added support for Rx interrupt.
+
* **Updated Mellanox mlx5 driver.**
Updated Mellanox mlx5 driver with new features and improvements, including:
/* SFP command */
HNS3_OPC_SFP_GET_SPEED = 0x7104,
+ /* Interrupts commands */
+ HNS3_OPC_ADD_RING_TO_VECTOR = 0x1503,
+ HNS3_OPC_DEL_RING_TO_VECTOR = 0x1504,
+
/* Error INT commands */
HNS3_QUERY_MSIX_INT_STS_BD_NUM = 0x1513,
HNS3_QUERY_CLEAR_ALL_MPF_MSIX_INT = 0x1514,
uint8_t rsv[18];
};
+#define HNS3_RING_TYPE_B 0
+#define HNS3_RING_TYPE_TX 0
+#define HNS3_RING_TYPE_RX 1
+#define HNS3_RING_GL_IDX_S 0
+#define HNS3_RING_GL_IDX_M GENMASK(1, 0)
+#define HNS3_RING_GL_RX 0
+#define HNS3_RING_GL_TX 1
+
+#define HNS3_VECTOR_ELEMENTS_PER_CMD 10
+
+#define HNS3_INT_TYPE_S 0
+#define HNS3_INT_TYPE_M GENMASK(1, 0)
+#define HNS3_TQP_ID_S 2
+#define HNS3_TQP_ID_M GENMASK(12, 2)
+#define HNS3_INT_GL_IDX_S 13
+#define HNS3_INT_GL_IDX_M GENMASK(14, 13)
+struct hns3_ctrl_vector_chain_cmd {
+ uint8_t int_vector_id;
+ uint8_t int_cause_num;
+ uint16_t tqp_type_and_id[HNS3_VECTOR_ELEMENTS_PER_CMD];
+ uint8_t vfid;
+ uint8_t rsv;
+};
+
struct hns3_config_max_frm_size_cmd {
uint16_t max_frm_size;
uint8_t min_frm_size;
return hns3_check_mq_mode(dev);
}
+static int
+hns3_bind_ring_with_vector(struct rte_eth_dev *dev, uint8_t vector_id,
+ bool mmap, uint16_t queue_id)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_cmd_desc desc;
+ struct hns3_ctrl_vector_chain_cmd *req =
+ (struct hns3_ctrl_vector_chain_cmd *)desc.data;
+ enum hns3_cmd_status status;
+ enum hns3_opcode_type op;
+ uint16_t tqp_type_and_id = 0;
+
+ op = mmap ? HNS3_OPC_ADD_RING_TO_VECTOR : HNS3_OPC_DEL_RING_TO_VECTOR;
+ hns3_cmd_setup_basic_desc(&desc, op, false);
+ req->int_vector_id = vector_id;
+
+ hns3_set_field(tqp_type_and_id, HNS3_INT_TYPE_M, HNS3_INT_TYPE_S,
+ HNS3_RING_TYPE_RX);
+ hns3_set_field(tqp_type_and_id, HNS3_TQP_ID_M, HNS3_TQP_ID_S, queue_id);
+ hns3_set_field(tqp_type_and_id, HNS3_INT_GL_IDX_M, HNS3_INT_GL_IDX_S,
+ HNS3_RING_GL_RX);
+ req->tqp_type_and_id[0] = rte_cpu_to_le_16(tqp_type_and_id);
+
+ req->int_cause_num = 1;
+ status = hns3_cmd_send(hw, &desc, 1);
+ if (status) {
+ hns3_err(hw, "Map TQP %d fail, vector_id is %d, status is %d.",
+ queue_id, vector_id, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
static int
hns3_dev_configure(struct rte_eth_dev *dev)
{
}
static int
-hns3_dev_start(struct rte_eth_dev *eth_dev)
+hns3_map_rx_interrupt(struct rte_eth_dev *dev)
{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint32_t intr_vector;
+ uint8_t base = 0;
+ uint8_t vec = 0;
+ uint16_t q_id;
int ret;
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ /* disable uio/vfio intr/eventfd mapping */
+ rte_intr_disable(intr_handle);
+
+ /* check and configure queue intr-vector mapping */
+ if (rte_intr_cap_multiple(intr_handle) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) {
+ intr_vector = dev->data->nb_rx_queues;
+ /* creates event fd for each intr vector when MSIX is used */
+ if (rte_intr_efd_enable(intr_handle, intr_vector))
+ return -EINVAL;
+ }
+ if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int), 0);
+ if (intr_handle->intr_vec == NULL) {
+ hns3_err(hw, "Failed to allocate %d rx_queues"
+ " intr_vec", dev->data->nb_rx_queues);
+ ret = -ENOMEM;
+ goto alloc_intr_vec_error;
+ }
+ }
+
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < dev->data->nb_rx_queues; q_id++) {
+ ret = hns3_bind_ring_with_vector(dev, vec, true, q_id);
+ if (ret)
+ goto bind_vector_error;
+ intr_handle->intr_vec[q_id] = vec;
+ if (vec < base + intr_handle->nb_efd - 1)
+ vec++;
+ }
+ }
+ rte_intr_enable(intr_handle);
+ return 0;
+
+bind_vector_error:
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
+ return ret;
+alloc_intr_vec_error:
+ rte_intr_efd_disable(intr_handle);
+ return ret;
+}
+
+static int
+hns3_dev_start(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret = 0;
+
PMD_INIT_FUNC_TRACE();
if (rte_atomic16_read(&hw->reset.resetting))
return -EBUSY;
+
rte_spinlock_lock(&hw->lock);
hw->adapter_state = HNS3_NIC_STARTING;
hw->adapter_state = HNS3_NIC_STARTED;
rte_spinlock_unlock(&hw->lock);
- hns3_set_rxtx_function(eth_dev);
- hns3_mp_req_start_rxtx(eth_dev);
+
+ ret = hns3_map_rx_interrupt(dev);
+ if (ret)
+ return ret;
+ hns3_set_rxtx_function(dev);
+ hns3_mp_req_start_rxtx(dev);
hns3_info(hw, "hns3 dev start successful!");
return 0;
}
static void
-hns3_dev_stop(struct rte_eth_dev *eth_dev)
+hns3_unmap_rx_interrupt(struct rte_eth_dev *dev)
{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ uint8_t base = 0;
+ uint8_t vec = 0;
+ uint16_t q_id;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return;
+
+ /* unmap the ring with vector */
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < dev->data->nb_rx_queues; q_id++) {
+ (void)hns3_bind_ring_with_vector(dev, vec, false, q_id);
+ if (vec < base + intr_handle->nb_efd - 1)
+ vec++;
+ }
+ }
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
+}
+
+static void
+hns3_dev_stop(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
PMD_INIT_FUNC_TRACE();
hw->adapter_state = HNS3_NIC_STOPPING;
- hns3_set_rxtx_function(eth_dev);
+ hns3_set_rxtx_function(dev);
rte_wmb();
/* Disable datapath on secondary process. */
- hns3_mp_req_stop_rxtx(eth_dev);
+ hns3_mp_req_stop_rxtx(dev);
/* Prevent crashes when queues are still in use. */
rte_delay_ms(hw->tqps_num);
hw->adapter_state = HNS3_NIC_CONFIGURED;
}
rte_spinlock_unlock(&hw->lock);
+ hns3_unmap_rx_interrupt(dev);
}
static void
.tx_queue_setup = hns3_tx_queue_setup,
.rx_queue_release = hns3_dev_rx_queue_release,
.tx_queue_release = hns3_dev_tx_queue_release,
+ .rx_queue_intr_enable = hns3_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = hns3_dev_rx_queue_intr_disable,
.dev_configure = hns3_dev_configure,
.flow_ctrl_get = hns3_flow_ctrl_get,
.flow_ctrl_set = hns3_flow_ctrl_set,
hw->io_base = NULL;
}
+static int
+hns3vf_bind_ring_with_vector(struct rte_eth_dev *dev, uint8_t vector_id,
+ bool mmap, uint16_t queue_id)
+
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_vf_bind_vector_msg bind_msg;
+ uint16_t code;
+ int ret;
+
+ memset(&bind_msg, 0, sizeof(bind_msg));
+ code = mmap ? HNS3_MBX_MAP_RING_TO_VECTOR :
+ HNS3_MBX_UNMAP_RING_TO_VECTOR;
+ bind_msg.vector_id = vector_id;
+ bind_msg.ring_num = 1;
+ bind_msg.param[0].ring_type = HNS3_RING_TYPE_RX;
+ bind_msg.param[0].tqp_index = queue_id;
+ bind_msg.param[0].int_gl_index = HNS3_RING_GL_RX;
+
+ ret = hns3_send_mbx_msg(hw, code, 0, (uint8_t *)&bind_msg,
+ sizeof(bind_msg), false, NULL, 0);
+ if (ret) {
+ hns3_err(hw, "Map TQP %d fail, vector_id is %d, ret is %d.",
+ queue_id, vector_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int
hns3vf_do_stop(struct hns3_adapter *hns)
{
}
static void
-hns3vf_dev_stop(struct rte_eth_dev *eth_dev)
+hns3vf_unmap_rx_interrupt(struct rte_eth_dev *dev)
{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ uint8_t base = 0;
+ uint8_t vec = 0;
+ uint16_t q_id;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return;
+
+ /* unmap the ring with vector */
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < dev->data->nb_rx_queues; q_id++) {
+ (void)hns3vf_bind_ring_with_vector(dev, vec, false,
+ q_id);
+ if (vec < base + intr_handle->nb_efd - 1)
+ vec++;
+ }
+ }
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
+}
+
+static void
+hns3vf_dev_stop(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
PMD_INIT_FUNC_TRACE();
hw->adapter_state = HNS3_NIC_STOPPING;
- hns3_set_rxtx_function(eth_dev);
+ hns3_set_rxtx_function(dev);
rte_wmb();
/* Disable datapath on secondary process. */
- hns3_mp_req_stop_rxtx(eth_dev);
+ hns3_mp_req_stop_rxtx(dev);
/* Prevent crashes when queues are still in use. */
rte_delay_ms(hw->tqps_num);
hns3_dev_release_mbufs(hns);
hw->adapter_state = HNS3_NIC_CONFIGURED;
}
- rte_eal_alarm_cancel(hns3vf_service_handler, eth_dev);
+ rte_eal_alarm_cancel(hns3vf_service_handler, dev);
rte_spinlock_unlock(&hw->lock);
+
+ hns3vf_unmap_rx_interrupt(dev);
}
static void
}
static int
-hns3vf_dev_start(struct rte_eth_dev *eth_dev)
+hns3vf_map_rx_interrupt(struct rte_eth_dev *dev)
{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint32_t intr_vector;
+ uint8_t base = 0;
+ uint8_t vec = 0;
+ uint16_t q_id;
int ret;
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ /* disable uio/vfio intr/eventfd mapping */
+ rte_intr_disable(intr_handle);
+
+ /* check and configure queue intr-vector mapping */
+ if (rte_intr_cap_multiple(intr_handle) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) {
+ intr_vector = dev->data->nb_rx_queues;
+ /* It creates event fd for each intr vector when MSIX is used */
+ if (rte_intr_efd_enable(intr_handle, intr_vector))
+ return -EINVAL;
+ }
+ if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int), 0);
+ if (intr_handle->intr_vec == NULL) {
+ hns3_err(hw, "Failed to allocate %d rx_queues"
+ " intr_vec", dev->data->nb_rx_queues);
+ ret = -ENOMEM;
+ goto vf_alloc_intr_vec_error;
+ }
+ }
+
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < dev->data->nb_rx_queues; q_id++) {
+ ret = hns3vf_bind_ring_with_vector(dev, vec, true,
+ q_id);
+ if (ret)
+ goto vf_bind_vector_error;
+ intr_handle->intr_vec[q_id] = vec;
+ if (vec < base + intr_handle->nb_efd - 1)
+ vec++;
+ }
+ }
+ rte_intr_enable(intr_handle);
+ return 0;
+
+vf_bind_vector_error:
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
+ return ret;
+vf_alloc_intr_vec_error:
+ rte_intr_efd_disable(intr_handle);
+ return ret;
+}
+
+static int
+hns3vf_dev_start(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret = 0;
+
PMD_INIT_FUNC_TRACE();
if (rte_atomic16_read(&hw->reset.resetting))
return -EBUSY;
+
rte_spinlock_lock(&hw->lock);
hw->adapter_state = HNS3_NIC_STARTING;
ret = hns3vf_do_start(hns, true);
}
hw->adapter_state = HNS3_NIC_STARTED;
rte_spinlock_unlock(&hw->lock);
- hns3_set_rxtx_function(eth_dev);
- hns3_mp_req_start_rxtx(eth_dev);
- rte_eal_alarm_set(HNS3VF_SERVICE_INTERVAL, hns3vf_service_handler,
- eth_dev);
- return 0;
+
+ ret = hns3vf_map_rx_interrupt(dev);
+ if (ret)
+ return ret;
+ hns3_set_rxtx_function(dev);
+ hns3_mp_req_start_rxtx(dev);
+ rte_eal_alarm_set(HNS3VF_SERVICE_INTERVAL, hns3vf_service_handler, dev);
+ return ret;
}
static bool
.tx_queue_setup = hns3_tx_queue_setup,
.rx_queue_release = hns3_dev_rx_queue_release,
.tx_queue_release = hns3_dev_tx_queue_release,
+ .rx_queue_intr_enable = hns3_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = hns3_dev_rx_queue_intr_disable,
.dev_configure = hns3vf_dev_configure,
.mac_addr_add = hns3vf_add_mac_addr,
.mac_addr_remove = hns3vf_remove_mac_addr,
uint16_t msg[8];
};
+struct hns3_ring_chain_param {
+ uint8_t ring_type;
+ uint8_t tqp_index;
+ uint8_t int_gl_index;
+};
+
+#define HNS3_MBX_MAX_RING_CHAIN_PARAM_NUM 4
+struct hns3_vf_bind_vector_msg {
+ uint8_t vector_id;
+ uint8_t ring_num;
+ struct hns3_ring_chain_param param[HNS3_MBX_MAX_RING_CHAIN_PARAM_NUM];
+};
+
struct hns3_vf_rst_cmd {
uint8_t dest_vfid;
uint8_t vf_rst;
#define HNS3_RING_EN_B 0
+#define HNS3_VECTOR_REG_OFFSET 0x4
+#define HNS3_VECTOR_VF_OFFSET 0x100000
+
#define HNS3_TQP_REG_OFFSET 0x80000
#define HNS3_TQP_REG_SIZE 0x200
return 0;
}
+void
+hns3_tqp_intr_enable(struct hns3_hw *hw, uint16_t tpq_int_num, bool en)
+{
+ uint32_t addr, value;
+
+ addr = HNS3_TQP_INTR_CTRL_REG + tpq_int_num * HNS3_VECTOR_REG_OFFSET;
+ value = en ? 1 : 0;
+
+ hns3_write_dev(hw, addr, value);
+}
+
+int
+hns3_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return -ENOTSUP;
+
+ /* enable the vectors */
+ hns3_tqp_intr_enable(hw, queue_id, true);
+
+ return rte_intr_ack(intr_handle);
+}
+
+int
+hns3_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return -ENOTSUP;
+
+ /* disable the vectors */
+ hns3_tqp_intr_enable(hw, queue_id, false);
+
+ return 0;
+}
+
static int
hns3_dev_rx_queue_start(struct hns3_adapter *hns, uint16_t idx)
{
void hns3_dev_tx_queue_release(void *queue);
void hns3_free_all_queues(struct rte_eth_dev *dev);
int hns3_reset_all_queues(struct hns3_adapter *hns);
+int hns3_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
+int hns3_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);
int hns3_start_queues(struct hns3_adapter *hns, bool reset_queue);
int hns3_stop_queues(struct hns3_adapter *hns, bool reset_queue);
void hns3_dev_release_mbufs(struct hns3_adapter *hns);
uint16_t nb_pkts);
const uint32_t *hns3_dev_supported_ptypes_get(struct rte_eth_dev *dev);
void hns3_set_rxtx_function(struct rte_eth_dev *eth_dev);
+void hns3_tqp_intr_enable(struct hns3_hw *hw, uint16_t tpq_int_num, bool en);
#endif /* _HNS3_RXTX_H_ */