Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/mlx5e: Add recovery flow for tx devlink health reporter for unhealthy PTP SQ

A new check for the tx devlink health reporter is introduced for
determining when the PTP port timestamping SQ is considered unhealthy. If
there are enough CQEs considered never to be delivered, the space that can
be utilized on the SQ decreases significantly, impacting performance and
usability of the SQ. The health reporter is triggered when the number of
likely never delivered port timestamping CQEs that utilize the space of the
PTP SQ is greater than 93.75% of the total capacity of the SQ. A devlink
health reporter recover method is also provided for this specific TX error
context that restarts the PTP SQ.

Signed-off-by: Rahul Rameshbabu <rrameshbabu@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>

authored by

Rahul Rameshbabu and committed by
Saeed Mahameed
53b836a4 3178308a

+94 -1
+4 -1
Documentation/networking/devlink/mlx5.rst
··· 135 135 136 136 tx reporter 137 137 ----------- 138 - The tx reporter is responsible for reporting and recovering of the following two error scenarios: 138 + The tx reporter is responsible for reporting and recovering of the following three error scenarios: 139 139 140 140 - tx timeout 141 141 Report on kernel tx timeout detection. ··· 143 143 - tx error completion 144 144 Report on error tx completion. 145 145 Recover by flushing the tx queue and reset it. 146 + - tx PTP port timestamping CQ unhealthy 147 + Report too many CQEs never delivered on port ts CQ. 148 + Recover by flushing and re-creating all PTP channels. 146 149 147 150 tx reporter also support on demand diagnose callback, on which it provides 148 151 real time information of its send queues status.
+1
drivers/net/ethernet/mellanox/mlx5/core/en/health.h
··· 18 18 void mlx5e_reporter_tx_destroy(struct mlx5e_priv *priv); 19 19 void mlx5e_reporter_tx_err_cqe(struct mlx5e_txqsq *sq); 20 20 int mlx5e_reporter_tx_timeout(struct mlx5e_txqsq *sq); 21 + void mlx5e_reporter_tx_ptpsq_unhealthy(struct mlx5e_ptpsq *ptpsq); 21 22 22 23 int mlx5e_health_cq_diag_fmsg(struct mlx5e_cq *cq, struct devlink_fmsg *fmsg); 23 24 int mlx5e_health_cq_common_diag_fmsg(struct mlx5e_cq *cq, struct devlink_fmsg *fmsg);
+22
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
··· 2 2 // Copyright (c) 2020 Mellanox Technologies 3 3 4 4 #include "en/ptp.h" 5 + #include "en/health.h" 5 6 #include "en/txrx.h" 6 7 #include "en/params.h" 7 8 #include "en/fs_tt_redirect.h" ··· 141 140 return skb; 142 141 } 143 142 143 + static bool mlx5e_ptp_metadata_map_unhealthy(struct mlx5e_ptp_metadata_map *map) 144 + { 145 + /* Considered beginning unhealthy state if size * 15 / 2^4 cannot be reclaimed. */ 146 + return map->undelivered_counter > (map->capacity >> 4) * 15; 147 + } 148 + 144 149 static void mlx5e_ptpsq_mark_ts_cqes_undelivered(struct mlx5e_ptpsq *ptpsq, 145 150 ktime_t port_tstamp) 146 151 { ··· 212 205 out: 213 206 napi_consume_skb(skb, budget); 214 207 mlx5e_ptp_metadata_fifo_push(&ptpsq->metadata_freelist, metadata_id); 208 + if (unlikely(mlx5e_ptp_metadata_map_unhealthy(&ptpsq->metadata_map)) && 209 + !test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) 210 + queue_work(ptpsq->txqsq.priv->wq, &ptpsq->report_unhealthy_work); 215 211 } 216 212 217 213 static bool mlx5e_ptp_poll_ts_cq(struct mlx5e_cq *cq, int budget) ··· 432 422 kvfree(ptpsq->ts_cqe_pending_list); 433 423 } 434 424 425 + static void mlx5e_ptpsq_unhealthy_work(struct work_struct *work) 426 + { 427 + struct mlx5e_ptpsq *ptpsq = 428 + container_of(work, struct mlx5e_ptpsq, report_unhealthy_work); 429 + 430 + mlx5e_reporter_tx_ptpsq_unhealthy(ptpsq); 431 + } 432 + 435 433 static int mlx5e_ptp_open_txqsq(struct mlx5e_ptp *c, u32 tisn, 436 434 int txq_ix, struct mlx5e_ptp_params *cparams, 437 435 int tc, struct mlx5e_ptpsq *ptpsq) ··· 469 451 if (err) 470 452 goto err_free_txqsq; 471 453 454 + INIT_WORK(&ptpsq->report_unhealthy_work, mlx5e_ptpsq_unhealthy_work); 455 + 472 456 return 0; 473 457 474 458 err_free_txqsq: ··· 484 464 struct mlx5e_txqsq *sq = &ptpsq->txqsq; 485 465 struct mlx5_core_dev *mdev = sq->mdev; 486 466 467 + if (current_work() != &ptpsq->report_unhealthy_work) 468 + cancel_work_sync(&ptpsq->report_unhealthy_work); 487 469 mlx5e_ptp_free_traffic_db(ptpsq); 488 470 cancel_work_sync(&sq->recover_work); 489 471 mlx5e_ptp_destroy_sq(mdev, sq->sqn);
+2
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
··· 10 10 #include <linux/ktime.h> 11 11 #include <linux/ptp_classify.h> 12 12 #include <linux/time64.h> 13 + #include <linux/workqueue.h> 13 14 14 15 #define MLX5E_PTP_CHANNEL_IX 0 15 16 #define MLX5E_PTP_MAX_LOG_SQ_SIZE (8U) ··· 35 34 struct mlx5e_ptp_cq_stats *cq_stats; 36 35 u16 ts_cqe_ctr_mask; 37 36 37 + struct work_struct report_unhealthy_work; 38 38 struct mlx5e_ptp_port_ts_cqe_list *ts_cqe_pending_list; 39 39 struct mlx5e_ptp_metadata_fifo metadata_freelist; 40 40 struct mlx5e_ptp_metadata_map metadata_map;
+65
drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
··· 164 164 return err; 165 165 } 166 166 167 + static int mlx5e_tx_reporter_ptpsq_unhealthy_recover(void *ctx) 168 + { 169 + struct mlx5e_ptpsq *ptpsq = ctx; 170 + struct mlx5e_channels *chs; 171 + struct net_device *netdev; 172 + struct mlx5e_priv *priv; 173 + int carrier_ok; 174 + int err; 175 + 176 + if (!test_bit(MLX5E_SQ_STATE_RECOVERING, &ptpsq->txqsq.state)) 177 + return 0; 178 + 179 + priv = ptpsq->txqsq.priv; 180 + 181 + mutex_lock(&priv->state_lock); 182 + chs = &priv->channels; 183 + netdev = priv->netdev; 184 + 185 + carrier_ok = netif_carrier_ok(netdev); 186 + netif_carrier_off(netdev); 187 + 188 + mlx5e_deactivate_priv_channels(priv); 189 + 190 + mlx5e_ptp_close(chs->ptp); 191 + err = mlx5e_ptp_open(priv, &chs->params, chs->c[0]->lag_port, &chs->ptp); 192 + 193 + mlx5e_activate_priv_channels(priv); 194 + 195 + /* return carrier back if needed */ 196 + if (carrier_ok) 197 + netif_carrier_on(netdev); 198 + 199 + mutex_unlock(&priv->state_lock); 200 + 201 + return err; 202 + } 203 + 167 204 /* state lock cannot be grabbed within this function. 168 205 * It can cause a dead lock or a read-after-free. 169 206 */ ··· 553 516 return mlx5e_tx_reporter_dump_sq(priv, fmsg, to_ctx->sq); 554 517 } 555 518 519 + static int mlx5e_tx_reporter_ptpsq_unhealthy_dump(struct mlx5e_priv *priv, 520 + struct devlink_fmsg *fmsg, 521 + void *ctx) 522 + { 523 + struct mlx5e_ptpsq *ptpsq = ctx; 524 + 525 + return mlx5e_tx_reporter_dump_sq(priv, fmsg, &ptpsq->txqsq); 526 + } 527 + 556 528 static int mlx5e_tx_reporter_dump_all_sqs(struct mlx5e_priv *priv, 557 529 struct devlink_fmsg *fmsg) 558 530 { ··· 665 619 666 620 mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx); 667 621 return to_ctx.status; 622 + } 623 + 624 + void mlx5e_reporter_tx_ptpsq_unhealthy(struct mlx5e_ptpsq *ptpsq) 625 + { 626 + struct mlx5e_ptp_metadata_map *map = &ptpsq->metadata_map; 627 + char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; 628 + struct mlx5e_txqsq *txqsq = &ptpsq->txqsq; 629 + struct mlx5e_cq *ts_cq = &ptpsq->ts_cq; 630 + struct mlx5e_priv *priv = txqsq->priv; 631 + struct mlx5e_err_ctx err_ctx = {}; 632 + 633 + err_ctx.ctx = ptpsq; 634 + err_ctx.recover = mlx5e_tx_reporter_ptpsq_unhealthy_recover; 635 + err_ctx.dump = mlx5e_tx_reporter_ptpsq_unhealthy_dump; 636 + snprintf(err_str, sizeof(err_str), 637 + "Unhealthy TX port TS queue: %d, SQ: 0x%x, CQ: 0x%x, Undelivered CQEs: %u Map Capacity: %u", 638 + txqsq->ch_ix, txqsq->sqn, ts_cq->mcq.cqn, map->undelivered_counter, map->capacity); 639 + 640 + mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx); 668 641 } 669 642 670 643 static const struct devlink_health_reporter_ops mlx5_tx_reporter_ops = {