Hi, if you pick this patch, then please also pick "wifi: iwlwifi: pcie: Fix TSO preparation" which was submitted recently. Otherwise there is a regression in the n_segments calculation that can lead to packet loss. https://lore.kernel.org/linux-wireless/20250306122425.8c0e23a3d583.I3cb4d6768c9d28ce3da6cd0a6c65466176cfc1ee@changeid/ Benjamin On Mon, 2025-03-10 at 18:04 +0100, Greg Kroah-Hartman wrote: > 6.13-stable review patch. If anyone has any objections, please let me know. > > ------------------ > > From: Ilan Peer <ilan.peer@xxxxxxxxx> > > [ Upstream commit 3640dbc1f75ce15d128ea4af44226960d894f3fd ] > > The TSO preparation assumed that the skb head contained the headers > while the rest of the data was in the fragments. Since this is not > always true, e.g., it is possible that the data was linearised, modify > the TSO preparation to start the data processing after the network > headers. > > Fixes: 7f5e3038f029 ("wifi: iwlwifi: map entire SKB when sending AMSDUs") > Signed-off-by: Ilan Peer <ilan.peer@xxxxxxxxx> > Reviewed-by: Benjamin Berg <benjamin.berg@xxxxxxxxx> > Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@xxxxxxxxx> > Link: https://patch.msgid.link/20250209143303.75769a4769bf.Iaf79e8538093cdf8c446c292cc96164ad6498f61@changeid > Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx> > Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> > --- > .../wireless/intel/iwlwifi/pcie/internal.h | 5 +++-- > .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 5 +++-- > drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 20 +++++++++++-------- > 3 files changed, 18 insertions(+), 12 deletions(-) > > diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h > index 27a7e0b5b3d51..ebe9b25cc53a9 100644 > --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h > +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h > @@ -1,6 +1,6 @@ > /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ > /* > - * Copyright (C) 2003-2015, 2018-2024 Intel Corporation > + * Copyright (C) 2003-2015, 2018-2025 Intel Corporation > * Copyright (C) 2013-2015 Intel Mobile Communications GmbH > * Copyright (C) 2016-2017 Intel Deutschland GmbH > */ > @@ -643,7 +643,8 @@ dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset, > unsigned int len); > struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, > struct iwl_cmd_meta *cmd_meta, > - u8 **hdr, unsigned int hdr_room); > + u8 **hdr, unsigned int hdr_room, > + unsigned int offset); > > void iwl_pcie_free_tso_pages(struct iwl_trans *trans, struct sk_buff *skb, > struct iwl_cmd_meta *cmd_meta); > diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c > index 7bb74a480d7f1..477a05cd1288b 100644 > --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c > +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c > @@ -1,7 +1,7 @@ > // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause > /* > * Copyright (C) 2017 Intel Deutschland GmbH > - * Copyright (C) 2018-2020, 2023-2024 Intel Corporation > + * Copyright (C) 2018-2020, 2023-2025 Intel Corporation > */ > #include <net/tso.h> > #include <linux/tcp.h> > @@ -188,7 +188,8 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, > (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)); > > /* Our device supports 9 segments at most, it will fit in 1 page */ > - sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room); > + sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room, > + snap_ip_tcp_hdrlen + hdr_len); > if (!sgt) > return -ENOMEM; > > diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c > index 1ef14340953c3..f46bdc0a5fec9 100644 > --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c > +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c > @@ -1,6 +1,6 @@ > // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause > /* > - * Copyright (C) 2003-2014, 2018-2021, 2023-2024 Intel Corporation > + * Copyright (C) 2003-2014, 2018-2021, 2023-2025 Intel Corporation > * Copyright (C) 2013-2015 Intel Mobile Communications GmbH > * Copyright (C) 2016-2017 Intel Deutschland GmbH > */ > @@ -1853,6 +1853,7 @@ dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset, > * @cmd_meta: command meta to store the scatter list information for unmapping > * @hdr: output argument for TSO headers > * @hdr_room: requested length for TSO headers > + * @offset: offset into the data from which mapping should start > * > * Allocate space for a scatter gather list and TSO headers and map the SKB > * using the scatter gather list. The SKB is unmapped again when the page is > @@ -1862,18 +1863,20 @@ dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset, > */ > struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, > struct iwl_cmd_meta *cmd_meta, > - u8 **hdr, unsigned int hdr_room) > + u8 **hdr, unsigned int hdr_room, > + unsigned int offset) > { > struct sg_table *sgt; > + unsigned int n_segments; > > if (WARN_ON_ONCE(skb_has_frag_list(skb))) > return NULL; > > + n_segments = DIV_ROUND_UP(skb->len - offset, skb_shinfo(skb)->gso_size); > *hdr = iwl_pcie_get_page_hdr(trans, > hdr_room + __alignof__(struct sg_table) + > sizeof(struct sg_table) + > - (skb_shinfo(skb)->nr_frags + 1) * > - sizeof(struct scatterlist), > + n_segments * sizeof(struct scatterlist), > skb); > if (!*hdr) > return NULL; > @@ -1881,11 +1884,11 @@ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, > sgt = (void *)PTR_ALIGN(*hdr + hdr_room, __alignof__(struct sg_table)); > sgt->sgl = (void *)(sgt + 1); > > - sg_init_table(sgt->sgl, skb_shinfo(skb)->nr_frags + 1); > + sg_init_table(sgt->sgl, n_segments); > > /* Only map the data, not the header (it is copied to the TSO page) */ > - sgt->orig_nents = skb_to_sgvec(skb, sgt->sgl, skb_headlen(skb), > - skb->data_len); > + sgt->orig_nents = skb_to_sgvec(skb, sgt->sgl, offset, > + skb->len - offset); > if (WARN_ON_ONCE(sgt->orig_nents <= 0)) > return NULL; > > @@ -1937,7 +1940,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, > (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len; > > /* Our device supports 9 segments at most, it will fit in 1 page */ > - sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room); > + sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room, > + snap_ip_tcp_hdrlen + hdr_len + iv_len); > if (!sgt) > return -ENOMEM; >