| From foo@baz Sun Feb 10 12:47:17 CET 2019 |
| From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| Date: Mon, 4 Feb 2019 11:20:29 +0100 |
| Subject: net: dp83640: expire old TX-skb |
| |
| From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| |
| [ Upstream commit 53bc8d2af08654659abfadfd3e98eb9922ff787c ] |
| |
| During sendmsg() a cloned skb is saved via dp83640_txtstamp() in |
| ->tx_queue. After the NIC sends this packet, the PHY will reply with a |
| timestamp for that TX packet. If the cable is pulled at the right time I |
| don't see that packet. It might gets flushed as part of queue shutdown |
| on NIC's side. |
| Once the link is up again then after the next sendmsg() we enqueue |
| another skb in dp83640_txtstamp() and have two on the list. Then the PHY |
| will send a reply and decode_txts() attaches it to the first skb on the |
| list. |
| No crash occurs since refcounting works but we are one packet behind. |
| linuxptp/ptp4l usually closes the socket and opens a new one (in such a |
| timeout case) so those "stale" replies never get there. However it does |
| not resume normal operation anymore. |
| |
| Purge old skbs in decode_txts(). |
| |
| Fixes: cb646e2b02b2 ("ptp: Added a clock driver for the National Semiconductor PHYTER.") |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de> |
| Acked-by: Richard Cochran <richardcochran@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/phy/dp83640.c | 13 ++++++++++--- |
| 1 file changed, 10 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/net/phy/dp83640.c |
| +++ b/drivers/net/phy/dp83640.c |
| @@ -893,14 +893,14 @@ static void decode_txts(struct dp83640_p |
| struct phy_txts *phy_txts) |
| { |
| struct skb_shared_hwtstamps shhwtstamps; |
| + struct dp83640_skb_info *skb_info; |
| struct sk_buff *skb; |
| - u64 ns; |
| u8 overflow; |
| + u64 ns; |
| |
| /* We must already have the skb that triggered this. */ |
| - |
| +again: |
| skb = skb_dequeue(&dp83640->tx_queue); |
| - |
| if (!skb) { |
| pr_debug("have timestamp but tx_queue empty\n"); |
| return; |
| @@ -915,6 +915,11 @@ static void decode_txts(struct dp83640_p |
| } |
| return; |
| } |
| + skb_info = (struct dp83640_skb_info *)skb->cb; |
| + if (time_after(jiffies, skb_info->tmo)) { |
| + kfree_skb(skb); |
| + goto again; |
| + } |
| |
| ns = phy2txts(phy_txts); |
| memset(&shhwtstamps, 0, sizeof(shhwtstamps)); |
| @@ -1466,6 +1471,7 @@ static bool dp83640_rxtstamp(struct phy_ |
| static void dp83640_txtstamp(struct phy_device *phydev, |
| struct sk_buff *skb, int type) |
| { |
| + struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb; |
| struct dp83640_private *dp83640 = phydev->priv; |
| |
| switch (dp83640->hwts_tx_en) { |
| @@ -1478,6 +1484,7 @@ static void dp83640_txtstamp(struct phy_ |
| /* fall through */ |
| case HWTSTAMP_TX_ON: |
| skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; |
| + skb_info->tmo = jiffies + SKB_TIMESTAMP_TIMEOUT; |
| skb_queue_tail(&dp83640->tx_queue, skb); |
| break; |
| |