1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-16 10:20:30 +00:00

Add support for disabling and enabling RX and TX DMA rings in mlx5en(4).

This is useful for supporting setups similar to Netmap.

Sponsored by:	Mellanox Technologies
MFC after:	1 week
This commit is contained in:
Hans Petter Selasky 2017-11-10 14:10:41 +00:00
parent b35a986d25
commit bb3616ab20
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=325659
3 changed files with 189 additions and 0 deletions

View File

@ -408,6 +408,8 @@ struct mlx5e_params {
m(+1, u64 tx_completion_fact_max, "tx_completion_fact_max", "Maximum completion event ratio") \
m(+1, u64 hw_lro, "hw_lro", "set to enable hw_lro") \
m(+1, u64 cqe_zipping, "cqe_zipping", "0 : CQE zipping disabled") \
m(+1, u64 modify_tx_dma, "modify_tx_dma", "0: Enable TX 1: Disable TX") \
m(+1, u64 modify_rx_dma, "modify_rx_dma", "0: Enable RX 1: Disable RX") \
m(+1, u64 diag_pci_enable, "diag_pci_enable", "0: Disabled 1: Enabled") \
m(+1, u64 diag_general_enable, "diag_general_enable", "0: Disabled 1: Enabled")
@ -837,5 +839,8 @@ int mlx5e_enable_sq(struct mlx5e_sq *, struct mlx5e_sq_param *, int tis_num);
int mlx5e_modify_sq(struct mlx5e_sq *, int curr_state, int next_state);
void mlx5e_disable_sq(struct mlx5e_sq *);
void mlx5e_drain_sq(struct mlx5e_sq *);
void mlx5e_modify_tx_dma(struct mlx5e_priv *priv, uint8_t value);
void mlx5e_modify_rx_dma(struct mlx5e_priv *priv, uint8_t value);
void mlx5e_resume_sq(struct mlx5e_sq *sq);
#endif /* _MLX5_EN_H_ */

View File

@ -377,6 +377,32 @@ mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
mlx5e_open_locked(priv->ifp);
break;
case MLX5_PARAM_OFFSET(modify_tx_dma):
/* check if network interface is opened */
if (was_opened) {
priv->params_ethtool.modify_tx_dma =
priv->params_ethtool.modify_tx_dma ? 1 : 0;
/* modify tx according to value */
mlx5e_modify_tx_dma(priv, value != 0);
} else {
/* if closed force enable tx */
priv->params_ethtool.modify_tx_dma = 0;
}
break;
case MLX5_PARAM_OFFSET(modify_rx_dma):
/* check if network interface is opened */
if (was_opened) {
priv->params_ethtool.modify_rx_dma =
priv->params_ethtool.modify_rx_dma ? 1 : 0;
/* modify rx according to value */
mlx5e_modify_rx_dma(priv, value != 0);
} else {
/* if closed force enable rx */
priv->params_ethtool.modify_rx_dma = 0;
}
break;
case MLX5_PARAM_OFFSET(diag_pci_enable):
priv->params_ethtool.diag_pci_enable =
priv->params_ethtool.diag_pci_enable ? 1 : 0;

View File

@ -2927,6 +2927,164 @@ sysctl_firmware(SYSCTL_HANDLER_ARGS)
return (error);
}
static void
mlx5e_disable_tx_dma(struct mlx5e_channel *ch)
{
int i;
for (i = 0; i < ch->num_tc; i++)
mlx5e_drain_sq(&ch->sq[i]);
}
static void
mlx5e_reset_sq_doorbell_record(struct mlx5e_sq *sq)
{
sq->doorbell.d32[0] = cpu_to_be32(MLX5_OPCODE_NOP);
sq->doorbell.d32[1] = cpu_to_be32(sq->sqn << 8);
mlx5e_tx_notify_hw(sq, sq->doorbell.d32, 0);
sq->doorbell.d64 = 0;
}
void
mlx5e_resume_sq(struct mlx5e_sq *sq)
{
int err;
/* check if already enabled */
if (sq->stopped == 0)
return;
err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_ERR,
MLX5_SQC_STATE_RST);
if (err != 0) {
if_printf(sq->ifp,
"mlx5e_modify_sq() from ERR to RST failed: %d\n", err);
}
sq->cc = 0;
sq->pc = 0;
/* reset doorbell prior to moving from RST to RDY */
mlx5e_reset_sq_doorbell_record(sq);
err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST,
MLX5_SQC_STATE_RDY);
if (err != 0) {
if_printf(sq->ifp,
"mlx5e_modify_sq() from RST to RDY failed: %d\n", err);
}
mtx_lock(&sq->lock);
sq->cev_next_state = MLX5E_CEV_STATE_INITIAL;
sq->stopped = 0;
mtx_unlock(&sq->lock);
}
static void
mlx5e_enable_tx_dma(struct mlx5e_channel *ch)
{
int i;
for (i = 0; i < ch->num_tc; i++)
mlx5e_resume_sq(&ch->sq[i]);
}
static void
mlx5e_disable_rx_dma(struct mlx5e_channel *ch)
{
struct mlx5e_rq *rq = &ch->rq;
int err;
mtx_lock(&rq->mtx);
rq->enabled = 0;
callout_stop(&rq->watchdog);
mtx_unlock(&rq->mtx);
callout_drain(&rq->watchdog);
err = mlx5e_modify_rq(rq, MLX5_RQC_STATE_RDY, MLX5_RQC_STATE_ERR);
if (err != 0) {
if_printf(rq->ifp,
"mlx5e_modify_rq() from RDY to RST failed: %d\n", err);
}
while (!mlx5_wq_ll_is_empty(&rq->wq)) {
msleep(1);
rq->cq.mcq.comp(&rq->cq.mcq);
}
/*
* Transitioning into RST state will allow the FW to track less ERR state queues,
* thus reducing the recv queue flushing time
*/
err = mlx5e_modify_rq(rq, MLX5_RQC_STATE_ERR, MLX5_RQC_STATE_RST);
if (err != 0) {
if_printf(rq->ifp,
"mlx5e_modify_rq() from ERR to RST failed: %d\n", err);
}
}
static void
mlx5e_enable_rx_dma(struct mlx5e_channel *ch)
{
struct mlx5e_rq *rq = &ch->rq;
int err;
rq->wq.wqe_ctr = 0;
mlx5_wq_ll_update_db_record(&rq->wq);
err = mlx5e_modify_rq(rq, MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY);
if (err != 0) {
if_printf(rq->ifp,
"mlx5e_modify_rq() from RST to RDY failed: %d\n", err);
}
rq->enabled = 1;
rq->cq.mcq.comp(&rq->cq.mcq);
}
void
mlx5e_modify_tx_dma(struct mlx5e_priv *priv, uint8_t value)
{
int i;
if (priv->channel == NULL)
return;
for (i = 0; i < priv->params.num_channels; i++) {
if (!priv->channel[i])
continue;
if (value)
mlx5e_disable_tx_dma(priv->channel[i]);
else
mlx5e_enable_tx_dma(priv->channel[i]);
}
}
void
mlx5e_modify_rx_dma(struct mlx5e_priv *priv, uint8_t value)
{
int i;
if (priv->channel == NULL)
return;
for (i = 0; i < priv->params.num_channels; i++) {
if (!priv->channel[i])
continue;
if (value)
mlx5e_disable_rx_dma(priv->channel[i]);
else
mlx5e_enable_rx_dma(priv->channel[i]);
}
}
static void
mlx5e_add_hw_stats(struct mlx5e_priv *priv)
{