]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
bnx2x: Prevent ptp_task to be rescheduled indefinitely
authorGuilherme G. Piccoli <gpiccoli@canonical.com>
Thu, 27 Jun 2019 16:31:33 +0000 (13:31 -0300)
committerDavid S. Miller <davem@davemloft.net>
Sat, 29 Jun 2019 19:19:42 +0000 (12:19 -0700)
Currently bnx2x ptp worker tries to read a register with timestamp
information in case of TX packet timestamping and in case it fails,
the routine reschedules itself indefinitely. This was reported as a
kworker always at 100% of CPU usage, which was narrowed down to be
bnx2x ptp_task.

By following the ioctl handler, we could narrow down the problem to
an NTP tool (chrony) requesting HW timestamping from bnx2x NIC with
RX filter zeroed; this isn't reproducible for example with ptp4l
(from linuxptp) since this tool requests a supported RX filter.
It seems NIC FW timestamp mechanism cannot work well with
RX_FILTER_NONE - driver's PTP filter init routine skips a register
write to the adapter if there's not a supported filter request.

This patch addresses the problem of bnx2x ptp thread's everlasting
reschedule by retrying the register read 10 times; between the read
attempts the thread sleeps for an increasing amount of time starting
in 1ms to give FW some time to perform the timestamping. If it still
fails after all retries, we bail out in order to prevent an unbound
resource consumption from bnx2x.

The patch also adds an ethtool statistic for accounting the skipped
TX timestamp packets and it reduces the priority of timestamping
error messages to prevent log flooding. The code was tested using
both linuxptp and chrony.

Reported-and-tested-by: Przemyslaw Hausman <przemyslaw.hausman@canonical.com>
Suggested-by: Sudarsana Reddy Kalluru <skalluru@marvell.com>
Signed-off-by: Guilherme G. Piccoli <gpiccoli@canonical.com>
Acked-by: Sudarsana Reddy Kalluru <skalluru@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h

index 008ad0ca89ba0ea7a20085ec4d69b1d010d77c88..c12c1bab0fe473b8579249c2d85fd3a87e8362a4 100644 (file)
@@ -3857,9 +3857,12 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
                if (!(bp->flags & TX_TIMESTAMPING_EN)) {
+                       bp->eth_stats.ptp_skip_tx_ts++;
                        BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n");
                } else if (bp->ptp_tx_skb) {
-                       BNX2X_ERR("The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+                       bp->eth_stats.ptp_skip_tx_ts++;
+                       netdev_err_once(bp->dev,
+                                       "Device supports only a single outstanding packet to timestamp, this packet won't be timestamped\n");
                } else {
                        skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                        /* schedule check for Tx timestamp */
index 51fc845de31adca502a86cbd5e83403a830bf626..4a0ba6801c9e488fac1d8d29f3d4685b61d6f48c 100644 (file)
@@ -182,7 +182,9 @@ static const struct {
        { STATS_OFFSET32(driver_filtered_tx_pkt),
                                4, false, "driver_filtered_tx_pkt" },
        { STATS_OFFSET32(eee_tx_lpi),
-                               4, true, "Tx LPI entry count"}
+                               4, true, "Tx LPI entry count"},
+       { STATS_OFFSET32(ptp_skip_tx_ts),
+                               4, false, "ptp_skipped_tx_tstamp" },
 };
 
 #define BNX2X_NUM_STATS                ARRAY_SIZE(bnx2x_stats_arr)
index 03ac10b1cd1e1db4684c8af8eed33f950492ab5b..2cc14db8f0ec9c1d0ee8b922ea9926320cc5bb96 100644 (file)
@@ -15214,11 +15214,24 @@ static void bnx2x_ptp_task(struct work_struct *work)
        u32 val_seq;
        u64 timestamp, ns;
        struct skb_shared_hwtstamps shhwtstamps;
+       bool bail = true;
+       int i;
+
+       /* FW may take a while to complete timestamping; try a bit and if it's
+        * still not complete, may indicate an error state - bail out then.
+        */
+       for (i = 0; i < 10; i++) {
+               /* Read Tx timestamp registers */
+               val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+                                NIG_REG_P0_TLLH_PTP_BUF_SEQID);
+               if (val_seq & 0x10000) {
+                       bail = false;
+                       break;
+               }
+               msleep(1 << i);
+       }
 
-       /* Read Tx timestamp registers */
-       val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
-                        NIG_REG_P0_TLLH_PTP_BUF_SEQID);
-       if (val_seq & 0x10000) {
+       if (!bail) {
                /* There is a valid timestamp value */
                timestamp = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_TS_MSB :
                                   NIG_REG_P0_TLLH_PTP_BUF_TS_MSB);
@@ -15233,16 +15246,18 @@ static void bnx2x_ptp_task(struct work_struct *work)
                memset(&shhwtstamps, 0, sizeof(shhwtstamps));
                shhwtstamps.hwtstamp = ns_to_ktime(ns);
                skb_tstamp_tx(bp->ptp_tx_skb, &shhwtstamps);
-               dev_kfree_skb_any(bp->ptp_tx_skb);
-               bp->ptp_tx_skb = NULL;
 
                DP(BNX2X_MSG_PTP, "Tx timestamp, timestamp cycles = %llu, ns = %llu\n",
                   timestamp, ns);
        } else {
-               DP(BNX2X_MSG_PTP, "There is no valid Tx timestamp yet\n");
-               /* Reschedule to keep checking for a valid timestamp value */
-               schedule_work(&bp->ptp_task);
+               DP(BNX2X_MSG_PTP,
+                  "Tx timestamp is not recorded (register read=%u)\n",
+                  val_seq);
+               bp->eth_stats.ptp_skip_tx_ts++;
        }
+
+       dev_kfree_skb_any(bp->ptp_tx_skb);
+       bp->ptp_tx_skb = NULL;
 }
 
 void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb)
index b2644ed13d064eacc3b34cf59d48b156bedac16b..d55e63692cf3bf5ab4c11b8ddc9d800c520d5e78 100644 (file)
@@ -207,6 +207,9 @@ struct bnx2x_eth_stats {
        u32 driver_filtered_tx_pkt;
        /* src: Clear-on-Read register; Will not survive PMF Migration */
        u32 eee_tx_lpi;
+
+       /* PTP */
+       u32 ptp_skip_tx_ts;
 };
 
 struct bnx2x_eth_q_stats {