Skip to content

Commit 8cbc756

Browse files
lsun100jwrdegoede
authored andcommitted
platform/mellanox: mlxbf-tmfifo: Drop Tx network packet when Tx TmFIFO is full
Starting from Linux 5.16 kernel, Tx timeout mechanism was added in the virtio_net driver which prints the "Tx timeout" warning message when a packet stays in Tx queue for too long. Below is an example of the reported message: "[494105.316739] virtio_net virtio1 tmfifo_net0: TX timeout on queue: 0, sq: output.0, vq: 0×1, name: output.0, usecs since last trans: 3079892256". This issue could happen when external host driver which drains the FIFO is restared, stopped or upgraded. To avoid such confusing "Tx timeout" messages, this commit adds logic to drop the outstanding Tx packet if it's not able to transmit in two seconds due to Tx FIFO full, which can be considered as congestion or out-of-resource drop. This commit also handles the special case that the packet is half- transmitted into the Tx FIFO. In such case, the packet is discarded with remaining length stored in vring->rem_padding. So paddings with zeros can be sent out when Tx space is available to maintain the integrity of the packet format. The padded packet will be dropped on the receiving side. Signed-off-by: Liming Sun <[email protected]> Reviewed-by: Ilpo Järvinen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Hans de Goede <[email protected]>
1 parent 8530eca commit 8cbc756

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

drivers/platform/mellanox/mlxbf-tmfifo.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
/* Message with data needs at least two words (for header & data). */
4848
#define MLXBF_TMFIFO_DATA_MIN_WORDS 2
4949

50+
/* Tx timeout in milliseconds. */
51+
#define TMFIFO_TX_TIMEOUT 2000
52+
5053
/* ACPI UID for BlueField-3. */
5154
#define TMFIFO_BF3_UID 1
5255

@@ -62,12 +65,14 @@ struct mlxbf_tmfifo;
6265
* @drop_desc: dummy desc for packet dropping
6366
* @cur_len: processed length of the current descriptor
6467
* @rem_len: remaining length of the pending packet
68+
* @rem_padding: remaining bytes to send as paddings
6569
* @pkt_len: total length of the pending packet
6670
* @next_avail: next avail descriptor id
6771
* @num: vring size (number of descriptors)
6872
* @align: vring alignment size
6973
* @index: vring index
7074
* @vdev_id: vring virtio id (VIRTIO_ID_xxx)
75+
* @tx_timeout: expire time of last tx packet
7176
* @fifo: pointer to the tmfifo structure
7277
*/
7378
struct mlxbf_tmfifo_vring {
@@ -79,12 +84,14 @@ struct mlxbf_tmfifo_vring {
7984
struct vring_desc drop_desc;
8085
int cur_len;
8186
int rem_len;
87+
int rem_padding;
8288
u32 pkt_len;
8389
u16 next_avail;
8490
int num;
8591
int align;
8692
int index;
8793
int vdev_id;
94+
unsigned long tx_timeout;
8895
struct mlxbf_tmfifo *fifo;
8996
};
9097

@@ -819,6 +826,50 @@ static bool mlxbf_tmfifo_rxtx_one_desc(struct mlxbf_tmfifo_vring *vring,
819826
return true;
820827
}
821828

829+
static void mlxbf_tmfifo_check_tx_timeout(struct mlxbf_tmfifo_vring *vring)
830+
{
831+
unsigned long flags;
832+
833+
/* Only handle Tx timeout for network vdev. */
834+
if (vring->vdev_id != VIRTIO_ID_NET)
835+
return;
836+
837+
/* Initialize the timeout or return if not expired. */
838+
if (!vring->tx_timeout) {
839+
/* Initialize the timeout. */
840+
vring->tx_timeout = jiffies +
841+
msecs_to_jiffies(TMFIFO_TX_TIMEOUT);
842+
return;
843+
} else if (time_before(jiffies, vring->tx_timeout)) {
844+
/* Return if not timeout yet. */
845+
return;
846+
}
847+
848+
/*
849+
* Drop the packet after timeout. The outstanding packet is
850+
* released and the remaining bytes will be sent with padding byte 0x00
851+
* as a recovery. On the peer(host) side, the padding bytes 0x00 will be
852+
* either dropped directly, or appended into existing outstanding packet
853+
* thus dropped as corrupted network packet.
854+
*/
855+
vring->rem_padding = round_up(vring->rem_len, sizeof(u64));
856+
mlxbf_tmfifo_release_pkt(vring);
857+
vring->cur_len = 0;
858+
vring->rem_len = 0;
859+
vring->fifo->vring[0] = NULL;
860+
861+
/*
862+
* Make sure the load/store are in order before
863+
* returning back to virtio.
864+
*/
865+
virtio_mb(false);
866+
867+
/* Notify upper layer. */
868+
spin_lock_irqsave(&vring->fifo->spin_lock[0], flags);
869+
vring_interrupt(0, vring->vq);
870+
spin_unlock_irqrestore(&vring->fifo->spin_lock[0], flags);
871+
}
872+
822873
/* Rx & Tx processing of a queue. */
823874
static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
824875
{
@@ -841,6 +892,7 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
841892
return;
842893

843894
do {
895+
retry:
844896
/* Get available FIFO space. */
845897
if (avail == 0) {
846898
if (is_rx)
@@ -851,6 +903,17 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
851903
break;
852904
}
853905

906+
/* Insert paddings for discarded Tx packet. */
907+
if (!is_rx) {
908+
vring->tx_timeout = 0;
909+
while (vring->rem_padding >= sizeof(u64)) {
910+
writeq(0, vring->fifo->tx.data);
911+
vring->rem_padding -= sizeof(u64);
912+
if (--avail == 0)
913+
goto retry;
914+
}
915+
}
916+
854917
/* Console output always comes from the Tx buffer. */
855918
if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
856919
mlxbf_tmfifo_console_tx(fifo, avail);
@@ -860,6 +923,10 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
860923
/* Handle one descriptor. */
861924
more = mlxbf_tmfifo_rxtx_one_desc(vring, is_rx, &avail);
862925
} while (more);
926+
927+
/* Check Tx timeout. */
928+
if (avail <= 0 && !is_rx)
929+
mlxbf_tmfifo_check_tx_timeout(vring);
863930
}
864931

865932
/* Handle Rx or Tx queues. */

0 commit comments

Comments
 (0)