Commit 9adebac3 authored by Sudarsana Reddy Kalluru's avatar Sudarsana Reddy Kalluru Committed by David S. Miller

qede: Handle infinite driver spinning for Tx timestamp.

In PTP Tx implementation, driver kept scheduling a poll thread until the
timestamp is available. In the error scenarios (e.g. app requesting the
timestamp for non-ptp packet), this thread kept waiting for the timestamp
forever.  This patch add changes to report such scenario as an error and
terminate the thread. Added a timeout of 2 seconds i.e., max time to wait
for Tx timestamp. Added a stat value ptp_skip_txts for reporting the number
of packets for which Tx timestamping is skipped.
Signed-off-by: default avatarSudarsana Reddy Kalluru <skalluru@marvell.com>
Signed-off-by: default avatarMichal Kalderon <mkalderon@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 24c6203b
...@@ -92,6 +92,7 @@ struct qede_stats_common { ...@@ -92,6 +92,7 @@ struct qede_stats_common {
u64 non_coalesced_pkts; u64 non_coalesced_pkts;
u64 coalesced_bytes; u64 coalesced_bytes;
u64 link_change_count; u64 link_change_count;
u64 ptp_skip_txts;
/* port */ /* port */
u64 rx_64_byte_packets; u64 rx_64_byte_packets;
...@@ -189,6 +190,7 @@ struct qede_dev { ...@@ -189,6 +190,7 @@ struct qede_dev {
const struct qed_eth_ops *ops; const struct qed_eth_ops *ops;
struct qede_ptp *ptp; struct qede_ptp *ptp;
u64 ptp_skip_txts;
struct qed_dev_eth_info dev_info; struct qed_dev_eth_info dev_info;
#define QEDE_MAX_RSS_CNT(edev) ((edev)->dev_info.num_queues) #define QEDE_MAX_RSS_CNT(edev) ((edev)->dev_info.num_queues)
......
...@@ -174,6 +174,7 @@ static const struct { ...@@ -174,6 +174,7 @@ static const struct {
QEDE_STAT(coalesced_bytes), QEDE_STAT(coalesced_bytes),
QEDE_STAT(link_change_count), QEDE_STAT(link_change_count),
QEDE_STAT(ptp_skip_txts),
}; };
#define QEDE_NUM_STATS ARRAY_SIZE(qede_stats_arr) #define QEDE_NUM_STATS ARRAY_SIZE(qede_stats_arr)
......
...@@ -390,6 +390,7 @@ void qede_fill_by_demand_stats(struct qede_dev *edev) ...@@ -390,6 +390,7 @@ void qede_fill_by_demand_stats(struct qede_dev *edev)
p_common->brb_discards = stats.common.brb_discards; p_common->brb_discards = stats.common.brb_discards;
p_common->tx_mac_ctrl_frames = stats.common.tx_mac_ctrl_frames; p_common->tx_mac_ctrl_frames = stats.common.tx_mac_ctrl_frames;
p_common->link_change_count = stats.common.link_change_count; p_common->link_change_count = stats.common.link_change_count;
p_common->ptp_skip_txts = edev->ptp_skip_txts;
if (QEDE_IS_BB(edev)) { if (QEDE_IS_BB(edev)) {
struct qede_stats_bb *p_bb = &edev->stats.bb; struct qede_stats_bb *p_bb = &edev->stats.bb;
...@@ -2232,6 +2233,8 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, ...@@ -2232,6 +2233,8 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode,
if (mode != QEDE_UNLOAD_RECOVERY) if (mode != QEDE_UNLOAD_RECOVERY)
DP_NOTICE(edev, "Link is down\n"); DP_NOTICE(edev, "Link is down\n");
edev->ptp_skip_txts = 0;
DP_INFO(edev, "Ending qede unload\n"); DP_INFO(edev, "Ending qede unload\n");
} }
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "qede_ptp.h" #include "qede_ptp.h"
#define QEDE_PTP_TX_TIMEOUT (2 * HZ)
struct qede_ptp { struct qede_ptp {
const struct qed_eth_ptp_ops *ops; const struct qed_eth_ptp_ops *ops;
...@@ -38,6 +39,7 @@ struct qede_ptp { ...@@ -38,6 +39,7 @@ struct qede_ptp {
struct timecounter tc; struct timecounter tc;
struct ptp_clock *clock; struct ptp_clock *clock;
struct work_struct work; struct work_struct work;
unsigned long ptp_tx_start;
struct qede_dev *edev; struct qede_dev *edev;
struct sk_buff *tx_skb; struct sk_buff *tx_skb;
...@@ -160,18 +162,30 @@ static void qede_ptp_task(struct work_struct *work) ...@@ -160,18 +162,30 @@ static void qede_ptp_task(struct work_struct *work)
struct qede_dev *edev; struct qede_dev *edev;
struct qede_ptp *ptp; struct qede_ptp *ptp;
u64 timestamp, ns; u64 timestamp, ns;
bool timedout;
int rc; int rc;
ptp = container_of(work, struct qede_ptp, work); ptp = container_of(work, struct qede_ptp, work);
edev = ptp->edev; edev = ptp->edev;
timedout = time_is_before_jiffies(ptp->ptp_tx_start +
QEDE_PTP_TX_TIMEOUT);
/* Read Tx timestamp registers */ /* Read Tx timestamp registers */
spin_lock_bh(&ptp->lock); spin_lock_bh(&ptp->lock);
rc = ptp->ops->read_tx_ts(edev->cdev, &timestamp); rc = ptp->ops->read_tx_ts(edev->cdev, &timestamp);
spin_unlock_bh(&ptp->lock); spin_unlock_bh(&ptp->lock);
if (rc) { if (rc) {
/* Reschedule to keep checking for a valid timestamp value */ if (unlikely(timedout)) {
schedule_work(&ptp->work); DP_INFO(edev, "Tx timestamp is not recorded\n");
dev_kfree_skb_any(ptp->tx_skb);
ptp->tx_skb = NULL;
clear_bit_unlock(QEDE_FLAGS_PTP_TX_IN_PRORGESS,
&edev->flags);
edev->ptp_skip_txts++;
} else {
/* Reschedule to keep checking for a valid TS value */
schedule_work(&ptp->work);
}
return; return;
} }
...@@ -514,19 +528,28 @@ void qede_ptp_tx_ts(struct qede_dev *edev, struct sk_buff *skb) ...@@ -514,19 +528,28 @@ void qede_ptp_tx_ts(struct qede_dev *edev, struct sk_buff *skb)
if (!ptp) if (!ptp)
return; return;
if (test_and_set_bit_lock(QEDE_FLAGS_PTP_TX_IN_PRORGESS, &edev->flags)) if (test_and_set_bit_lock(QEDE_FLAGS_PTP_TX_IN_PRORGESS,
&edev->flags)) {
DP_ERR(edev, "Timestamping in progress\n");
edev->ptp_skip_txts++;
return; return;
}
if (unlikely(!test_bit(QEDE_FLAGS_TX_TIMESTAMPING_EN, &edev->flags))) { if (unlikely(!test_bit(QEDE_FLAGS_TX_TIMESTAMPING_EN, &edev->flags))) {
DP_NOTICE(edev, DP_ERR(edev,
"Tx timestamping was not enabled, this packet will not be timestamped\n"); "Tx timestamping was not enabled, this packet will not be timestamped\n");
clear_bit_unlock(QEDE_FLAGS_PTP_TX_IN_PRORGESS, &edev->flags);
edev->ptp_skip_txts++;
} else if (unlikely(ptp->tx_skb)) { } else if (unlikely(ptp->tx_skb)) {
DP_NOTICE(edev, DP_ERR(edev,
"The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n"); "The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
clear_bit_unlock(QEDE_FLAGS_PTP_TX_IN_PRORGESS, &edev->flags);
edev->ptp_skip_txts++;
} else { } else {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
/* schedule check for Tx timestamp */ /* schedule check for Tx timestamp */
ptp->tx_skb = skb_get(skb); ptp->tx_skb = skb_get(skb);
ptp->ptp_tx_start = jiffies;
schedule_work(&ptp->work); schedule_work(&ptp->work);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment