net/hns3: support Rx interrupt

This patch adds supports of receive packets through interrupt mode for
hns3 PF/VF driver. The following ops functions should be implemented
defined in the struct eth_dev_ops:
rx_queue_intr_enable
rx_queue_intr_disable

Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
This commit is contained in:
Hao Chen 2019-12-21 18:32:45 +08:00 committed by Ferruh Yigit
parent 4f19f4140e
commit 02a7b55657
11 changed files with 399 additions and 22 deletions

View File

@ -5,6 +5,7 @@
;
[Features]
Link status = Y
Rx interrupt = Y
MTU update = Y
Jumbo frame = Y
Promiscuous mode = Y

View File

@ -5,6 +5,7 @@
;
[Features]
Link status = Y
Rx interrupt = Y
MTU update = Y
Jumbo frame = Y
Unicast MAC filter = Y

View File

@ -22,6 +22,7 @@ Features of the HNS3 PMD are:
- Port hardware statistics
- Jumbo frames
- Link state information
- Interrupt mode for RX
- VLAN stripping
- NUMA support

View File

@ -61,6 +61,12 @@ New Features
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:

View File

@ -209,6 +209,10 @@ enum hns3_opcode_type {
/* 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,
@ -673,6 +677,30 @@ struct hns3_tqp_map_cmd {
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;

View File

@ -2021,6 +2021,40 @@ hns3_check_dcb_cfg(struct rte_eth_dev *dev)
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)
{
@ -4020,15 +4054,83 @@ err_config_mac_mode:
}
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;
@ -4041,8 +4143,12 @@ hns3_dev_start(struct rte_eth_dev *eth_dev)
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;
@ -4070,18 +4176,50 @@ hns3_do_stop(struct hns3_adapter *hns)
}
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);
@ -4092,6 +4230,7 @@ hns3_dev_stop(struct rte_eth_dev *eth_dev)
hw->adapter_state = HNS3_NIC_CONFIGURED;
}
rte_spinlock_unlock(&hw->lock);
hns3_unmap_rx_interrupt(dev);
}
static void
@ -4748,6 +4887,8 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.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,

View File

@ -1208,6 +1208,36 @@ hns3vf_uninit_vf(struct rte_eth_dev *eth_dev)
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)
{
@ -1225,18 +1255,51 @@ 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);
@ -1246,8 +1309,10 @@ hns3vf_dev_stop(struct rte_eth_dev *eth_dev)
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
@ -1329,15 +1394,84 @@ hns3vf_do_start(struct hns3_adapter *hns, bool reset_queue)
}
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);
@ -1348,11 +1482,14 @@ hns3vf_dev_start(struct rte_eth_dev *eth_dev)
}
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
@ -1685,6 +1822,8 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.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,

View File

@ -104,6 +104,19 @@ struct hns3_mbx_pf_to_vf_cmd {
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;

View File

@ -83,6 +83,9 @@
#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

View File

@ -395,6 +395,47 @@ hns3_reset_all_queues(struct hns3_adapter *hns)
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)
{

View File

@ -295,6 +295,8 @@ void hns3_dev_rx_queue_release(void *queue);
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);
@ -311,4 +313,5 @@ uint16_t hns3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
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_ */