From nobody Sat Jul 25 01:37:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0E2B53FC5C3; Tue, 21 Jul 2026 02:21:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784600492; cv=none; b=Qz4r30zkKRHHXcp4RCBGi1ELdYuzca37iY4Sfvrvk10/fn1NmXFRVfDAqA/0cf7t8zElrbfWLhugjtuAT83sS4MIbhRmnexVJlEb952BLcI5sJ+E89jgNVYMkpQXZB26m8I3yx/4P/rJ8tAawRf7u3KfJra0jzPErK6d9aBnepc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784600492; c=relaxed/simple; bh=cpsPDNbTObDrhmsVuo4YfvMITcMiSGI6Oq8yYAd7T/E=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PgYJtNFTe34Gd8y8SSJ9ieNxAhaiBCV58bqVv4eCLt4W6BPGNcOM9OV/zicsjJ1P3GX226nlHUVcso/GiuYw4vtITw7+zciLYD9qSXZhJ30qLH1hixqhkfE7lcOw+10pFRF9mqKOGvZuRohALeSVD5MRZelQS1KIdSF8tSMQxM8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BRi4SNM3; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BRi4SNM3" Received: by smtp.kernel.org (Postfix) with ESMTPS id BCD44C2BCF7; Tue, 21 Jul 2026 02:21:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784600491; bh=cpsPDNbTObDrhmsVuo4YfvMITcMiSGI6Oq8yYAd7T/E=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=BRi4SNM3bu4DYAD3lTBhsXpWpyBHNp9CjMQl2iukycipnGDZr7f+pStlDKaLzieMv 7I/1Yd72Ky+o1j+MS4FlLR2bcGS5bgKMOEZUE62RUQsNkS8xMXj/ufPRXFO9Sa/aqD 4ucPt11Lo7bMIEjo6ACqfgC5+CPQQRJqwS/fUeOAszFqjcZyeOHHPcduXlF2poUQgQ ePqhZlu0bpBG7oKt/cAgo8g3iGr/Ybobw4JZYk6hUxffMhwVnBtteEwq6fuunGau17 eBPSQJ/53zLU4j8RVz0PyewKseGO0pQln3Gi9zJnd1zqkPGyfTPqn4xHXwxq8eChTy Unmh3a/6EtRgA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9B2D4C44520; Tue, 21 Jul 2026 02:21:31 +0000 (UTC) From: Selvamani Rajagopal via B4 Relay Date: Mon, 20 Jul 2026 19:20:35 -0700 Subject: [PATCH net v4 1/3] net: ethernet: oa_tc6: Protect skb pointer used by two different kernel instances Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260720-fix-race-condition-and-crash-v4-1-8273e2f38a1f@onsemi.com> References: <20260720-fix-race-condition-and-crash-v4-0-8273e2f38a1f@onsemi.com> In-Reply-To: <20260720-fix-race-condition-and-crash-v4-0-8273e2f38a1f@onsemi.com> To: Parthiban Veerasooran , Andrew Lunn , Piergiorgio Beruto , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Andrew Lunn , Parthiban Veerasooran , Selvamani Rajagopal X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784600442; l=5762; i=Selvamani.Rajagopal@onsemi.com; s=20260531; h=from:subject:message-id; bh=PtJKXxiHIQ65kW4ADgjT422PMBMh9A+ziMoUoFppues=; b=oJHhMqZ0P+P1VXVB3w7NrLpJoIFeXU+WdK75pJrqVkAFct8tSf3tI07VkThX5l9MlIa1HpOBd rsVZkSUMVP0B9ohNDU2Wk+3VoYeyhhEf0/05hyafYEMZQbbtZzTnTwd X-Developer-Key: i=Selvamani.Rajagopal@onsemi.com; a=ed25519; pk=5QRdM0HS/LGWWcUZZ9hVfZ+qbPQGZCumcTXOiN7Fyug= X-Endpoint-Received: by B4 Relay for Selvamani.Rajagopal@onsemi.com/20260531 with auth_id=803 X-Original-From: Selvamani Rajagopal Reply-To: Selvamani.Rajagopal@onsemi.com From: Selvamani Rajagopal Threaded IRQ uses waiting_tx_skb. Transmit path also uses this pointer without any mutual exclusion protection. As a result, it might leak skb buffer, particularly threaded IRQ runs in the middle of tranmsmit path, near skb_linearize. Fixes: b542d13fab0f ("net: ethernet: oa_tc6: Interrupt is active low, level= triggered.") Signed-off-by: Selvamani Rajagopal --- changes in v4 - No change changes in v3 - Added the missed out spin lock protection for waiting_tx_skb and disable_traffic flag changes in v2 - added the missing prefix to the title --- drivers/net/ethernet/oa_tc6.c | 100 +++++++++++++++++++++++++++++---------= ---- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 0727d53345a3..5b24cce4f9b5 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -652,6 +652,26 @@ static int oa_tc6_enable_data_transfer(struct oa_tc6 *= tc6) return oa_tc6_write_register(tc6, OA_TC6_REG_CONFIG0, value); } =20 +/* Called when a frame that is meant to be transmitted, is dropped. */ +static void oa_tc6_drop_tx_skb(struct oa_tc6 *tc6, struct sk_buff *skb) +{ + if (skb) { + tc6->netdev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + } +} + +static struct sk_buff *oa_tc6_detach_waiting_tx_skb(struct oa_tc6 *tc6) +{ + struct sk_buff *skb; + + lockdep_assert_held(&tc6->tx_skb_lock); + skb =3D tc6->waiting_tx_skb; + tc6->waiting_tx_skb =3D NULL; + + return skb; +} + static void oa_tc6_cleanup_ongoing_rx_skb(struct oa_tc6 *tc6) { if (tc6->rx_skb) { @@ -663,26 +683,30 @@ static void oa_tc6_cleanup_ongoing_rx_skb(struct oa_t= c6 *tc6) =20 static void oa_tc6_cleanup_ongoing_tx_skb(struct oa_tc6 *tc6) { - if (tc6->ongoing_tx_skb) { - tc6->netdev->stats.tx_dropped++; - kfree_skb(tc6->ongoing_tx_skb); - tc6->ongoing_tx_skb =3D NULL; - } + oa_tc6_drop_tx_skb(tc6, tc6->ongoing_tx_skb); + tc6->ongoing_tx_skb =3D NULL; } =20 static void oa_tc6_cleanup_waiting_tx_skb(struct oa_tc6 *tc6) { - if (tc6->waiting_tx_skb) { - tc6->netdev->stats.tx_dropped++; - kfree_skb(tc6->waiting_tx_skb); - tc6->waiting_tx_skb =3D NULL; - } + struct sk_buff *skb; + + spin_lock_bh(&tc6->tx_skb_lock); + skb =3D oa_tc6_detach_waiting_tx_skb(tc6); + spin_unlock_bh(&tc6->tx_skb_lock); + + oa_tc6_drop_tx_skb(tc6, skb); } =20 -static void oa_tc6_free_pending_skbs(struct oa_tc6 *tc6) +static void oa_tc6_free_ongoing_skbs(struct oa_tc6 *tc6) { oa_tc6_cleanup_ongoing_tx_skb(tc6); oa_tc6_cleanup_ongoing_rx_skb(tc6); +} + +static void oa_tc6_free_pending_skbs(struct oa_tc6 *tc6) +{ + oa_tc6_free_ongoing_skbs(tc6); oa_tc6_cleanup_waiting_tx_skb(tc6); } =20 @@ -693,9 +717,15 @@ static void oa_tc6_free_pending_skbs(struct oa_tc6 *tc= 6) static void oa_tc6_disable_traffic(struct oa_tc6 *tc6) { u32 regval =3D INT_MASK0_ALL_INTERRUPTS; + struct sk_buff *skb; =20 + spin_lock_bh(&tc6->tx_skb_lock); tc6->disable_traffic =3D true; - oa_tc6_free_pending_skbs(tc6); + skb =3D oa_tc6_detach_waiting_tx_skb(tc6); + spin_unlock_bh(&tc6->tx_skb_lock); + + oa_tc6_drop_tx_skb(tc6, skb); + oa_tc6_free_ongoing_skbs(tc6); oa_tc6_write_register(tc6, OA_TC6_REG_INT_MASK0, regval); oa_tc6_read_register(tc6, OA_TC6_REG_STATUS0, ®val); oa_tc6_write_register(tc6, OA_TC6_REG_STATUS0, regval); @@ -1136,8 +1166,7 @@ static int oa_tc6_try_spi_transfer(struct oa_tc6 *tc6) if (ret =3D=3D -EAGAIN) continue; =20 - oa_tc6_cleanup_ongoing_tx_skb(tc6); - oa_tc6_cleanup_ongoing_rx_skb(tc6); + oa_tc6_free_ongoing_skbs(tc6); netdev_err(tc6->netdev, "Device error: %d\n", ret); return ret; } @@ -1159,15 +1188,20 @@ static irqreturn_t oa_tc6_macphy_threaded_irq(int i= rq, void *data) * no need to attempt spi transfer, once it fails. Pending skbs * are already freed. */ - if (!tc6->disable_traffic) { - while (tc6->int_flag || - (tc6->waiting_tx_skb && tc6->tx_credits)) { - ret =3D oa_tc6_try_spi_transfer(tc6); - if (ret) { - disable_irq_nosync(tc6->spi->irq); - oa_tc6_disable_traffic(tc6); - break; - } + spin_lock_bh(&tc6->tx_skb_lock); + if (tc6->disable_traffic) { + spin_unlock_bh(&tc6->tx_skb_lock); + return IRQ_HANDLED; + } + spin_unlock_bh(&tc6->tx_skb_lock); + + while (tc6->int_flag || + (tc6->waiting_tx_skb && tc6->tx_credits)) { + ret =3D oa_tc6_try_spi_transfer(tc6); + if (ret) { + disable_irq_nosync(tc6->spi->irq); + oa_tc6_disable_traffic(tc6); + break; } } =20 @@ -1250,18 +1284,22 @@ EXPORT_SYMBOL_GPL(oa_tc6_zero_align_receive_frame_e= nable); */ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb) { - if (tc6->disable_traffic || tc6->waiting_tx_skb) { - netif_stop_queue(tc6->netdev); - return NETDEV_TX_BUSY; - } - if (skb_linearize(skb)) { - dev_kfree_skb_any(skb); - tc6->netdev->stats.tx_dropped++; + oa_tc6_drop_tx_skb(tc6, skb); return NETDEV_TX_OK; } =20 spin_lock_bh(&tc6->tx_skb_lock); + if (tc6->waiting_tx_skb) { + netif_stop_queue(tc6->netdev); + spin_unlock_bh(&tc6->tx_skb_lock); + return NETDEV_TX_BUSY; + } + if (tc6->disable_traffic) { + spin_unlock_bh(&tc6->tx_skb_lock); + oa_tc6_drop_tx_skb(tc6, skb); + return NETDEV_TX_OK; + } tc6->waiting_tx_skb =3D skb; spin_unlock_bh(&tc6->tx_skb_lock); =20 @@ -1393,7 +1431,9 @@ EXPORT_SYMBOL_GPL(oa_tc6_init); */ void oa_tc6_exit(struct oa_tc6 *tc6) { + spin_lock_bh(&tc6->tx_skb_lock); tc6->disable_traffic =3D true; + spin_unlock_bh(&tc6->tx_skb_lock); disable_irq(tc6->spi->irq); oa_tc6_phy_exit(tc6); oa_tc6_free_pending_skbs(tc6); --=20 2.43.0 From nobody Sat Jul 25 01:37:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1BC833B7B8B; Tue, 21 Jul 2026 02:21:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784600492; cv=none; b=nO7UGaTZo0YrXB4Gpog4of7m83tNBj/eR8mvhIKX5gIENHmqmO76axnHXtRXxyClpg4jqCKW5/aCVbBfEEW3DSLNdt7g69gEd3zzYTV5cjYKMHTsgQ6GpxtTbU6ZO3uQ51UGKoAMsJN6emMzTrkZgHPqr99S6A3F3i0ryaUJnqc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784600492; c=relaxed/simple; bh=cRlHfTh90++mvV/5Ce86hsbjhl2TNON6Ne1mKHjEeuk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JIm5vXyBoc3NHW78mfDkZzBpwA3sjIAoaOuC8THDP42/wZZEIdy/jN9eNQRpSIMicoPfhA8chfknq8e9ycMw96AeRN8YTu8i9moF65uhSLJSewPJ27ubLSj9OuDfkQ76HRliKf549ojVhnjzrp21dSvO7i4Yu4D/NlgC+KnGgRw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FzKEwwu3; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FzKEwwu3" Received: by smtp.kernel.org (Postfix) with ESMTPS id CD7EEC2BCFC; Tue, 21 Jul 2026 02:21:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784600491; bh=cRlHfTh90++mvV/5Ce86hsbjhl2TNON6Ne1mKHjEeuk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=FzKEwwu3tup/dvsu9luR6nDGvFWhm+rsWbTblO1+PMHDDUzTdGblk2gioGWvBVcGY +wFus5JMub5kyVXHFnqu1ZG3ex28MuACSiHVKuMxc9NzCEatwnBvw4eOT4e+ubwhGc eV85YjuIFdzvlfzVefaeZne3kQ1Cmk35IXB/s+BD41PlDbQ2k7iXhnuo1+cgmwFLaJ y9knckuYXxbmt4+pCgqAjV/QnT7tcDkPXvhedNi99BqfxZKnen/NMA3xS8HAvDS8gX AyY38ekN0u46gv9qERvmbEla/ivkb29yS1xAUvs53v+mJBlEDwrnmo7ABriIT6N51L lfr0tXu4GRV1g== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id AFCD7C4452F; Tue, 21 Jul 2026 02:21:31 +0000 (UTC) From: Selvamani Rajagopal via B4 Relay Date: Mon, 20 Jul 2026 19:20:36 -0700 Subject: [PATCH net v4 2/3] net: ethernet: oa_tc6: Improvements to error recovery Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260720-fix-race-condition-and-crash-v4-2-8273e2f38a1f@onsemi.com> References: <20260720-fix-race-condition-and-crash-v4-0-8273e2f38a1f@onsemi.com> In-Reply-To: <20260720-fix-race-condition-and-crash-v4-0-8273e2f38a1f@onsemi.com> To: Parthiban Veerasooran , Andrew Lunn , Piergiorgio Beruto , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Andrew Lunn , Parthiban Veerasooran , Selvamani Rajagopal X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784600442; l=9964; i=Selvamani.Rajagopal@onsemi.com; s=20260531; h=from:subject:message-id; bh=pJcLfH5O90O7Cb0UUGzAZb2XuohihqZvY8cxmSkb95I=; b=hrjej8TxikFOAPdAw7Q+Aqp+VZ/B04yzxdZ35SKHmQexUsaGzOgknMCc6WJRdrftOQtvGx/jT 9RMVdaBQce5CdYs+Kj8o2SeRANEGHJAT/Zdnxs4Ibroq7oBXLQjJ+cR X-Developer-Key: i=Selvamani.Rajagopal@onsemi.com; a=ed25519; pk=5QRdM0HS/LGWWcUZZ9hVfZ+qbPQGZCumcTXOiN7Fyug= X-Endpoint-Received: by B4 Relay for Selvamani.Rajagopal@onsemi.com/20260531 with auth_id=803 X-Original-From: Selvamani Rajagopal Reply-To: Selvamani.Rajagopal@onsemi.com From: Selvamani Rajagopal When oversubscribed traffic causes lot of buffer overflow errors, probably due to loss of data chunks, driver fails to find a data chunk with end_valid bit set, before it runs out of sk buffer space. As a result, assert is seen during skb_put. Now check is made if tail + len > end, driver abandons the current data and starts look for a data chunk with start_valid bit, that is a new frame. SK buffer allocation error is considered as recoverable error. Fixes: d70a0d8f2f2d ("net: ethernet: oa_tc6: implement receive path to rece= ive rx ethernet frames") Signed-off-by: Selvamani Rajagopal --- changes in v4 - rx_buf_overflow flag cleared, when end of frame and start of frame are handled in the same data chunk. - Added more comments to answer some of the AI review questions. changes in v3 - Continue processing more chunks on error code -EAGAIN. Previously we were bailing out. changes in v2 - Check rx_skb pointer before new allocation and NULL before use. --- drivers/net/ethernet/oa_tc6.c | 131 ++++++++++++++++++++++++++++++++------= ---- 1 file changed, 100 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 5b24cce4f9b5..9e6850ccfe6c 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -710,6 +710,12 @@ static void oa_tc6_free_pending_skbs(struct oa_tc6 *tc= 6) oa_tc6_cleanup_waiting_tx_skb(tc6); } =20 +static void oa_tc6_look_for_new_frame(struct oa_tc6 *tc6) +{ + tc6->rx_buf_overflow =3D true; + oa_tc6_cleanup_ongoing_rx_skb(tc6); +} + /* If the failure is at SPI interface level, masking and clearing * the interrupt of the device won't work. Since SPI interrupt is * disabled, it should stop the repeated interrupts. @@ -753,8 +759,7 @@ static int oa_tc6_process_extended_status(struct oa_tc6= *tc6) } =20 if (FIELD_GET(STATUS0_RX_BUFFER_OVERFLOW_ERROR, value)) { - tc6->rx_buf_overflow =3D true; - oa_tc6_cleanup_ongoing_rx_skb(tc6); + oa_tc6_look_for_new_frame(tc6); net_err_ratelimited("%s: Receive buffer overflow error\n", tc6->netdev->name); return -EAGAIN; @@ -780,6 +785,8 @@ static int oa_tc6_process_extended_status(struct oa_tc6= *tc6) =20 static int oa_tc6_process_rx_chunk_footer(struct oa_tc6 *tc6, u32 footer) { + int ret =3D 0; + /* Process rx chunk footer for the following, * 1. tx credits * 2. errors if any from MAC-PHY @@ -790,9 +797,11 @@ static int oa_tc6_process_rx_chunk_footer(struct oa_tc= 6 *tc6, u32 footer) footer); =20 if (FIELD_GET(OA_TC6_DATA_FOOTER_EXTENDED_STS, footer)) { - int ret =3D oa_tc6_process_extended_status(tc6); - - if (ret) + ret =3D oa_tc6_process_extended_status(tc6); + /* EAGAIN error is recoverable. Move on to check + * HEADER and SYNC errors before returning. + */ + if (ret && ret !=3D -EAGAIN) return ret; } =20 @@ -810,7 +819,7 @@ static int oa_tc6_process_rx_chunk_footer(struct oa_tc6= *tc6, u32 footer) return -ENODEV; } =20 - return 0; + return ret; } =20 static void oa_tc6_submit_rx_skb(struct oa_tc6 *tc6) @@ -835,13 +844,35 @@ static void oa_tc6_submit_rx_skb(struct oa_tc6 *tc6) tc6->rx_skb =3D NULL; } =20 -static void oa_tc6_update_rx_skb(struct oa_tc6 *tc6, u8 *payload, u8 lengt= h) +/* On oversubscribed traffic condition, particularly with overwhelming rx + * buffer overflow errors, there could be data chunk loss. If tail + length + * goes beyond end pointer, that is an indication that the data chunk with + * end_valid bit is lost. Time to look for a data chunk with start_valid b= it. + * + * If rx_skb is NULL, it is time to start looking for data chunk with + * start_bit. + */ +static int oa_tc6_update_rx_skb(struct oa_tc6 *tc6, u8 *payload, u8 length) { + if (!tc6->rx_skb || + (tc6->rx_skb->tail + length) > tc6->rx_skb->end) { + oa_tc6_look_for_new_frame(tc6); + return -EAGAIN; + } + memcpy(skb_put(tc6->rx_skb, length), payload, length); + return 0; } =20 +/* On overwhelming rx buffer overflow errors, due to data chunk loss, it is + * possible that we get two data chunks with start_valid bit set, without + * end_valid bit set in between. In this case, rx_skb would have a valid + * buffer pointer. We should release, if a valid pointer is found before + * allocating a new one. + */ static int oa_tc6_allocate_rx_skb(struct oa_tc6 *tc6) { + oa_tc6_cleanup_ongoing_rx_skb(tc6); tc6->rx_skb =3D netdev_alloc_skb_ip_align(tc6->netdev, tc6->netdev->mtu + ETH_HLEN + ETH_FCS_LEN); if (!tc6->rx_skb) { @@ -861,7 +892,9 @@ static int oa_tc6_prcs_complete_rx_frame(struct oa_tc6 = *tc6, u8 *payload, if (ret) return ret; =20 - oa_tc6_update_rx_skb(tc6, payload, size); + ret =3D oa_tc6_update_rx_skb(tc6, payload, size); + if (ret) + return ret; =20 oa_tc6_submit_rx_skb(tc6); =20 @@ -876,22 +909,24 @@ static int oa_tc6_prcs_rx_frame_start(struct oa_tc6 *= tc6, u8 *payload, u16 size) if (ret) return ret; =20 - oa_tc6_update_rx_skb(tc6, payload, size); - - return 0; + return oa_tc6_update_rx_skb(tc6, payload, size); } =20 -static void oa_tc6_prcs_rx_frame_end(struct oa_tc6 *tc6, u8 *payload, u16 = size) +static int oa_tc6_prcs_rx_frame_end(struct oa_tc6 *tc6, u8 *payload, u16 s= ize) { - oa_tc6_update_rx_skb(tc6, payload, size); + int ret; =20 - oa_tc6_submit_rx_skb(tc6); + ret =3D oa_tc6_update_rx_skb(tc6, payload, size); + if (!ret) + oa_tc6_submit_rx_skb(tc6); + return ret; } =20 -static void oa_tc6_prcs_ongoing_rx_frame(struct oa_tc6 *tc6, u8 *payload, - u32 footer) +static int oa_tc6_prcs_ongoing_rx_frame(struct oa_tc6 *tc6, u8 *payload, + u32 footer) { - oa_tc6_update_rx_skb(tc6, payload, OA_TC6_CHUNK_PAYLOAD_SIZE); + return oa_tc6_update_rx_skb(tc6, payload, + OA_TC6_CHUNK_PAYLOAD_SIZE); } =20 static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data, @@ -931,8 +966,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *= tc6, u8 *data, /* Process the chunk with only rx frame end */ if (end_valid && !start_valid) { size =3D end_byte_offset + 1; - oa_tc6_prcs_rx_frame_end(tc6, data, size); - return 0; + return oa_tc6_prcs_rx_frame_end(tc6, data, size); } =20 /* Process the chunk with previous rx frame end and next rx frame @@ -946,6 +980,14 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 = *tc6, u8 *data, if (tc6->rx_skb) { size =3D end_byte_offset + 1; oa_tc6_prcs_rx_frame_end(tc6, data, size); + + /* Purpose of rx_buf_overflow is make the + * code to look for new frame. At this + * stage, we have a new frame to process. + * So, making it false, in case it is set + * to true by oa_tc6_prcs_rx_frame_end. + */ + tc6->rx_buf_overflow =3D false; } size =3D OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset; return oa_tc6_prcs_rx_frame_start(tc6, @@ -954,9 +996,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *= tc6, u8 *data, } =20 /* Process the chunk with ongoing rx frame data */ - oa_tc6_prcs_ongoing_rx_frame(tc6, data, footer); - - return 0; + return oa_tc6_prcs_ongoing_rx_frame(tc6, data, footer); } =20 static u32 oa_tc6_get_rx_chunk_footer(struct oa_tc6 *tc6, u16 footer_offse= t) @@ -972,8 +1012,9 @@ static u32 oa_tc6_get_rx_chunk_footer(struct oa_tc6 *t= c6, u16 footer_offset) static int oa_tc6_process_spi_data_rx_buf(struct oa_tc6 *tc6, u16 length) { u16 no_of_rx_chunks =3D length / OA_TC6_CHUNK_SIZE; + bool retry =3D false; + int ret =3D 0; u32 footer; - int ret; =20 /* All the rx chunks in the receive SPI data buffer are examined here */ for (int i =3D 0; i < no_of_rx_chunks; i++) { @@ -982,8 +1023,11 @@ static int oa_tc6_process_spi_data_rx_buf(struct oa_t= c6 *tc6, u16 length) OA_TC6_CHUNK_PAYLOAD_SIZE); =20 ret =3D oa_tc6_process_rx_chunk_footer(tc6, footer); - if (ret) - return ret; + if (ret) { + if (ret !=3D -EAGAIN) + return ret; + retry =3D true; + } =20 /* If there is a data valid chunks then process it for the * information needed to determine the validity and the location @@ -995,12 +1039,35 @@ static int oa_tc6_process_spi_data_rx_buf(struct oa_= tc6 *tc6, u16 length) =20 ret =3D oa_tc6_prcs_rx_chunk_payload(tc6, payload, footer); - if (ret) - return ret; + if (ret) { + if (ret !=3D -ENOMEM && ret !=3D -EAGAIN) + return ret; + retry =3D true; + } } } =20 - return 0; + /* Not bailing out on recoverable error codes, -EAGAIN and + * -ENOMEM. If subsequent loop iterations, if any, succeeds, + * error code would be overwritten. retry flag helps to + * make the caller to continue and retry. Since recovery + * action for -ENOMEM and -EAGAIN are same, we are returning + * one of the error codes, that is -EAGAIN. + * + * Successful recovery depends on how small the frames are, + * how many chunks, among the received chunks triggered the + * error, whether data is intact even with error conditions. + * As a result, there is no single, best method to recover + * most data when error conditions hit. We do our best by + * processing all the chunks with good "footer header" and + * "data valid" bit set. + */ + if (retry) { + ret =3D -EAGAIN; + oa_tc6_look_for_new_frame(tc6); + } + + return ret; } =20 static __be32 oa_tc6_prepare_data_header(bool data_valid, bool start_valid, @@ -1162,10 +1229,12 @@ static int oa_tc6_try_spi_transfer(struct oa_tc6 *t= c6) } =20 ret =3D oa_tc6_process_spi_data_rx_buf(tc6, spi_len); - if (ret) { - if (ret =3D=3D -EAGAIN) - continue; =20 + /* Not continuing with the next iteration to give + * waiting_tx_skb a chance to get drained, if + * needed. + */ + if (ret && ret !=3D -EAGAIN) { oa_tc6_free_ongoing_skbs(tc6); netdev_err(tc6->netdev, "Device error: %d\n", ret); return ret; --=20 2.43.0 From nobody Sat Jul 25 01:37:51 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1BD8D3FE348; Tue, 21 Jul 2026 02:21:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784600492; cv=none; b=lUkNGfBToDtPnJWLDqGWckZEaQmosvFmTvSKoaImHUyubUBwzlVOMSrAnUs8pdvEPEQYKwAgduq77tYHsHMa89hi01c2yOIN1jQ9DEq+ePA7eq0A03vghitUKQvf6ZCmmq87HrAiizxBjjHWyCo5WRx2F21MZq6ToVCpG4koUD8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784600492; c=relaxed/simple; bh=/0ZxuVF2xdp9CxZy5Tn4QJ2tJtwZOwTJ5tMXtltKE2k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ik+I4guVrlpxAVFt+9qSHt3z5hnxi5oPYlH9c9nIPnrmuqHwM2W66eXiwRY/Ae0ArFb/jwxxcTmdegHmUcz70LkYZ1AIGk1JplirN798AM4ohGKhGsVbsHk/8iSHvwnMDlE90JVoaSkDQK2U6FAe9LPKXFTuPhOSCxSgM1ITXLc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=vFsIJCBk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="vFsIJCBk" Received: by smtp.kernel.org (Postfix) with ESMTPS id D5A06C2BCC9; Tue, 21 Jul 2026 02:21:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784600491; bh=/0ZxuVF2xdp9CxZy5Tn4QJ2tJtwZOwTJ5tMXtltKE2k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=vFsIJCBkAjWNxFMisza0J1xSPIuWN7EqEl0rTBrVT9s2KHFLdZVFTPAl5Zh7iU3xT K2PLZ+9SmjsnU88GFbBtFCdJ1S0dwN5anU6qjYzcpipwVX3+DZ1HS3aLk0JQPnOcLW hZVZg/189Haqp8nYZ4fueU23dxJ0g9fPn9lq5hJCFCQVmhEX40wqFYCkQilzANL7wh Viq4XsLBlurSK7CqWVjRubeqNHUQnBRRS1HXhPakhO3G2WmsdoVIeYujy+zc8DO5RS o663wr99zorF/dIB/nloDnOvVBRpEALt9L4jsSMIYHzQOjZzP+XfzFYRUJcx9eTLBQ jknfNX+PWtTPg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id BF581C4452D; Tue, 21 Jul 2026 02:21:31 +0000 (UTC) From: Selvamani Rajagopal via B4 Relay Date: Mon, 20 Jul 2026 19:20:37 -0700 Subject: [PATCH net v4 3/3] net: ethernet: oa_tc6: Disabled tx queues when disable_traffic is set Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260720-fix-race-condition-and-crash-v4-3-8273e2f38a1f@onsemi.com> References: <20260720-fix-race-condition-and-crash-v4-0-8273e2f38a1f@onsemi.com> In-Reply-To: <20260720-fix-race-condition-and-crash-v4-0-8273e2f38a1f@onsemi.com> To: Parthiban Veerasooran , Andrew Lunn , Piergiorgio Beruto , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Andrew Lunn , Parthiban Veerasooran , Selvamani Rajagopal X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784600442; l=1302; i=Selvamani.Rajagopal@onsemi.com; s=20260531; h=from:subject:message-id; bh=G5SfllbV/PC7FsuuOcRTYnuvtsbR0nxTKy7i93ghP+4=; b=/61oGyRTdppdnWwmvQewbMjpmLAPT1+acCoE67og71xTheZQwqpEWQ/NRgoOCuCAqlG1nChZk LMvjluVFg6TAv/+EiIsK09amwYSrTbao1ZeAjtrgVHjOm5AosbpzzZB X-Developer-Key: i=Selvamani.Rajagopal@onsemi.com; a=ed25519; pk=5QRdM0HS/LGWWcUZZ9hVfZ+qbPQGZCumcTXOiN7Fyug= X-Endpoint-Received: by B4 Relay for Selvamani.Rajagopal@onsemi.com/20260531 with auth_id=803 X-Original-From: Selvamani Rajagopal Reply-To: Selvamani.Rajagopal@onsemi.com From: Selvamani Rajagopal Previously, TX queue interface was stopped when disable_traffic flag was set. It is more appropriate to disable the queue as there is no recovery, once disable_traffic is set. Carrier is also marked off Fixes: b542d13fab0f ("net: ethernet: oa_tc6: Interrupt is active low, level= triggered.") Signed-off-by: Selvamani Rajagopal changes in v4 - Reverted the the statement that turned carrier off on disble_traffic, as it may have side effects changes in v3 - New patch. Carrier marked off once disable_traffic is set --- drivers/net/ethernet/oa_tc6.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 9e6850ccfe6c..4b8f6280be51 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -730,6 +730,11 @@ static void oa_tc6_disable_traffic(struct oa_tc6 *tc6) skb =3D oa_tc6_detach_waiting_tx_skb(tc6); spin_unlock_bh(&tc6->tx_skb_lock); =20 + /* disable_traffic, when set, is a point of no + * return to working state. TX queues are + * disabled. + */ + netif_tx_disable(tc6->netdev); oa_tc6_drop_tx_skb(tc6, skb); oa_tc6_free_ongoing_skbs(tc6); oa_tc6_write_register(tc6, OA_TC6_REG_INT_MASK0, regval); --=20 2.43.0