Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v2 04/18] dt-bindings: clock: mediatek: reorder MT8186 compatibles
From: Conor Dooley @ 2026-07-09 18:09 UTC (permalink / raw)
  To: Louis-Alexis Eyraud
  Cc: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran, kernel, linux-clk, devicetree,
	linux-kernel, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260709-mt8189-clocks-system-base-v2-4-2926da3db6cf@collabora.com>

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v2 03/18] dt-bindings: clock: mediatek: Make '#clock-cells' required for MT8195
From: Conor Dooley @ 2026-07-09 18:09 UTC (permalink / raw)
  To: Louis-Alexis Eyraud
  Cc: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran, kernel, linux-clk, devicetree,
	linux-kernel, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260709-mt8189-clocks-system-base-v2-3-2926da3db6cf@collabora.com>

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v2 02/18] dt-bindings: clock: mediatek: Make '#clock-cells' required for MT8192
From: Conor Dooley @ 2026-07-09 18:08 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno
  Cc: Louis-Alexis Eyraud, Michael Turquette, Stephen Boyd,
	Brian Masney, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, Chun-Jie Chen, Philipp Zabel, Edward-JW Yang,
	Richard Cochran, kernel, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <ff0f6f05-8445-459e-9c21-13f3dd57c4c4@collabora.com>

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v2 01/18] dt-bindings: clock: mediatek: Make '#clock-cells' required for MT8186
From: Conor Dooley @ 2026-07-09 18:08 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno
  Cc: Louis-Alexis Eyraud, Michael Turquette, Stephen Boyd,
	Brian Masney, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, Chun-Jie Chen, Philipp Zabel, Edward-JW Yang,
	Richard Cochran, kernel, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <fe7dee8d-afe9-441e-898b-695aacf1aa04@collabora.com>

[-- Attachment #1: Type: text/plain, Size: 1099 bytes --]

On Thu, Jul 09, 2026 at 04:01:49PM +0200, AngeloGioacchino Del Regno wrote:
> On 7/9/26 15:42, Louis-Alexis Eyraud wrote:
> > Both MT8186 clock controllers dt-bindings (clock and sys-clock)
> > document the '#clock-cells' property but do not enforce it as required
> > property.
> > As clock provider nodes should define this property in devicetrees, add
> > it to the required property list in both its dt-bindings files.
> > 
> > Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
> 
> Though you could've done that in one commit, or just skipped the additions in all
> of mt8186/92/95 and went directly for the new one... IMO, it's ok as you're showing
> that there was an actual mistake on the bindings for clock controllers.
> 
> Same comment applies for patch 2 and 3, btw.
> 
> Anyway:
> 
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> 

Prob should have a fixes tag too.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

(sorry if you got this twice, mutt crashed while sending)

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCHv2 net-next 6/7] net: usb: remove dependencies on cdc_ether
From: Sergey Shtylyov @ 2026-07-09 18:08 UTC (permalink / raw)
  To: Oliver Neukum, andrew+netdev, davem, edumazet, kuba, pabeni,
	netdev, linux-usb, linux-kernel, manuelebner
In-Reply-To: <20260709120116.1423033-6-oneukum@suse.com>

On 7/9/26 3:01 PM, Oliver Neukum wrote:

> Now that the driver no longer exports symbols to act
> as a library for other drivers other drivers don't
> depend on it. Remove the dependencies.
> 
> Signed-off-by: Oliver Neukum <oneukum@suse.com>
> ---
> 
> v2:
> - added to allow removal of dependencies
> 
>  drivers/net/usb/Kconfig | 7 ++-----
>  1 file changed, 2 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
> index da0f6a138f4f..622ff080218e 100644
> --- a/drivers/net/usb/Kconfig
> +++ b/drivers/net/usb/Kconfig
[...]> @@ -634,7 +631,7 @@ config USB_NET_AQC111
>  
>  config USB_RTL8153_ECM
>  	tristate
> -	depends on USB_NET_CDCETHER && (USB_RTL8152 || USB_RTL8152=n)
> +	depends on (USB_RTL8152 || USB_RTL8152=n)

   I think you could drop the parens, while at it...

[...]

MBR, Sergey


^ permalink raw reply

* Re: [PATCH net-next V5 4/6] devlink: Apply eswitch mode boot defaults
From: Mark Bloch @ 2026-07-09 18:06 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Andrew Lunn,
	Jonathan Corbet, Shuah Khan, netdev, linux-rdma, linux-doc
In-Reply-To: <ak9thhKgtDBepkcD@FV6GYCPJ69>



On 09/07/2026 12:46, Jiri Pirko wrote:
> Thu, Jul 09, 2026 at 07:45:20AM +0200, mbloch@nvidia.com wrote:
>>
>>
>> On 08/07/2026 11:59, Jiri Pirko wrote:
>>> Tue, Jul 07, 2026 at 07:45:25PM +0200, mbloch@nvidia.com wrote:
>>>> Apply parsed devlink_eswitch_mode= defaults after devlink registration
>>>> and after successful reload.
>>>>
>>>> devl_register() may still be called before the device is ready for an
>>>> eswitch mode change. Keep the registration path passive and let the
>>>> regular devl_unlock() path queue the async apply work once the instance
>>>> is registered and the default is still pending.
>>>>
>>>> The queueing path runs while the devlink instance lock is held, so the
>>>> queued work gets its devlink reference before the caller drops the lock.
>>>> The worker then takes the devlink instance lock normally and applies the
>>>> default only if the instance is still registered and the default is still
>>>> pending.
>>>
>>> This is very code-descriptive. What's the benefit of that?
>>
>> The point is that there is still a window before the queued work
>> runs where the user can explicitly set the eswitch mode. If they 
>> do, the default will no longer be pending, so the worker will skip
>> applying it.
>>
>> I'll reword.
>>
>>>
>>>
>>>>
>>>> For successful reloads that performed DRIVER_REINIT, devlink_reload()
>>>> already holds the devlink instance lock and the driver has completed
>>>> reload_up(). Clear pending work and apply the default directly from the
>>>> reload path instead of queueing work.
>>>>
>>>> Preserve the user configured mode when it is set before devlink applies
>>>> the default.
>>>>
>>>
>>> [..]
>>>
>>>
>>>> +void devlink_default_esw_mode_apply_locked(struct devlink *devlink)
>>>> +{
>>>> +	const struct devlink_ops *ops = devlink->ops;
>>>> +	int err;
>>>> +
>>>> +	devl_assert_locked(devlink);
>>>> +
>>>> +	if (!devlink_default_esw_mode_match(devlink))
>>>> +		return;
>>>> +
>>>> +	if (!ops->eswitch_mode_set) {
>>>> +		if (!devlink_default_esw_mode_match_all)
>>>> +			devl_warn(devlink,
>>>> +				  "devlink_eswitch_mode= selected this device but eswitch mode setting is not supported\n");
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	err = devlink_eswitch_mode_set(devlink, devlink_default_esw_mode, NULL);
>>>> +	if (err)
>>>> +		devl_warn(devlink,
>>>> +			  "Couldn't apply default eswitch mode, err %d\n",
>>>> +			  err);
>>>> +}
>>>> +
>>>> +void devlink_default_esw_mode_queue_apply_work(struct devlink *devlink)
>>>
>>> eswitch/esw - we call it "eswitch" consistently everywhere. Why "esw"
>>> here?
>>
>> Ack
>>
>>>
>>>
>>>
>>>> +{
>>>> +	devl_assert_locked(devlink);
>>>> +
>>>> +	if (!devlink_default_esw_mode_enabled || !devlink_default_esw_mode_wq)
>>>> +		return;
>>>> +	if (!devlink->default_esw_mode_apply_pending ||
>>>> +	    !__devl_is_registered(devlink))
>>>> +		return;
>>>> +	if (!devlink_try_get(devlink))
>>>> +		return;
>>>> +	if (!queue_work(devlink_default_esw_mode_wq,
>>>> +			&devlink->default_esw_mode_apply_work))
>>>> +		devlink_put(devlink);
>>>> +}
>>>> +
>>>> +static void devlink_default_esw_mode_apply_work(struct work_struct *work)
>>>> +{
>>>> +	struct devlink *devlink;
>>>> +
>>>> +	devlink = container_of(work, struct devlink,
>>>> +			       default_esw_mode_apply_work);
>>>> +
>>>
>>> What happens if userspace eswitch mode set happens now? Any userspace
>>> attempt should cancel the default apply. I don't see such mechanism in
>>> your patches, did I miss it?
>>
>> devlink_nl_eswitch_set_doit() calls
>> devlink_default_esw_mode_apply_pending_clear(), which clears the
>> pending bit.
>>
>> So if a user sets the eswitch mode before the queued default
>> work applies it, the worker will see that the default is no longer
>> pending and will do nothing
> 
> Okay.
> 
> 
>>
>>>
>>>
>>>
>>>> +	devl_lock(devlink);
>>>> +
>>>> +	if (devl_is_registered(devlink) &&
>>>> +	    devlink->default_esw_mode_apply_pending) {
>>>> +		devlink_default_esw_mode_apply_locked(devlink);
>>>> +		devlink->default_esw_mode_apply_pending = false;
>>>> +	}
>>>> +
>>>> +	devl_unlock(devlink);
>>>> +	devlink_put(devlink);
>>>> +}
>>>> +
>>>> +void devlink_default_esw_mode_instance_init(struct devlink *devlink)
>>>
>>> Why "_instance_"? Care to drop?
>>
>> Ack
>>
>>>
>>>
>>>> +{
>>>> +	INIT_WORK(&devlink->default_esw_mode_apply_work,
>>>> +		  devlink_default_esw_mode_apply_work);
>>>> +	devlink->default_esw_mode_apply_pending = true;
>>>> +}
>>>> +
>>>> +void devlink_default_esw_mode_apply_pending_clear(struct devlink *devlink)
>>>> +{
>>>> +	devl_assert_locked(devlink);
>>>> +
>>>> +	devlink->default_esw_mode_apply_pending = false;
>>>> +}
>>>> +
>>>> +void devlink_default_esw_mode_instance_cleanup(struct devlink *devlink)
>>>
>>> Why "_instance_"? Care to drop?
>>
>> Ack
>>
>>>
>>>
>>>> +{
>>>> +	if (cancel_work_sync(&devlink->default_esw_mode_apply_work))
>>>> +		devlink_put(devlink);
>>>> +}
>>>> +
>>>> static int __init devlink_default_esw_mode_setup(char *str)
>>>> {
>>>> 	devlink_default_esw_mode_param = str;
>>>> @@ -228,10 +325,21 @@ int __init devlink_default_esw_mode_init(void)
>>>> 		return err;
>>>> 	}
>>>>
>>>> +	devlink_default_esw_mode_wq = alloc_workqueue("devlink_default_esw_mode",
>>>> +						      WQ_UNBOUND | WQ_MEM_RECLAIM,
>>>> +						      0);
>>>> +	if (!devlink_default_esw_mode_wq) {
>>>> +		devlink_default_esw_mode_param = NULL;
>>>> +		devlink_default_esw_mode_nodes_clear();
>>>> +		pr_warn("devlink: devlink_eswitch_mode parameter ignored, failed to allocate workqueue\n");
>>>
>>> Why you don't "return"  here? I think that we don't need to allow the
>>> case wq is not allocated.
>>
>> The function returns right after this block. It is not treated
> 
> What I ment was "return error".
> 
> 
>> as a valid “workqueue unavailable” mode, the parsed defaults are
>> cleared, the parameter is ignored, and no default eswitch mode will
>> be applied.
>>
>> I kept it as a non critical failure so we do not abort the whole
>> devlink init just because the default-mode workqueue could not be
>> allocated.
> 
> Why to treat it like this? Is there any other example of such flow in
> devlink? I don't see the benefit, only potential confusion in very
> unlikely case the alloc_workqueue fails. Am I wrong? If not, just bail
> out here.

As I'm dropping the work queue it doesn't matter. I'll treat failed
parsing as error then.

Mark

> 
> 
> 
>>
>> That said, I can make this more explicit by returning 0 directly
>>from this error path.
>>
>> Mark
>>
>>>
>>>
>>>> +	}
>>>> +
>>>> 	return 0;
>>>> }
>>>>
>>>> void __init devlink_default_esw_mode_cleanup(void)
>>>> {
>>>> +	if (devlink_default_esw_mode_wq)
>>>> +		destroy_workqueue(devlink_default_esw_mode_wq);
>>>> 	devlink_default_esw_mode_nodes_clear();
>>>> }
>>>
>>> [..]
>>


^ permalink raw reply

* Re: [PATCH net-next 04/11] igb: prepare for RSS key get/set support
From: Tony Nguyen @ 2026-07-09 17:52 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: Takashi Kozu, horms, enjuk, kohei.enju, Piotr Kwapulinski,
	Aleksandr Loktionov, Rinitha S
In-Reply-To: <20260701210303.1745310-5-anthony.l.nguyen@intel.com>

On 7/1/2026 2:02 PM, Tony Nguyen wrote:
> From: Takashi Kozu <takkozu@amazon.com>
...

> +/**
> + * igb_write_rss_key - Program the RSS key into device registers
> + * @adapter: board private structure
> + *
> + * Write the RSS key stored in adapter->rss_key to the E1000 hardware registers.
> + * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
> + * to the appropriate register.
> + */
> +void igb_write_rss_key(struct igb_adapter *adapter)
> +{
> +	struct e1000_hw *hw = &adapter->hw;
> +
> +	ASSERT_RTNL();

Hi Takashi-san,

Sashiko flags this for the power management path.

"
Will the new ASSERT_RTNL() in igb_write_rss_key() trigger a false-positive
kernel warning during runtime power management resume?
When the device undergoes runtime PM suspend and then wakes up,
igb_runtime_resume() is called. This passes rpm=true to __igb_resume(), 
which
explicitly skips acquiring the rtnl_lock() to avoid deadlocks.
__igb_resume() then calls __igb_open(), which cascades to igb_configure(),
igb_setup_mrqc(), and finally igb_write_rss_key(). Because the lock is
intentionally not held on this path, the ASSERT_RTNL() will fail and 
trigger a
WARN_ONCE.
Is it possible to remove this assertion or adjust it to account for the
runtime PM resume path?
"

Kohei-san's version in igc did not have this and it does share similar 
flows with igc. I'm not sure if you added this for a specific reason but 
would you be able to send a follow up patch to adjust or remove this?

Thanks,
Tony

> +
> +	for (int i = 0; i < IGB_RSS_KEY_SIZE / 4; i++) {
> +		u32 val = get_unaligned_le32(&adapter->rss_key[i * 4]);
> +
> +		wr32(E1000_RSSRK(i), val);
> +	}
> +}
> +


^ permalink raw reply

* [PATCH net-next 2/2] net: atlantic: convert RX path to page_pool
From: Yangyu Chen @ 2026-07-09 17:37 UTC (permalink / raw)
  To: Sukhdeep Singh, Andrew Lunn, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni
  Cc: netdev, bpf, linux-kernel, Jesper Dangaard Brouer,
	Richard Cochran, Lino Sanfilippo, Yangyu Chen
In-Reply-To: <tencent_7DB01BE7F8FA056BB5F11D3570CF636C4309@qq.com>

The driver currently allocates RX buffers with dev_alloc_pages(), maps
them with dma_map_page(), and uses a hand-rolled page-flip scheme to
subdivide high-order pages. Behind an IOMMU, the map/unmap churn is a
major RX cost: on a Thunderbolt-attached QNAP QNA-T310G1S, iperf3 -R
over IPv6 tops out at about 2.2 Gbit/s over MTU 1500.

Convert RX buffers to page_pool fragments. Pages are DMA-mapped once
when entering the pool and recycled through the stack or XDP via the
MEM_TYPE_PAGE_POOL memory model. This removes the custom page-flip
accounting, lets page_pool handle fragment reuse, and ensures every RX
path either keeps the ring's fragment reference for reposting or hands
it to the skb/xdp_buff for later recycling.

Register the PTP RX ring's xdp_rxq as well, since it shares the RX
clean paths. Walk the full RX ring during deinit so consumed but not yet
refilled slots cannot leak page-pool references. Drop the ethtool
PageFlips/PageReuses/PageFrees counters which only described the old
scheme.

On the QNA-T310G1S, MTU 1500, TCP over IPv6, iperf3 -R improves from
2.24 Gbit/s to 9.14 Gbit/s. The module was also smoke-tested with native
XDP PASS, DROP, and ABORTED actions; carrier recovered after each
attach/detach cycle and dmesg showed no page_pool/DMA warnings.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Yangyu Chen <cyy@cyyself.name>
---
 drivers/net/ethernet/aquantia/Kconfig         |   1 +
 .../ethernet/aquantia/atlantic/aq_ethtool.c   |   3 -
 .../net/ethernet/aquantia/atlantic/aq_ptp.c   |  20 +-
 .../net/ethernet/aquantia/atlantic/aq_ring.c  | 238 ++++++++----------
 .../net/ethernet/aquantia/atlantic/aq_ring.h  |   6 +-
 .../net/ethernet/aquantia/atlantic/aq_vec.c   |  15 +-
 6 files changed, 140 insertions(+), 143 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/Kconfig b/drivers/net/ethernet/aquantia/Kconfig
index cec2018c84a9..c8fb7b33e5b7 100644
--- a/drivers/net/ethernet/aquantia/Kconfig
+++ b/drivers/net/ethernet/aquantia/Kconfig
@@ -20,6 +20,7 @@ config AQTION
 	tristate "aQuantia AQtion(tm) Support"
 	depends on PCI
 	depends on MACSEC || MACSEC=n
+	select PAGE_POOL
 	help
 	  This enables the support for the aQuantia AQtion(tm) Ethernet card.
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 420af958d486..0f5125bd2315 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -100,9 +100,6 @@ static const char * const aq_ethtool_queue_rx_stat_names[] = {
 	"%sQueue[%d] AllocFails",
 	"%sQueue[%d] SkbAllocFails",
 	"%sQueue[%d] Polls",
-	"%sQueue[%d] PageFlips",
-	"%sQueue[%d] PageReuses",
-	"%sQueue[%d] PageFrees",
 	"%sQueue[%d] XdpAbort",
 	"%sQueue[%d] XdpDrop",
 	"%sQueue[%d] XdpPass",
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
index 558ac9237f75..5b8a4d0d1cff 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
@@ -13,6 +13,7 @@
 #include <linux/ptp_classify.h>
 #include <linux/interrupt.h>
 #include <linux/clocksource.h>
+#include <net/xdp.h>
 
 #include "aq_nic.h"
 #include "aq_ptp.h"
@@ -1192,12 +1193,25 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
 	if (err)
 		goto err_exit_ptp_tx;
 
+	err = xdp_rxq_info_reg(&aq_ptp->ptp_rx.xdp_rxq, aq_nic->ndev,
+			       rx_ring_idx, aq_ptp->napi.napi_id);
+	if (err < 0)
+		goto err_exit_ptp_rx;
+
+	err = xdp_rxq_info_reg_mem_model(&aq_ptp->ptp_rx.xdp_rxq,
+					 MEM_TYPE_PAGE_POOL,
+					 aq_ptp->ptp_rx.pg_pool);
+	if (err < 0) {
+		xdp_rxq_info_unreg(&aq_ptp->ptp_rx.xdp_rxq);
+		goto err_exit_ptp_rx;
+	}
+
 	if (aq_ptp->a1_ptp) {
 		err = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
 					    aq_nic->aq_nic_cfg.rxds,
 					    aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
 		if (err)
-			goto err_exit_ptp_rx;
+			goto err_exit_xdp_rxq;
 	}
 
 	err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds);
@@ -1217,6 +1231,8 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
 err_exit_hwts_rx:
 	if (aq_ptp->a1_ptp)
 		aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
+err_exit_xdp_rxq:
+	xdp_rxq_info_unreg(&aq_ptp->ptp_rx.xdp_rxq);
 err_exit_ptp_rx:
 	aq_ring_free(&aq_ptp->ptp_rx);
 err_exit_ptp_tx:
@@ -1233,6 +1249,8 @@ void aq_ptp_ring_free(struct aq_nic_s *aq_nic)
 		return;
 
 	aq_ring_free(&aq_ptp->ptp_tx);
+	if (xdp_rxq_info_is_reg(&aq_ptp->ptp_rx.xdp_rxq))
+		xdp_rxq_info_unreg(&aq_ptp->ptp_rx.xdp_rxq);
 	aq_ring_free(&aq_ptp->ptp_rx);
 	if (aq_ptp->a1_ptp)
 		aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index c59b6c0b37f1..e06c502b59f9 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -14,120 +14,37 @@
 #include "aq_vec.h"
 #include "aq_main.h"
 
+#include <net/page_pool/helpers.h>
 #include <net/xdp.h>
 #include <linux/filter.h>
 #include <linux/bpf_trace.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 
-static void aq_get_rxpages_xdp(struct aq_ring_buff_s *buff,
-			       struct xdp_buff *xdp)
-{
-	struct skb_shared_info *sinfo;
-	int i;
-
-	if (xdp_buff_has_frags(xdp)) {
-		sinfo = xdp_get_shared_info_from_buff(xdp);
-
-		for (i = 0; i < sinfo->nr_frags; i++) {
-			skb_frag_t *frag = &sinfo->frags[i];
-
-			page_ref_inc(skb_frag_page(frag));
-		}
-	}
-	page_ref_inc(buff->rxdata.page);
-}
-
-static inline void aq_free_rxpage(struct aq_rxpage *rxpage, struct device *dev)
-{
-	unsigned int len = PAGE_SIZE << rxpage->order;
-
-	dma_unmap_page(dev, rxpage->daddr, len, DMA_FROM_DEVICE);
-
-	/* Drop the ref for being in the ring. */
-	__free_pages(rxpage->page, rxpage->order);
-	rxpage->page = NULL;
-}
-
-static int aq_alloc_rxpages(struct aq_rxpage *rxpage, struct aq_ring_s *rx_ring)
+static int aq_get_rxpages(struct aq_ring_s *self, struct aq_ring_buff_s *rxbuf)
 {
-	struct device *dev = aq_nic_get_dev(rx_ring->aq_nic);
-	unsigned int order = rx_ring->page_order;
+	unsigned int size = self->page_offset + self->frame_max +
+			    self->tail_size;
+	unsigned int pg_off;
 	struct page *page;
-	int ret = -ENOMEM;
-	dma_addr_t daddr;
-
-	page = dev_alloc_pages(order);
-	if (unlikely(!page))
-		goto err_exit;
 
-	daddr = dma_map_page(dev, page, 0, PAGE_SIZE << order,
-			     DMA_FROM_DEVICE);
+	/* Buffers whose page was not passed up the stack are reposted
+	 * with the data they already carry discarded.
+	 */
+	if (rxbuf->rxdata.page)
+		return 0;
 
-	if (unlikely(dma_mapping_error(dev, daddr)))
-		goto free_page;
-
-	rxpage->page = page;
-	rxpage->daddr = daddr;
-	rxpage->order = order;
-	rxpage->pg_off = rx_ring->page_offset;
-
-	return 0;
-
-free_page:
-	__free_pages(page, order);
-
-err_exit:
-	return ret;
-}
-
-static int aq_get_rxpages(struct aq_ring_s *self, struct aq_ring_buff_s *rxbuf)
-{
-	unsigned int order = self->page_order;
-	u16 page_offset = self->page_offset;
-	u16 frame_max = self->frame_max;
-	u16 tail_size = self->tail_size;
-	int ret;
-
-	if (rxbuf->rxdata.page) {
-		/* One means ring is the only user and can reuse */
-		if (page_ref_count(rxbuf->rxdata.page) > 1) {
-			/* Try reuse buffer */
-			rxbuf->rxdata.pg_off += frame_max + page_offset +
-						tail_size;
-			if (rxbuf->rxdata.pg_off + frame_max + tail_size <=
-			    (PAGE_SIZE << order)) {
-				u64_stats_update_begin(&self->stats.rx.syncp);
-				self->stats.rx.pg_flips++;
-				u64_stats_update_end(&self->stats.rx.syncp);
-
-			} else {
-				/* Buffer exhausted. We have other users and
-				 * should release this page and realloc
-				 */
-				aq_free_rxpage(&rxbuf->rxdata,
-					       aq_nic_get_dev(self->aq_nic));
-				u64_stats_update_begin(&self->stats.rx.syncp);
-				self->stats.rx.pg_losts++;
-				u64_stats_update_end(&self->stats.rx.syncp);
-			}
-		} else {
-			rxbuf->rxdata.pg_off = page_offset;
-			u64_stats_update_begin(&self->stats.rx.syncp);
-			self->stats.rx.pg_reuses++;
-			u64_stats_update_end(&self->stats.rx.syncp);
-		}
+	page = page_pool_dev_alloc_frag(self->pg_pool, &pg_off, size);
+	if (unlikely(!page)) {
+		u64_stats_update_begin(&self->stats.rx.syncp);
+		self->stats.rx.alloc_fails++;
+		u64_stats_update_end(&self->stats.rx.syncp);
+		return -ENOMEM;
 	}
 
-	if (!rxbuf->rxdata.page) {
-		ret = aq_alloc_rxpages(&rxbuf->rxdata, self);
-		if (ret) {
-			u64_stats_update_begin(&self->stats.rx.syncp);
-			self->stats.rx.alloc_fails++;
-			u64_stats_update_end(&self->stats.rx.syncp);
-		}
-		return ret;
-	}
+	rxbuf->rxdata.page = page;
+	rxbuf->rxdata.daddr = page_pool_get_dma_addr(page);
+	rxbuf->rxdata.pg_off = pg_off + self->page_offset;
 
 	return 0;
 }
@@ -179,6 +96,15 @@ int aq_ring_rx_alloc(struct aq_ring_s *self,
 		     unsigned int idx,
 		     struct aq_nic_cfg_s *aq_nic_cfg)
 {
+	struct page_pool_params pp_params = {
+		.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
+		.pool_size = aq_nic_cfg->rxds,
+		.nid = NUMA_NO_NODE,
+		.dev = aq_nic_get_dev(aq_nic),
+		.dma_dir = DMA_FROM_DEVICE,
+	};
+	struct page_pool *pool;
+
 	self->aq_nic = aq_nic;
 	self->idx = idx;
 	self->size = aq_nic_cfg->rxds;
@@ -200,6 +126,18 @@ int aq_ring_rx_alloc(struct aq_ring_s *self,
 		self->tail_size = 0;
 	}
 
+	pp_params.order = self->page_order;
+	pp_params.max_len = PAGE_SIZE << self->page_order;
+
+	pool = page_pool_create(&pp_params);
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+
+	self->pg_pool = pool;
+
+	/* On failure aq_ring_alloc() calls aq_ring_free(), which also
+	 * destroys the page pool.
+	 */
 	return aq_ring_alloc(self, aq_nic);
 }
 
@@ -346,7 +284,11 @@ bool aq_ring_tx_clean(struct aq_ring_s *self)
 			++self->stats.tx.packets;
 			self->stats.tx.bytes += xdp_get_frame_len(buff->xdpf);
 			u64_stats_update_end(&self->stats.tx.syncp);
-			xdp_return_frame_rx_napi(buff->xdpf);
+			/* Frames queued via ndo_xdp_xmit() may come from a
+			 * page pool owned by another NAPI context: no direct
+			 * recycling.
+			 */
+			xdp_return_frame(buff->xdpf);
 		}
 
 out:
@@ -438,22 +380,15 @@ int aq_xdp_xmit(struct net_device *dev, int num_frames,
 }
 
 static struct sk_buff *aq_xdp_build_skb(struct xdp_buff *xdp,
-					struct net_device *dev,
-					struct aq_ring_buff_s *buff)
+					struct net_device *dev)
 {
 	struct xdp_frame *xdpf;
-	struct sk_buff *skb;
 
 	xdpf = xdp_convert_buff_to_frame(xdp);
 	if (unlikely(!xdpf))
 		return NULL;
 
-	skb = xdp_build_skb_from_frame(xdpf, dev);
-	if (!skb)
-		return NULL;
-
-	aq_get_rxpages_xdp(buff, xdp);
-	return skb;
+	return xdp_build_skb_from_frame(xdpf, dev);
 }
 
 static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
@@ -474,8 +409,16 @@ static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
 	u64_stats_update_end(&rx_ring->stats.rx.syncp);
 
 	prog = READ_ONCE(rx_ring->xdp_prog);
-	if (!prog)
-		return aq_xdp_build_skb(xdp, aq_nic->ndev, buff);
+	if (!prog) {
+		skb = aq_xdp_build_skb(xdp, aq_nic->ndev);
+		/* The ring has already handed its page pool reference to the
+		 * xdp_buff, so if the skb could not be built the buffer must
+		 * be returned to the pool here or its fragments would leak.
+		 */
+		if (!skb)
+			xdp_return_buff(xdp);
+		return skb;
+	}
 
 	prefetchw(xdp->data_hard_start); /* xdp_frame write */
 
@@ -486,7 +429,7 @@ static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
 	act = bpf_prog_run_xdp(prog, xdp);
 	switch (act) {
 	case XDP_PASS:
-		skb = aq_xdp_build_skb(xdp, aq_nic->ndev, buff);
+		skb = aq_xdp_build_skb(xdp, aq_nic->ndev);
 		if (!skb)
 			goto out_aborted;
 		u64_stats_update_begin(&rx_ring->stats.rx.syncp);
@@ -504,7 +447,6 @@ static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
 		u64_stats_update_begin(&rx_ring->stats.rx.syncp);
 		++rx_ring->stats.rx.xdp_tx;
 		u64_stats_update_end(&rx_ring->stats.rx.syncp);
-		aq_get_rxpages_xdp(buff, xdp);
 		break;
 	case XDP_REDIRECT:
 		if (xdp_do_redirect(aq_nic->ndev, xdp, prog) < 0)
@@ -513,7 +455,6 @@ static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
 		u64_stats_update_begin(&rx_ring->stats.rx.syncp);
 		++rx_ring->stats.rx.xdp_redirect;
 		u64_stats_update_end(&rx_ring->stats.rx.syncp);
-		aq_get_rxpages_xdp(buff, xdp);
 		break;
 	default:
 		fallthrough;
@@ -524,11 +465,13 @@ static struct sk_buff *aq_xdp_run_prog(struct aq_nic_s *aq_nic,
 		u64_stats_update_end(&rx_ring->stats.rx.syncp);
 		trace_xdp_exception(aq_nic->ndev, prog, act);
 		bpf_warn_invalid_xdp_action(aq_nic->ndev, prog, act);
+		xdp_return_buff(xdp);
 		break;
 	case XDP_DROP:
 		u64_stats_update_begin(&rx_ring->stats.rx.syncp);
 		++rx_ring->stats.rx.xdp_drop;
 		u64_stats_update_end(&rx_ring->stats.rx.syncp);
+		xdp_return_buff(xdp);
 		break;
 	}
 
@@ -547,8 +490,11 @@ static bool aq_add_rx_fragment(struct device *dev,
 	do {
 		skb_frag_t *frag;
 
-		if (unlikely(sinfo->nr_frags >= MAX_SKB_FRAGS))
+		if (unlikely(sinfo->nr_frags >= MAX_SKB_FRAGS)) {
+			/* Attached frags must reach xdp_return_buff() */
+			xdp_buff_set_frags_flag(xdp);
 			return true;
+		}
 
 		frag = &sinfo->frags[sinfo->nr_frags++];
 		buff_ = &ring->buff_ring[buff_->next];
@@ -572,6 +518,11 @@ static bool aq_add_rx_fragment(struct device *dev,
 		if (page_is_pfmemalloc(buff_->rxdata.page))
 			xdp_buff_set_frag_pfmemalloc(xdp);
 
+		/* The frag's page pool reference is owned by the xdp_buff
+		 * from now on.
+		 */
+		buff_->rxdata.page = NULL;
+
 	} while (!buff_->is_eop);
 
 	xdp_buff_set_frags_flag(xdp);
@@ -675,6 +626,7 @@ static int __aq_ring_rx_clean(struct aq_ring_s *self, struct napi_struct *napi,
 			err = -ENOMEM;
 			goto err_exit;
 		}
+		skb_mark_for_recycle(skb);
 		if (is_ptp_ring)
 			buff->len -=
 				aq_ptp_extract_ts(self->aq_nic, skb_hwtstamps(skb),
@@ -695,7 +647,7 @@ static int __aq_ring_rx_clean(struct aq_ring_s *self, struct napi_struct *napi,
 					buff->rxdata.pg_off + hdr_len,
 					buff->len - hdr_len,
 					self->frame_max);
-			page_ref_inc(buff->rxdata.page);
+			buff->rxdata.page = NULL;
 		}
 
 		if (!buff->is_eop) {
@@ -714,7 +666,7 @@ static int __aq_ring_rx_clean(struct aq_ring_s *self, struct napi_struct *napi,
 						buff_->rxdata.pg_off,
 						buff_->len,
 						self->frame_max);
-				page_ref_inc(buff_->rxdata.page);
+				buff_->rxdata.page = NULL;
 				buff_->is_cleaned = 1;
 
 				buff->is_ip_cso &= buff_->is_ip_cso;
@@ -852,6 +804,11 @@ static int __aq_ring_xdp_clean(struct aq_ring_s *rx_ring,
 		xdp_init_buff(&xdp, frame_sz, &rx_ring->xdp_rxq);
 		xdp_prepare_buff(&xdp, hard_start, rx_ring->page_offset,
 				 buff->len, false);
+		/* The xdp_buff owns the buffer's page pool reference from
+		 * here on; it comes back through the MEM_TYPE_PAGE_POOL
+		 * memory model on every XDP verdict.
+		 */
+		buff->rxdata.page = NULL;
 		if (!buff->is_eop) {
 			if (aq_add_rx_fragment(dev, rx_ring, buff, &xdp)) {
 				u64_stats_update_begin(&rx_ring->stats.rx.syncp);
@@ -859,6 +816,7 @@ static int __aq_ring_xdp_clean(struct aq_ring_s *rx_ring,
 				rx_ring->stats.rx.bytes += xdp_get_buff_len(&xdp);
 				++rx_ring->stats.rx.xdp_aborted;
 				u64_stats_update_end(&rx_ring->stats.rx.syncp);
+				xdp_return_buff(&xdp);
 				continue;
 			}
 		}
@@ -951,15 +909,37 @@ int aq_ring_rx_fill(struct aq_ring_s *self)
 
 void aq_ring_rx_deinit(struct aq_ring_s *self)
 {
-	if (!self)
+	unsigned int i;
+
+	/* The ring may already be gone: on a partial aq_ptp_ring_alloc()
+	 * failure the unwind frees it but leaves aq_nic set, so the
+	 * deinit paths still get here.
+	 */
+	if (!self || !self->buff_ring)
 		return;
 
-	for (; self->sw_head != self->sw_tail;
-		self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
-		struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
+	/* Release every fragment still owned by the ring, or
+	 * page_pool_destroy() will stall on the outstanding references.
+	 *
+	 * Walking [sw_head, sw_tail) is not enough: refill is batched
+	 * (aq_ring_rx_fill() waits for AQ_CFG_RX_REFILL_THRES free slots),
+	 * so slots that were cleaned but not yet reposted accumulate in the
+	 * [sw_tail, sw_head) gap. Frames kept for in-place repost (RX
+	 * errors, XDP_DROP and header-only packets) still hold a fragment
+	 * there, so walk the whole ring and release whatever is left.
+	 */
+	for (i = 0; i < self->size; i++) {
+		struct aq_ring_buff_s *buff = &self->buff_ring[i];
+
+		if (!buff->rxdata.page)
+			continue;
 
-		aq_free_rxpage(&buff->rxdata, aq_nic_get_dev(self->aq_nic));
+		page_pool_put_full_page(self->pg_pool, buff->rxdata.page,
+					false);
+		buff->rxdata.page = NULL;
 	}
+
+	self->sw_head = self->sw_tail;
 }
 
 void aq_ring_free(struct aq_ring_s *self)
@@ -970,6 +950,11 @@ void aq_ring_free(struct aq_ring_s *self)
 	kfree(self->buff_ring);
 	self->buff_ring = NULL;
 
+	if (self->pg_pool) {
+		page_pool_destroy(self->pg_pool);
+		self->pg_pool = NULL;
+	}
+
 	if (self->dx_ring) {
 		dma_free_coherent(aq_nic_get_dev(self->aq_nic),
 				  self->size * self->dx_size, self->dx_ring,
@@ -1008,9 +993,6 @@ unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data)
 			data[++count] = self->stats.rx.alloc_fails;
 			data[++count] = self->stats.rx.skb_alloc_fails;
 			data[++count] = self->stats.rx.polls;
-			data[++count] = self->stats.rx.pg_flips;
-			data[++count] = self->stats.rx.pg_reuses;
-			data[++count] = self->stats.rx.pg_losts;
 			data[++count] = self->stats.rx.xdp_aborted;
 			data[++count] = self->stats.rx.xdp_drop;
 			data[++count] = self->stats.rx.xdp_pass;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
index 6431cc62962f..58bcadb3e3cc 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
@@ -17,12 +17,12 @@
 #define AQ_XDP_TAILROOM		SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
 
 struct page;
+struct page_pool;
 struct aq_nic_cfg_s;
 
 struct aq_rxpage {
 	struct page *page;
 	dma_addr_t daddr;
-	unsigned int order;
 	unsigned int pg_off;
 };
 
@@ -105,9 +105,6 @@ struct aq_ring_stats_rx_s {
 	u64 alloc_fails;
 	u64 skb_alloc_fails;
 	u64 polls;
-	u64 pg_losts;
-	u64 pg_flips;
-	u64 pg_reuses;
 	u64 xdp_aborted;
 	u64 xdp_drop;
 	u64 xdp_pass;
@@ -151,6 +148,7 @@ struct aq_ring_s {
 	u16 tail_size;
 	union aq_ring_stats_s stats;
 	dma_addr_t dx_ring_pa;
+	struct page_pool *pg_pool;
 	struct bpf_prog *xdp_prog;
 	enum atl_ring_type ring_type;
 	struct xdp_rxq_info xdp_rxq;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
index 05814fea0f5f..023a80f4614e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
@@ -146,25 +146,26 @@ int aq_vec_ring_alloc(struct aq_vec_s *self, struct aq_nic_s *aq_nic,
 		aq_nic_set_tx_ring(aq_nic, idx_ring, ring);
 
 		ring = &self->ring[i][AQ_VEC_RX_ID];
+		err = aq_ring_rx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
+		if (err)
+			goto err_exit;
+
 		if (xdp_rxq_info_reg(&ring->xdp_rxq,
 				     aq_nic->ndev, idx,
 				     self->napi.napi_id) < 0) {
+			aq_ring_free(ring);
 			err = -ENOMEM;
 			goto err_exit;
 		}
 		if (xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
-					       MEM_TYPE_PAGE_SHARED, NULL) < 0) {
+					       MEM_TYPE_PAGE_POOL,
+					       ring->pg_pool) < 0) {
 			xdp_rxq_info_unreg(&ring->xdp_rxq);
+			aq_ring_free(ring);
 			err = -ENOMEM;
 			goto err_exit;
 		}
 
-		err = aq_ring_rx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
-		if (err) {
-			xdp_rxq_info_unreg(&ring->xdp_rxq);
-			goto err_exit;
-		}
-
 		++self->rx_rings;
 	}
 
-- 
2.47.3


^ permalink raw reply related

* [PATCH net-next 1/2] net: atlantic: free stranded TX buffers on ring deinit
From: Yangyu Chen @ 2026-07-09 17:37 UTC (permalink / raw)
  To: Sukhdeep Singh, Andrew Lunn, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni
  Cc: netdev, bpf, linux-kernel, Jesper Dangaard Brouer,
	Richard Cochran, Lino Sanfilippo, Yangyu Chen
In-Reply-To: <tencent_7DB01BE7F8FA056BB5F11D3570CF636C4309@qq.com>

aq_vec_deinit() drains the TX rings with a single aq_ring_tx_clean()
call, which frees at most AQ_CFG_TX_CLEAN_BUDGET (256) descriptors and
stops at hw_head, which no longer moves once aq_vec_stop() has stopped
the hardware and NAPI. Completed descriptors beyond the budget and
everything still posted in [hw_head, sw_tail) keep their skb or
xdp_frame when the interface goes down: aq_vec_ring_free() then frees
the buffer ring and the references are lost for good.

Today this is a silent memory leak on every interface down under
TX/XDP_TX load. With the following conversion of the RX path to
page_pool it becomes much more visible: XDP_TX frames carry fragment
references on the RX ring's page_pool, so a single stranded frame
keeps the pool's inflight count above zero forever. page_pool_destroy()
then never completes, the pool is leaked together with its pages, and
"page_pool_release_retry() stalled pool shutdown" is warned every 60
seconds from that point on, on every ifdown, XDP detach or ring resize
under XDP_TX load.

Bring back aq_ring_tx_deinit() as it was before the removal and use it
for teardown again, with one extension: TX rings can hold xdp_frames
nowadays, so release those too. They are returned with
xdp_return_frame() since this runs in process context.

Fixes: eb36bedf28be ("net: aquantia: remove function aq_ring_tx_deinit")
Assisted-by: Claude:claude-fable-5
Signed-off-by: Yangyu Chen <cyy@cyyself.name>
---

Notes:
    Without this fix, converting the RX path to page_pool (next patch)
    turns the stranded XDP_TX frames into leaked page_pool fragments, so
    page_pool_destroy() can never drain and the shutdown stalls forever.
    
    Reproduced on an AQC100 with this patch dropped from the series (i.e.
    page_pool applied without the tx-deinit fix):
    
      # reflect received frames back out through XDP_TX
      xdp-bench tx enp99s0                    # or any trivial XDP_TX prog
      # from a peer on the same link, flood RX so frames are in flight, then
      ip link set enp99s0 down
    
    The pool is destroyed with frames still stranded on the TX ring, and
    page_pool_release_retry() warns every 60s with the same id and inflight
    count and a growing age, indefinitely:
    
      [161110.753385] page_pool_release_retry() stalled pool shutdown: id 361, 12 inflight 60 sec
      [161171.170756] page_pool_release_retry() stalled pool shutdown: id 361, 12 inflight 120 sec
      [161231.588685] page_pool_release_retry() stalled pool shutdown: id 361, 12 inflight 181 sec
      [161292.005886] page_pool_release_retry() stalled pool shutdown: id 361, 12 inflight 241 sec
    
    With this patch the stranded buffers are freed at deinit, inflight
    drops to zero and the pool drains cleanly.

 .../net/ethernet/aquantia/atlantic/aq_ring.c  | 30 +++++++++++++++++++
 .../net/ethernet/aquantia/atlantic/aq_ring.h  |  1 +
 .../net/ethernet/aquantia/atlantic/aq_vec.c   |  2 +-
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index 8ff07de2bd52..c59b6c0b37f1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -360,6 +360,36 @@ bool aq_ring_tx_clean(struct aq_ring_s *self)
 	return !!budget;
 }
 
+void aq_ring_tx_deinit(struct aq_ring_s *self)
+{
+	if (!self)
+		goto err_exit;
+
+	for (; self->sw_head != self->sw_tail;
+		self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
+		struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
+		struct device *ndev = aq_nic_get_dev(self->aq_nic);
+
+		if (likely(buff->is_mapped)) {
+			if (unlikely(buff->is_sop)) {
+				dma_unmap_single(ndev, buff->pa, buff->len,
+						 DMA_TO_DEVICE);
+			} else {
+				dma_unmap_page(ndev, buff->pa, buff->len,
+					       DMA_TO_DEVICE);
+			}
+		}
+
+		if (unlikely(buff->is_eop)) {
+			if (buff->skb)
+				dev_kfree_skb_any(buff->skb);
+			else if (buff->xdpf)
+				xdp_return_frame(buff->xdpf);
+		}
+	}
+err_exit:;
+}
+
 static void aq_rx_checksum(struct aq_ring_s *self,
 			   struct aq_ring_buff_s *buff,
 			   struct sk_buff *skb)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
index a70b880ada67..6431cc62962f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
@@ -202,6 +202,7 @@ void aq_ring_update_queue_state(struct aq_ring_s *ring);
 void aq_ring_queue_wake(struct aq_ring_s *ring);
 void aq_ring_queue_stop(struct aq_ring_s *ring);
 bool aq_ring_tx_clean(struct aq_ring_s *self);
+void aq_ring_tx_deinit(struct aq_ring_s *self);
 int aq_xdp_xmit(struct net_device *dev, int num_frames,
 		struct xdp_frame **frames, u32 flags);
 int aq_ring_rx_clean(struct aq_ring_s *self,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
index 2f9033ceed8c..05814fea0f5f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
@@ -275,7 +275,7 @@ void aq_vec_deinit(struct aq_vec_s *self)
 
 	for (i = 0U; self->tx_rings > i; ++i) {
 		ring = self->ring[i];
-		aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
+		aq_ring_tx_deinit(&ring[AQ_VEC_TX_ID]);
 		aq_ring_rx_deinit(&ring[AQ_VEC_RX_ID]);
 	}
 
-- 
2.47.3


^ permalink raw reply related

* [PATCH net-next 0/2] net: atlantic: convert RX path to page_pool
From: Yangyu Chen @ 2026-07-09 17:36 UTC (permalink / raw)
  To: Sukhdeep Singh, Andrew Lunn, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni
  Cc: netdev, bpf, linux-kernel, Jesper Dangaard Brouer,
	Richard Cochran, Lino Sanfilippo, Yangyu Chen

On systems where the NIC sits behind an IOMMU, the atlantic RX path
cannot reach line rate: every RX buffer is allocated with
dev_alloc_pages() and mapped with dma_map_page(), then unmapped and
freed once the stack has consumed the packet. Every map/unmap is an
IOTLB/pagetable operation, and at 10G rates this dominates the RX
path. On an AMD Strix Halo system with a Thunderbolt-attached QNAP
QNA-T310G1S (MTU 1500, TCP over IPv6, iperf3 -R), RX tops out at
about 2.2 Gbit/s.

An earlier patch [1] worked around this by making the RX page order
tunable via a module parameter, amortizing one map/unmap over eight
pages worth of frames. The review feedback was to convert the driver
to the page_pool API instead of adding a knob. This series does that
conversion.

Patch 1 fixes a long-standing teardown leak first: TX buffers beyond
the budgeted single aq_ring_tx_clean() pass, or still posted past the
frozen hw_head, are stranded when the interface goes down. Today that
is a silent leak; after the conversion a stranded XDP_TX frame would
hold a page_pool fragment reference and turn every such ifdown into a
permanently stalled pool shutdown, so it needs fixing before the
conversion lands.

Patch 2 converts the RX path to page_pool with the fragment API.
Pages are DMA-mapped once when they enter the per-ring pool
(PP_FLAG_DMA_MAP) and stay mapped while they recycle between the
driver and the stack, so steady-state RX performs no IOMMU work.
page_pool_dev_alloc_frag() takes over the sub-page splitting the
driver's hand-rolled "page flip" scheme did based on page_ref_count(),
buffer ownership becomes transfer-based, and the XDP memory model
switches to MEM_TYPE_PAGE_POOL.

Performance, QNA-T310G1S (AQC100) behind Thunderbolt/IOMMU, MTU 1500,
TCP over IPv6, iperf3 -R:

  before:  2.24 Gbit/s
  after:   9.14 Gbit/s

matching what previously required the rxpageorder=3 workaround, but
with order-0 pages and no tunable.

Tested on the same setup: line rate with plain RX and with XDP_PASS;
XDP_TX with a MAC-swap reflector under sustained traffic; repeated
ifdown/ifup and module unload cycles under both plain RX and XDP_TX
load complete without "stalled pool shutdown" warnings or other splats.

[1] https://lore.kernel.org/lkml/tencent_E71C2F71D9631843941A5DF87204D1B5B509@qq.com/

Yangyu Chen (2):
  net: atlantic: free stranded TX buffers on ring deinit
  net: atlantic: convert RX path to page_pool

 drivers/net/ethernet/aquantia/Kconfig         |   1 +
 .../ethernet/aquantia/atlantic/aq_ethtool.c   |   3 -
 .../net/ethernet/aquantia/atlantic/aq_ptp.c   |  20 +-
 .../net/ethernet/aquantia/atlantic/aq_ring.c  | 268 +++++++++---------
 .../net/ethernet/aquantia/atlantic/aq_ring.h  |   7 +-
 .../net/ethernet/aquantia/atlantic/aq_vec.c   |  17 +-
 6 files changed, 172 insertions(+), 144 deletions(-)

-- 
2.47.3


^ permalink raw reply

* Re: [PATCH] net: alacritech: add missing MODULE_DEVICE_TABLE()
From: Simon Horman @ 2026-07-09 17:21 UTC (permalink / raw)
  To: Pengpeng Hou
  Cc: Lino Sanfilippo, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, netdev, linux-kernel
In-Reply-To: <20260704152053.49780-1-pengpeng@iscas.ac.cn>

On Sat, Jul 04, 2026 at 11:20:53PM +0800, Pengpeng Hou wrote:
> The driver has a match table for the pci bus wired into its driver
> structure, but the table is not exported with MODULE_DEVICE_TABLE().
> 
> Add the missing MODULE_DEVICE_TABLE() entry so module alias information
> is generated for automatic module loading.
> 
> This is a source-level fix.  It does not claim dynamic hardware
> reproduction; the evidence is the driver-owned match table, its use by
> the driver registration structure, and the missing module alias
> publication.
> 
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* Re: [PATCH net-next] net: ipv4: clear dev->ip_ptr before destroying inetdev
From: Ido Schimmel @ 2026-07-09 17:17 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: David S. Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel, netdev,
	Kuniyuki Iwashima
In-Reply-To: <20260707043039.101983-1-yuyanghuang@google.com>

On Tue, Jul 07, 2026 at 01:30:39PM +0900, Yuyang Huang wrote:
> To prevent RCU readers from accessing a partially destroyed in_device,
> clear dev->ip_ptr early in inetdev_destroy() before freeing the
> multicast list and individual IP addresses. This aligns the IPv4 teardown
> sequence with the IPv6 implementation.
> 
> Cc: Ido Schimmel <idosch@nvidia.com>
> Cc: Kuniyuki Iwashima <kuniyu@google.com>
> Signed-off-by: Yuyang Huang <yuyanghuang@google.com>

I believe that sashiko-gemini [1] is right and you need to teach
prestera to ignore NETDEV_DOWN notifications in the inetaddr chain when
a RIF doesn't exist. Something like [2].

Regarding ieee80211_ifa_changed(), the net device is being tore down, so
failing to update the firmware ARP filter probably doesn't matter, but
you can do something like [3] to avoid it completely.

So, three patches where the last one aligns IPv4 with IPv6. Please check
if other listeners need to be adjusted (mlxsw is OK).

Thanks

[1] https://sashiko.dev/#/patchset/20260707043039.101983-1-yuyanghuang%40google.com

[2]
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router.c b/drivers/net/ethernet/marvell/prestera/prestera_router.c
index b036b173a308..0c4f462baa6e 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_router.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_router.c
@@ -1302,10 +1302,8 @@ static int __prestera_inetaddr_port_event(struct net_device *port_dev,
 		dev_hold(port_dev);
 		break;
 	case NETDEV_DOWN:
-		if (!re) {
-			NL_SET_ERR_MSG_MOD(extack, "Can't find RIF");
-			return -EEXIST;
-		}
+		if (!re)
+			return 0;
 		prestera_rif_entry_destroy(port->sw, re);
 		dev_put(port_dev);
 		break;

[3]
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 90d295cc364f..0e7a60dd1d8d 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -588,9 +588,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
 		return NOTIFY_DONE;
 
-	idev = __in_dev_get_rtnl(sdata->dev);
-	if (!idev)
-		return NOTIFY_DONE;
+	idev = ifa->ifa_dev;
 
 	ifmgd = &sdata->u.mgd;

^ permalink raw reply related

* Re: [PATCH] net: davicom: dm9051: add missing MODULE_DEVICE_TABLE()
From: Simon Horman @ 2026-07-09 17:15 UTC (permalink / raw)
  To: Pengpeng Hou
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, netdev, linux-kernel
In-Reply-To: <20260704152142.50156-1-pengpeng@iscas.ac.cn>

On Sat, Jul 04, 2026 at 11:21:42PM +0800, Pengpeng Hou wrote:
> The driver has a match table for the spi bus wired into its driver
> structure, but the table is not exported with MODULE_DEVICE_TABLE().
> 
> Add the missing MODULE_DEVICE_TABLE() entry so module alias information
> is generated for automatic module loading.
> 
> This is a source-level fix.  It does not claim dynamic hardware
> reproduction; the evidence is the driver-owned match table, its use by
> the driver registration structure, and the missing module alias
> publication.
> 
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* Re: [PATCH net] net: airoha: fix ETS channel derivation in airoha_tc_setup_qdisc_ets()
From: Simon Horman @ 2026-07-09 17:13 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260704-airoha-ets-handle-fix-v1-1-42516b3549a1@kernel.org>

On Sat, Jul 04, 2026 at 04:21:38PM +0200, Lorenzo Bianconi wrote:
> Derive the hardware QoS channel from opt->parent instead of opt->handle
> in airoha_tc_setup_qdisc_ets(). The ETS qdisc handle is either
> user-specified or auto-allocated by qdisc_alloc_handle() and bears no
> relation to the HTB leaf classid that identifies the hardware channel.
> HTB derives the channel from TC_H_MIN(opt->classid), and ETS is always
> attached as a child of an HTB leaf, so its opt->parent matches that
> classid. Using opt->handle instead can cause two ETS qdiscs on different
> HTB leaves to collide on the same hardware channel, corrupting scheduler
> configuration and stats.
> 
> Fixes: 20bf7d07c956 ("net: airoha: Add sched ETS offload support")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* Re: [PATCH] net: xscale: add missing MODULE_DEVICE_TABLE()
From: Simon Horman @ 2026-07-09 17:09 UTC (permalink / raw)
  To: Pengpeng Hou
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Richard Cochran, netdev, linux-kernel
In-Reply-To: <20260704122722.5715-1-pengpeng@iscas.ac.cn>

On Sat, Jul 04, 2026 at 08:27:22PM +0800, Pengpeng Hou wrote:
> The driver has an OF match table wired to .of_match_table, but does
> not export the table with MODULE_DEVICE_TABLE().
> 
> Add the missing MODULE_DEVICE_TABLE(of, ...) entry so module alias
> information is generated for OF based module autoloading.
> 
> This is a source-level fix.  It does not claim dynamic hardware
> reproduction; the evidence is the driver-owned match table, its use by
> the platform driver, and the missing module alias publication.
> 
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* Re: [PATCH nf] netfilter: flowtable: tear down HW offloaded flows on FIB route changes
From: Pablo Neira Ayuso @ 2026-07-09 17:08 UTC (permalink / raw)
  To: Ahmed Zaki
  Cc: netfilter-devel, fw, kuba, edumazet, davem, pabeni, horms, netdev
In-Reply-To: <20260708205404.911832-1-anzaki@gmail.com>

On Wed, Jul 08, 2026 at 02:54:04PM -0600, Ahmed Zaki wrote:
> Hardware-offloaded flows bypass the CPU and, unlike the software
> datapath, dst_check() does not invalidate them when a route changes.
> For ephemeral flows, this is usually not a problem as the flow expire on
> its own and the driver clears the entry in the HW. However, for persistent
> flows forwarded through the device, the HW is never informed that the
> route has expired.
> 
> For tables marked with NF_FLOWTABLE_HW_OFFLOAD, listen to the per-net FIB
> notifier chain and tear down the affected flows so they are re-evaluated by
> the SW forwarding path.
> 
> A lockless list is used to reduce the work items overhead in case of a
> route change storm allowing many FIB events to be processed by one work
> item.

This walks the hashtable anyway in case of fib event, maybe simply
walk over the hashtable and call dst_check() to check if the cached
dst is still current.

> Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support")

No, this is an enhancement, not a fix. This must be targeted to nf-next.

Thanks.

^ permalink raw reply

* Re: [PATCH v4] r8169: migrate Rx path to page_pool, prepare for XDP
From: Simon Horman @ 2026-07-09 17:01 UTC (permalink / raw)
  To: atharvapotdar07
  Cc: Simon Horman, hkallweit1, nic_swsd, andrew+netdev, davem,
	edumazet, kuba, pabeni, romieu, netdev
In-Reply-To: <20260704080653.33740-1-atharvapotdar07@gmail.com>

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://netdev-ai.bots.linux.dev/sashiko/
---
r8169: migrate Rx path to page_pool, prepare for XDP

This commit migrates the Rx path to page_pool on MACs newer than
RTL_GIGA_MAC_VER_06, reserves XDP_PACKET_HEADROOM in each buffer, and
decouples the Rx consumption loop (cur_rx) from a new refill loop
(dirty_rx) that reallocates only after napi_build_skb() takes
ownership of a page.

> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
> index ec4fc21fa21f..5b13880c7ed8 100644
> --- a/drivers/net/ethernet/realtek/r8169_main.c
> +++ b/drivers/net/ethernet/realtek/r8169_main.c

[ ... ]

> @@ -4161,21 +4169,14 @@ static void rtl8169_mark_to_asic(struct RxDesc *desc)
>  static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
>  					  struct RxDesc *desc)
>  {
> -	struct device *d = tp_to_dev(tp);
> -	int node = dev_to_node(d);
>  	dma_addr_t mapping;
>  	struct page *data;
>  
> -	data = alloc_pages_node(node, GFP_KERNEL, get_order(R8169_RX_BUF_SIZE));
> +	data = page_pool_dev_alloc_pages(tp->rx_pool);
>  	if (!data)
>  		return NULL;
>  
> -	mapping = dma_map_page(d, data, 0, R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
> -	if (unlikely(dma_mapping_error(d, mapping))) {
> -		netdev_err(tp->dev, "Failed to map RX DMA!\n");
> -		__free_pages(data, get_order(R8169_RX_BUF_SIZE));
> -		return NULL;
> -	}
> +	mapping = page_pool_get_dma_addr(data) + tp->rx_headroom;
>  
>  	desc->addr = cpu_to_le64(mapping);
>  	rtl8169_mark_to_asic(desc);

[Critical]
Can the NIC DMA past the end of the allocated page here?  The
descriptor's addr is offset by tp->rx_headroom (XDP_PACKET_HEADROOM,
256) inside a page whose backing allocation is order-2 (16384 bytes,
since R8169_RX_BUF_SIZE is SZ_16K - 1 = 16383):

	mapping = page_pool_get_dma_addr(data) + tp->rx_headroom;

but rtl8169_mark_to_asic() still programs the full R8169_RX_BUF_SIZE
into the descriptor's writable-size field:

	WRITE_ONCE(desc->opts1,
		   cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));

So the NIC's writable window becomes [page + 256, page + 16639], which
overshoots the 16384-byte allocation by up to 255 bytes.  page_pool's
own accounting has already been narrowed via params.max_len =
R8169_RX_BUF_SIZE - tp->rx_headroom, but that value never propagates
to opts1.

On RTL8125/8126, rtl_jumbo_max() returns JUMBO_16K and rtl_set_rx_max_size()
programs RxMaxSize = R8169_RX_BUF_SIZE + 1, so on-wire frames close to
16 KiB are accepted, exactly the range that drives the overrun.

The same mismatch appears on the zero-copy skb path.  napi_build_skb()
is called with frag_size = R8169_RX_BUF_SIZE:

	skb = napi_build_skb(rx_buf, R8169_RX_BUF_SIZE);
	if (likely(skb)) {
		skb_reserve(skb, tp->rx_headroom);
		skb_put(skb, pkt_size);

After skb_reserve(256), tailroom is around 16383 - 256 - overhead,
while pkt_size comes straight from the descriptor's 14-bit length
field (up to 16383, or 16379 after the ETH_FCS_LEN strip).  A large
enough pkt_size would trip skb_over_panic() inside skb_put() → BUG().

Should the descriptor size and napi_build_skb() frag_size use
R8169_RX_BUF_SIZE - tp->rx_headroom (or params.max_len) instead of
R8169_RX_BUF_SIZE?

Also, the commit message states:

    The pool is locked to order-2 (SZ_16K) allocations on all MACs,
    matching the existing R8169_RX_BUF_SIZE, so this migration
    introduces no change in per-descriptor allocation size or
    jumbo-frame behavior relative to the current tree.

Given that rx_headroom is now consuming part of that 16 KiB on newer
MACs while the descriptor size field is unchanged, is the
"no change in ... jumbo-frame behavior" claim still accurate?

> @@ -4188,14 +4189,18 @@ static void rtl8169_rx_clear(struct rtl8169_private *tp)
>  	int i;
>  
>  	for (i = 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) {
> -		dma_unmap_page(tp_to_dev(tp),
> -			       le64_to_cpu(tp->RxDescArray[i].addr),
> -			       R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
> -		__free_pages(tp->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
> +		page_pool_put_full_page(tp->rx_pool, tp->Rx_databuff[i], false);
>  		tp->Rx_databuff[i] = NULL;
>  		tp->RxDescArray[i].addr = 0;
>  		tp->RxDescArray[i].opts1 = 0;
>  	}
> +
> +	if (tp->rx_pool) {
> +		if (xdp_rxq_info_is_reg(&tp->xdp_rxq))
> +			xdp_rxq_info_unreg(&tp->xdp_rxq);
> +		page_pool_destroy(tp->rx_pool);
> +		tp->rx_pool = NULL;
> +	}
>  }

[High]
Can this loop leak Rx_databuff pages and orphan the page_pool?  The
loop condition terminates at the first NULL entry:

	for (i = 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) {

Prior to this patch, Rx_databuff[] was uniformly non-NULL between
fill and close, so early termination was safe.  With this patch, two
paths create NULL entries interspersed with live pages:

  - rl_rx() sets tp->Rx_databuff[entry] = NULL when napi_build_skb()
    succeeds and takes ownership of the page.
  - rtl8169_rx_refill() breaks on the first
    page_pool_dev_alloc_pages() failure, leaving that slot NULL while
    later slots still hold live pages.

If a close happens with any NULL entry in front of a still-populated
one, the loop exits early, page_pool_put_full_page() is never called
on the remaining pages, and page_pool_destroy() then sees non-zero
in-flight pages and schedules the deferred release worker.  With
tp->rx_pool set to NULL and the next rtl8169_init_ring() clearing
Rx_databuff via memset(), the surviving pointers are permanently
lost.

Should this iterate over all NUM_RX_DESC entries and null-check
inside the body instead of using the pointer as a loop condition?

[High]
A related concern that isn't in this diff, but is created by the new
Rx_databuff NULL semantics: rtl_reset_work() calls rtl8169_cleanup()
(which zeroes cur_rx and dirty_rx via rtl8169_init_ring_indexes())
and then unconditionally re-arms every descriptor:

drivers/net/ethernet/realtek/r8169_main.c:rtl_reset_work() {
	...
	rtl8169_cleanup(tp);

	for (i = 0; i < NUM_RX_DESC; i++)
		rtl8169_mark_to_asic(tp->RxDescArray + i);

	napi_enable(&tp->napi);
	rtl_hw_start(tp);
}

After this patch, Rx_databuff[k] can be NULL for slots whose pages
were consumed by napi_build_skb(), and the descriptor's addr for
those slots still points at a page that has been returned to the
page_pool (and may be recycled to another buffer).  Once
rtl_hw_start() re-enables the NIC, it can DMA incoming frames into
those stale addresses.

On top of that, because dirty_rx == cur_rx == 0 after the reset,
rtl8169_rx_refill() has nothing to advance over, and rl_rx's
guard fires without progressing state:

	if (unlikely(!tp->Rx_databuff[entry]))
		break;

so the NULL slots never get repopulated.

Should rtl_reset_work() refill the NULL slots (or do a full
rx_clear/rx_fill) before marking descriptors to ASIC?

^ permalink raw reply

* [PATCH net v2] can: esd_usb: kill anchored URBs before freeing netdevs
From: Fan Wu @ 2026-07-09 16:41 UTC (permalink / raw)
  To: linux-can
  Cc: frank.jungclaus, socketcan, mkl, mailhol, jedrzej.jagielski,
	netdev, linux-kernel, Fan Wu, stable
In-Reply-To: <20260709104620.133765-1-fanwu01@zju.edu.cn>

esd_usb_disconnect() frees each CAN netdev with free_candev() inside
its per-netdev loop and only calls unlink_all_urbs(dev) afterwards.
The per-netdev private data (struct esd_usb_net_priv) is embedded in
the net_device allocation returned by alloc_candev(), so once
free_candev() has run, dev->nets[i] points to freed memory.
unlink_all_urbs() then dereferences the freed dev->nets[i] to kill the
per-netdev TX anchor (usb_kill_anchored_urbs(&priv->tx_submitted)),
clear active_tx_jobs, and reset priv->tx_contexts[].

Reorder the teardown so the anchored URBs are killed before the netdevs
are freed, matching other CAN/USB drivers in the same directory such as
ems_usb, usb_8dev and mcba_usb, which unregister, then unlink, then
free: unregister the netdevs first (which stops their TX queues), call
unlink_all_urbs(dev) once, then free the netdevs.

This issue was found by an in-house static analysis tool.

Fixes: 96d8e90382dc ("can: Add driver for esd CAN-USB/2 device")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.5
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
---
Changes in v2: shorten the Fixes: tag to the abbreviated 12-char SHA
per Jedrzej Jagielski ("no need to put whole SHA, 12 first chars is
enough").

v1: https://lore.kernel.org/netdev/20260709104620.133765-1-fanwu01@zju.edu.cn/
 drivers/net/can/usb/esd_usb.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c
index d257440fa..f41d4a0d1 100644
--- a/drivers/net/can/usb/esd_usb.c
+++ b/drivers/net/can/usb/esd_usb.c
@@ -1390,10 +1390,13 @@ static void esd_usb_disconnect(struct usb_interface *intf)
 				netdev = dev->nets[i]->netdev;
 				netdev_info(netdev, "unregister\n");
 				unregister_netdev(netdev);
-				free_candev(netdev);
 			}
 		}
 		unlink_all_urbs(dev);
+		for (i = 0; i < dev->net_count; i++) {
+			if (dev->nets[i])
+				free_candev(dev->nets[i]->netdev);
+		}
 		kfree(dev);
 	}
 }
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH net-next v2 0/8] netconsole: stop charging netpoll users for netconsole-only data
From: Breno Leitao @ 2026-07-09 16:38 UTC (permalink / raw)
  To: Paolo Abeni
  Cc: Simon Horman, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Andrew Lunn, netdev, asantostc, gustavold, linux-kernel,
	kernel-team
In-Reply-To: <64257110-d9fe-42df-9990-2ec1421a7c29@redhat.com>

On Thu, Jul 09, 2026 at 12:27:35PM +0200, Paolo Abeni wrote:
> On 7/9/26 12:19 PM, Simon Horman wrote:
> > On Mon, Jul 06, 2026 at 04:55:35AM -0700, Breno Leitao wrote:
> >> On Thu, Jul 02, 2026 at 05:19:44AM -0700, Breno Leitao wrote:
> >>> This work continue to untangle netconsole and netpoll, improving
> >>> memory usage for netpoll users that are not netconsole.
> >>
> >> Quick follow up on the sashiko findings. most of them are assuming that
> >> netconsole_write is called locklelly, which is not the case, except
> >> on panic (CON_NBCON_ATOMIC_UNSAFE). 
> >>
> >>
> >> There are in order as they appear in
> >> https://sashiko.dev/#/patchset/20260702-netconsole_move_more-v2-0-1ebedd921dcb%40debian.org
> >>
> >> Tl;DR: There are two pre-existing issue that I will get fixed, but
> >> I don't think they are blockers for this series (IMO).
> > 
> > Thanks, I agree.
> > 
> > For the series:
> > 
> > Reviewed-by: Simon Horman <horms@kernel.org>
> > 
> > I did notice that patch 2/8 now applies with some fuzz, which trips up git am.
> > You may want to consider a rebase.
> 
> Yep, a rebase is needed, thanks!

Ack, I will do!

Thanks


^ permalink raw reply

* Re: [PATCH net-next] devlink: Replace strlcat() with seq_buf
From: Simon Horman @ 2026-07-09 16:34 UTC (permalink / raw)
  To: Ian Bridges
  Cc: Jiri Pirko, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, netdev, linux-kernel, linux-hardening
In-Reply-To: <akiCtALVjd9TF8Xl@dev>

On Fri, Jul 03, 2026 at 10:49:08PM -0500, Ian Bridges wrote:
> In preparation for removing the strlcat() API[1], replace its uses in
> __devlink_compat_running_version().
> 
> The function accumulates a variable number of version strings into a
> fixed buffer, which is what seq_buf is for. The seq_buf is anchored at
> the end of any existing string in the buffer and each version string
> is appended with a single seq_buf_printf(). The output is unchanged,
> including under truncation.
> 
> Link: https://github.com/KSPP/linux/issues/370 [1]
> Signed-off-by: Ian Bridges <icb@fastmail.org>
> ---
> The patch was tested as follows, on top of net-next:
>  - x86_64 allmodconfig and allyesconfig builds of net/devlink/dev.o at
>    W=1 produce no warnings.
>  - A userspace comparison of the old and new construction ran with
>    randomized version lists and buffer contents across all buffer
>    fill levels. The outputs are byte-identical in every case,
>    including on overflow.
>  - The changed path was exercised in a QEMU guest through the ethtool
>    GDRVINFO ioctl against a netdevsim device, before and after the
>    change, with identical fw_version output.

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* [syzbot] [wireless?] KASAN: slab-out-of-bounds Read in ieee80211_ie_split_ric (3)
From: syzbot @ 2026-07-09 16:33 UTC (permalink / raw)
  To: johannes, linux-kernel, linux-wireless, netdev, syzkaller-bugs

Hello,

syzbot found the following issue on:

HEAD commit:    a52d6c7160f7 selftests/arm64: fix spelling errors in comme..
git tree:       git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci
console output: https://syzkaller.appspot.com/x/log.txt?x=17ddd739580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=ecdef466b08b9772
dashboard link: https://syzkaller.appspot.com/bug?extid=cc867e537e4bd36f69bb
compiler:       Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
userspace arch: arm64
syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=13940432580000
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=156e7d89580000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/af2ea186884f/disk-a52d6c71.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/cef93b18732f/vmlinux-a52d6c71.xz
kernel image: https://storage.googleapis.com/syzbot-assets/b9f9b8922f14/Image-a52d6c71.gz.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+cc867e537e4bd36f69bb@syzkaller.appspotmail.com

==================================================================
BUG: KASAN: slab-out-of-bounds in skip_ie net/wireless/util.c:2068 [inline]
BUG: KASAN: slab-out-of-bounds in ieee80211_ie_split_ric+0x4a8/0x508 net/wireless/util.c:-1
Read of size 1 at addr ffff0000c2aac9c1 by task syz.0.18/4930

CPU: 0 UID: 0 PID: 4930 Comm: syz.0.18 Not tainted syzkaller #0 PREEMPT 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/02/2026
Call trace:
 show_stack+0x2c/0x3c arch/arm64/kernel/stacktrace.c:499 (C)
 __dump_stack+0x30/0x40 lib/dump_stack.c:94
 dump_stack_lvl+0xd8/0x12c lib/dump_stack.c:120
 print_address_description+0xb0/0x238 mm/kasan/report.c:378
 print_report+0x68/0x84 mm/kasan/report.c:482
 kasan_report+0x8c/0xc4 mm/kasan/report.c:595
 __asan_report_load1_noabort+0x20/0x2c mm/kasan/report_generic.c:378
 skip_ie net/wireless/util.c:2068 [inline]
 ieee80211_ie_split_ric+0x4a8/0x508 net/wireless/util.c:-1
 ieee80211_ie_split include/net/cfg80211.h:10226 [inline]
 cfg80211_sme_get_conn_ies net/wireless/sme.c:529 [inline]
 cfg80211_sme_connect net/wireless/sme.c:586 [inline]
 cfg80211_connect+0xca8/0x1be4 net/wireless/sme.c:1528
 cfg80211_mgd_wext_connect+0x3ac/0x508 net/wireless/wext-sme.c:57
 cfg80211_mgd_wext_siwessid+0x2c4/0x40c net/wireless/wext-sme.c:184
 cfg80211_wext_siwessid+0xc4/0x13c net/wireless/wext-compat.c:1415
 ioctl_standard_iw_point+0x678/0xb04 net/wireless/wext-core.c:864
 ioctl_standard_call+0xb4/0x178 net/wireless/wext-core.c:1049
 wireless_process_ioctl net/wireless/wext-core.c:-1 [inline]
 wext_ioctl_dispatch+0x104/0x36c net/wireless/wext-core.c:1013
 wext_handle_ioctl+0x154/0x288 net/wireless/wext-core.c:1074
 sock_ioctl+0x154/0x7ec net/socket.c:1353
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl fs/ioctl.c:583 [inline]
 __arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
 invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
 el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
 do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
 el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
 el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
 el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594

Allocated by task 4930:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x40/0x78 mm/kasan/common.c:78
 kasan_save_alloc_info+0x44/0x54 mm/kasan/generic.c:570
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x9c/0xb4 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5362 [inline]
 __kmalloc_node_track_caller_noprof+0x434/0x6d4 mm/slub.c:5497
 kmemdup_noprof+0x44/0x8c mm/util.c:138
 kmemdup_noprof include/linux/fortify-string.h:715 [inline]
 cfg80211_wext_siwgenie+0x170/0x28c net/wireless/wext-sme.c:322
 ioctl_standard_iw_point+0x678/0xb04 net/wireless/wext-core.c:864
 ioctl_standard_call+0xb4/0x178 net/wireless/wext-core.c:1049
 wireless_process_ioctl net/wireless/wext-core.c:-1 [inline]
 wext_ioctl_dispatch+0x104/0x36c net/wireless/wext-core.c:1013
 wext_handle_ioctl+0x154/0x288 net/wireless/wext-core.c:1074
 sock_ioctl+0x154/0x7ec net/socket.c:1353
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl fs/ioctl.c:583 [inline]
 __arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
 invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
 el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
 do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
 el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
 el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
 el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594

The buggy address belongs to the object at ffff0000c2aac9c0
 which belongs to the cache kmalloc-8 of size 8
The buggy address is located 0 bytes to the right of
 allocated 1-byte region [ffff0000c2aac9c0, ffff0000c2aac9c1)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff0000c2aaca20 pfn:0x102aac
flags: 0x5ffc00000000200(workingset|node=0|zone=2|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 05ffc00000000200 ffff0000c0001500 ffff0000c0000348 fffffdffc30937d0
raw: ffff0000c2aaca20 0000000800800064 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff0000c2aac880: fa fc fc fc fa fc fc fc fa fc fc fc fa fc fc fc
 ffff0000c2aac900: fa fc fc fc fa fc fc fc fa fc fc fc fa fc fc fc
>ffff0000c2aac980: fa fc fc fc fa fc fc fc 01 fc fc fc fa fc fc fc
                                           ^
 ffff0000c2aaca00: fa fc fc fc fa fc fc fc fa fc fc fc fa fc fc fc
 ffff0000c2aaca80: fa fc fc fc fa fc fc fc fa fc fc fc fa fc fc fc
==================================================================
------------[ cut here ]------------
memcpy: detected buffer overflow: 18446744073709551615 byte write of buffer size 0
WARNING: lib/string_helpers.c:1037 at __fortify_report+0xa0/0xb8 lib/string_helpers.c:1036, CPU#0: syz.0.18/4930
Modules linked in:
CPU: 0 UID: 0 PID: 4930 Comm: syz.0.18 Tainted: G    B               syzkaller #0 PREEMPT 
Tainted: [B]=BAD_PAGE
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/02/2026
pstate: 63400005 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : __fortify_report+0xa0/0xb8 lib/string_helpers.c:1036
lr : __fortify_report+0xa0/0xb8 lib/string_helpers.c:1036
sp : ffff8000986876a0
x29: ffff8000986876a0 x28: 1fffe000199c09e6 x27: 1fffe000199c09da
x26: ffff0000c2aac9c0 x25: 0000000000000001 x24: ffff0000d02ad200
x23: ffff0000cce04ed0 x22: ffff800086cbcad8 x21: 0000000000000001
x20: ffffffffffffffff x19: 0000000000000000 x18: 0000000000000000
x17: 3d3d3d3d3d3d3d3d x16: 3d3d3d3d3d3d3d3d x15: 3d3d3d3d3d3d3d3d
x14: 0000000000000000 x13: 0000000000000001 x12: 0000000000000000
x11: 0000000000000000 x10: 0000000000000002 x9 : e75ac9114b2ee700
x8 : e75ac9114b2ee700 x7 : 0000000000000000 x6 : ffff80008048ce60
x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffff8000802f7010
x2 : 0000000100000000 x1 : ffff0000d1543a80 x0 : 0000000000000000
Call trace:
 __fortify_report+0xa0/0xb8 lib/string_helpers.c:1036 (P)
 __fortify_panic+0x10/0x14 lib/string_helpers.c:1043
 fortify_memcpy_chk include/linux/fortify-string.h:547 [inline]
 cfg80211_sme_get_conn_ies net/wireless/sme.c:533 [inline]
 cfg80211_sme_connect net/wireless/sme.c:586 [inline]
 cfg80211_connect+0x1918/0x1be4 net/wireless/sme.c:1528
 cfg80211_mgd_wext_connect+0x3ac/0x508 net/wireless/wext-sme.c:57
 cfg80211_mgd_wext_siwessid+0x2c4/0x40c net/wireless/wext-sme.c:184
 cfg80211_wext_siwessid+0xc4/0x13c net/wireless/wext-compat.c:1415
 ioctl_standard_iw_point+0x678/0xb04 net/wireless/wext-core.c:864
 ioctl_standard_call+0xb4/0x178 net/wireless/wext-core.c:1049
 wireless_process_ioctl net/wireless/wext-core.c:-1 [inline]
 wext_ioctl_dispatch+0x104/0x36c net/wireless/wext-core.c:1013
 wext_handle_ioctl+0x154/0x288 net/wireless/wext-core.c:1074
 sock_ioctl+0x154/0x7ec net/socket.c:1353
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl fs/ioctl.c:583 [inline]
 __arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
 invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
 el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
 do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
 el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
 el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
 el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594
irq event stamp: 1077
hardirqs last  enabled at (1077): [<ffff8000868c3474>] irqentry_exit_to_kernel_mode_after_preempt include/linux/irq-entry-common.h:507 [inline]
hardirqs last  enabled at (1077): [<ffff8000868c3474>] arm64_exit_to_kernel_mode+0x80/0x94 arch/arm64/kernel/entry-common.c:62
hardirqs last disabled at (1076): [<ffff8000868bf484>] __el1_irq arch/arm64/kernel/entry-common.c:506 [inline]
hardirqs last disabled at (1076): [<ffff8000868bf484>] el1_interrupt+0x28/0x60 arch/arm64/kernel/entry-common.c:522
softirqs last  enabled at (978): [<ffff800084c68eac>] local_bh_enable include/linux/bottom_half.h:33 [inline]
softirqs last  enabled at (978): [<ffff800084c68eac>] rcu_read_unlock_bh include/linux/rcupdate.h:914 [inline]
softirqs last  enabled at (978): [<ffff800084c68eac>] __dev_queue_xmit+0x14d0/0x2ba4 net/core/dev.c:4907
softirqs last disabled at (972): [<ffff800084c67bd8>] local_bh_disable include/linux/bottom_half.h:20 [inline]
softirqs last disabled at (972): [<ffff800084c67bd8>] rcu_read_lock_bh include/linux/rcupdate.h:893 [inline]
softirqs last disabled at (972): [<ffff800084c67bd8>] __dev_queue_xmit+0x1fc/0x2ba4 net/core/dev.c:4793
---[ end trace 0000000000000000 ]---
------------[ cut here ]------------
kernel BUG at lib/string_helpers.c:1044!
Internal error: Oops - BUG: 00000000f2000800 [#1]  SMP
Modules linked in:
CPU: 1 UID: 0 PID: 4930 Comm: syz.0.18 Tainted: G    B   W           syzkaller #0 PREEMPT 
Tainted: [B]=BAD_PAGE, [W]=WARN
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/02/2026
pstate: 63400005 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : __fortify_panic+0x10/0x14 lib/string_helpers.c:1043
lr : __fortify_panic+0x10/0x14 lib/string_helpers.c:1043
sp : ffff8000986876d0
x29: ffff8000986876d0 x28: 1fffe000199c09e6 x27: 1fffe000199c09da
x26: ffff0000c2aac9c0 x25: 0000000000000001 x24: ffff0000d02ad200
x23: ffff0000cce04ed0 x22: 0000000000000002 x21: 0000000000000000
x20: ffff0000e2cc0740 x19: ffffffffffffffff x18: 0000000000000000
x17: 3d3d3d3d3d3d3d3d x16: 3d3d3d3d3d3d3d3d x15: 3d3d3d3d3d3d3d3d
x14: 0000000000000000 x13: 0000000000000001 x12: 0000000000000000
x11: 0000000000000000 x10: 0000000000000002 x9 : e75ac9114b2ee700
x8 : e75ac9114b2ee700 x7 : 0000000000000000 x6 : ffff80008048ce60
x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffff8000802f7010
x2 : 0000000100000000 x1 : ffff0000d1543a80 x0 : 0000000000000000
Call trace:
 __fortify_panic+0x10/0x14 lib/string_helpers.c:1043 (P)
 fortify_memcpy_chk include/linux/fortify-string.h:547 [inline]
 cfg80211_sme_get_conn_ies net/wireless/sme.c:533 [inline]
 cfg80211_sme_connect net/wireless/sme.c:586 [inline]
 cfg80211_connect+0x1918/0x1be4 net/wireless/sme.c:1528
 cfg80211_mgd_wext_connect+0x3ac/0x508 net/wireless/wext-sme.c:57
 cfg80211_mgd_wext_siwessid+0x2c4/0x40c net/wireless/wext-sme.c:184
 cfg80211_wext_siwessid+0xc4/0x13c net/wireless/wext-compat.c:1415
 ioctl_standard_iw_point+0x678/0xb04 net/wireless/wext-core.c:864
 ioctl_standard_call+0xb4/0x178 net/wireless/wext-core.c:1049
 wireless_process_ioctl net/wireless/wext-core.c:-1 [inline]
 wext_ioctl_dispatch+0x104/0x36c net/wireless/wext-core.c:1013
 wext_handle_ioctl+0x154/0x288 net/wireless/wext-core.c:1074
 sock_ioctl+0x154/0x7ec net/socket.c:1353
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl fs/ioctl.c:583 [inline]
 __arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
 invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
 el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
 do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
 el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
 el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
 el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594
Code: d503233f a9bf7bfd 910003fd 94618cfa (d4210000) 
---[ end trace 0000000000000000 ]---


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply

* [PATCH net v2] rds: Fix inet6_addr_lst NULL dereference when IPv6 is disabled
From: Ilia Gavrilov @ 2026-07-09 16:27 UTC (permalink / raw)
  To: Allison Henderson
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Ka-Cheong Poon, Santosh Shilimkar,
	netdev@vger.kernel.org, linux-rdma@vger.kernel.org,
	rds-devel@oss.oracle.com, linux-kernel@vger.kernel.org,
	lvc-project@linuxtesting.org

When booting with the 'ipv6.disable=1' parameter, inet6_addr_lst
is never initialized because inet6_init() exits before addrconf_init()
is called to initialize it. An attempt to bind an RDS socket to
an ipv6 address results in a crash in __ipv6_chk_addr_and_flags()

KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
RIP: 0010:__ipv6_chk_addr_and_flags+0x1df/0x7e0
Call Trace:
 <TASK>
 ipv6_chk_addr+0x3b/0x50
 rds_tcp_laddr_check+0x155/0x3b0 [rds_tcp]
 rds_trans_get_preferred+0x15d/0x2d0 [rds]
 ? trace_hardirqs_on+0x2d/0x110
 rds_bind+0x1433/0x1d60 [rds]
 ? rds_remove_bound+0xd50/0xd50 [rds]
 ? aa_af_perm+0x250/0x250
 ? __might_fault+0xde/0x190
 ? __sys_bind+0x1dc/0x210
 __sys_bind+0x1dc/0x210
 ? __ia32_sys_socketpair+0x100/0x100
 ? restore_fpregs_from_fpstate+0x53/0x100
 __x64_sys_bind+0x73/0xb0
 ? syscall_enter_from_user_mode+0x1c/0x50
 do_syscall_64+0x34/0x80
 entry_SYSCALL_64_after_hwframe+0x6e/0xd8
RIP: 0033:0x7f47f8269ea9
 </TASK>

The following code reproduces the issue:

struct sockaddr_in6 addr;
s = socket(PF_RDS, SOCK_SEQPACKET, 0);

memset(&addr, 0, sizeof(addr));
inet_pton(AF_INET6, ADDRESS, &addr.sin6_addr);
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(PORT);

bind(s, &addr, sizeof(addr));

Found by InfoTeCS on behalf of Linux Verification Center
(linuxtesting.org) with Syzkaller.

Fixes: eee2fa6ab322 ("rds: Changing IP address internal representation to struct in6_addr")
Fixes: 1e2b44e78eea ("rds: Enable RDS IPv6 support")
Signed-off-by: Ilia Gavrilov <Ilia.Gavrilov@infotecs.ru>
---
v2: Add a similar check for inbound link-local IPv6 connects

 net/rds/ib.c    | 4 ++++
 net/rds/ib_cm.c | 4 ++++
 net/rds/tcp.c   | 8 +++++---
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/net/rds/ib.c b/net/rds/ib.c
index 39f87272e071..8f9cf491984f 100644
--- a/net/rds/ib.c
+++ b/net/rds/ib.c
@@ -429,6 +429,10 @@ static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr,
 		sa = (struct sockaddr *)&sin;
 	} else {
 #if IS_ENABLED(CONFIG_IPV6)
+		if (!ipv6_mod_enabled()) {
+			ret = -EADDRNOTAVAIL;
+			goto out;
+		}
 		memset(&sin6, 0, sizeof(sin6));
 		sin6.sin6_family = AF_INET6;
 		sin6.sin6_addr = *addr;
diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c
index 5667f0173b47..d46146887ba4 100644
--- a/net/rds/ib_cm.c
+++ b/net/rds/ib_cm.c
@@ -810,6 +810,10 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
 	dp = event->param.conn.private_data;
 	if (isv6) {
 #if IS_ENABLED(CONFIG_IPV6)
+		if (!ipv6_mod_enabled()) {
+			err = -EOPNOTSUPP;
+			goto out;
+		}
 		dp_cmn = &dp->ricp_v6.dp_cmn;
 		saddr6 = &dp->ricp_v6.dp_saddr;
 		daddr6 = &dp->ricp_v6.dp_daddr;
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index a1de114d5e2e..955d92277d5a 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -366,9 +366,11 @@ int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
 		rcu_read_unlock();
 	}
 #if IS_ENABLED(CONFIG_IPV6)
-	ret = ipv6_chk_addr(net, addr, dev, 0);
-	if (ret)
-		return 0;
+	if (ipv6_mod_enabled()) {
+		ret = ipv6_chk_addr(net, addr, dev, 0);
+		if (ret)
+			return 0;
+	}
 #endif
 	return -EADDRNOTAVAIL;
 }
-- 
2.47.3

^ permalink raw reply related

* Re: [PATCH net-next 00/11][pull request] Intel Wired LAN Driver Updates 2026-07-01 (igc, igb)
From: Tony Nguyen @ 2026-07-09 16:23 UTC (permalink / raw)
  To: Paolo Abeni, davem, kuba, edumazet, andrew+netdev, netdev; +Cc: horms
In-Reply-To: <c9ccb69f-43a4-4462-9dc8-d08aec7ca433@redhat.com>



On 7/8/2026 5:41 AM, Paolo Abeni wrote:
> On 7/1/26 11:02 PM, Tony Nguyen wrote:
>> Kohei Enju adds ethtool support for get/set hash key on igc and adds
>> setting of skb hash type based on values from Rx descriptor on igb.
>>
>> Takashi Kozu adds ethtool support for get/set hash key on igb.
>>
>> Faizal adds support for forcing link speed via ethtool when
>> autonegotiation is disabled on the igc driver.
>>
>> The following are changes since commit d6e81529749190123aa0040626c7e5dbc20fdc9a:
>>    Merge branch 'net-fib_rules-rtnl-less-rtm_newrule-and-rtm_delrule'
>> and are available in the git repository at:
>>    git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue 1GbE
> 
> Sashiko gemini has some comments, please follow-up with them as needed:
> 
> https://sashiko.dev/#/patchset/20260701210303.1745310-1-anthony.l.nguyen%40intel.com

Hi Paolo,

Will do.

Thanks,
Tony

> /P
> 


^ permalink raw reply

* Re: [PATCH net-next] net: airoha: add preliminary support to configure tx hw QoS queue during flowtable offloading
From: Simon Horman @ 2026-07-09 16:23 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260703-airoha-hw-qos-queue-stub-v1-1-ef253ffdd093@kernel.org>

On Fri, Jul 03, 2026 at 01:02:17PM +0200, Lorenzo Bianconi wrote:
> Add the plumbing to program the AIROHA_FOE_QID field in the PPE FOE
> entry with a per-flow priority value during flowtable offload. This
> allows the hardware to steer offloaded flows to a specific QoS queue
> on the egress QDMA block for traffic forwarded between two interfaces
> via hardware acceleration, bypassing the kernel forwarding path.
> The priority parameter is currently always zero because netfilter does
> not yet provide a mechanism to pass the skb priority field to the
> flowtable offload driver. Once that support is added in the netfilter
> subsystem, the driver will be able to extract the priority from the
> flow rule and map it to the appropriate hardware queue.
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* Re: [PATCH net-next] net: Convert %pK back to %p
From: Kees Cook @ 2026-07-09 16:18 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: linux-atm-general, linux-can, linux-sctp, netdev, David S. Miller,
	Eric Dumazet, Herbert Xu, Jakub Kicinski, Kuniyuki Iwashima,
	Marc Kleine-Budde, Marcelo Ricardo Leitner, Neal Cardwell,
	Oliver Hartkopp, Paolo Abeni, Remi Denis-Courmont, Simon Horman,
	Steffen Klassert, Willem de Bruijn, Xin Long, Petr Mladek,
	Thomas Weißschuh
In-Reply-To: <20260706073824.xixrLxoD@linutronix.de>

On Mon, Jul 06, 2026 at 09:38:24AM +0200, Sebastian Andrzej Siewior wrote:
> This is a revert of commit 71338aa7d050c ("net: convert %p usage to
> %pK") which is from 2011. Back then the default behaviour for %p was to
> print the pointer. The %pK modifier was introduced to be able to control
> the behaviour of specific pointer output without changing the behaviour
> of %p for everyone. It was dedicated to avoid leaking pointers via
> /proc.

Given the policy on bare %p, and that there are so few in this list (15
files), how about review those that can just simply be removed or
switched to %pS, etc:
https://docs.kernel.org/process/deprecated.html#p-format-specifier

-- 
Kees Cook

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox