Linux wireless drivers development
 help / color / mirror / Atom feed
From: Ben Greear <greearb@candelatech.com>
To: Benjamin Berg <benjamin@sipsolutions.net>,
	linux-wireless@vger.kernel.org
Cc: benjamin.berg@intel.com, miriam.rachel.korenblit@intel.com,
	regressions@lists.linux.dev, johannes@sipsolutions.net,
	Kalle Valo <kvalo@kernel.org>,
	Chris Bainbridge <chris.bainbridge@gmail.com>,
	Rory Little <rory.little@candelatech.com>
Subject: Re: [PATCH] wifi: iwlwifi: correctly lookup DMA address in SG table
Date: Thu, 8 Aug 2024 10:36:53 -0700	[thread overview]
Message-ID: <85f652fa-7dc1-44ca-e185-6ecfc6269de7@candelatech.com> (raw)
In-Reply-To: <20240808172948.303258-1-benjamin@sipsolutions.net>

On 8/8/24 10:29, Benjamin Berg wrote:
> From: Benjamin Berg <benjamin.berg@intel.com>

Hello,

We'll try testing this on our systems...

Thanks,
Ben

> 
> The code to lookup the scatter gather table entry assumed that it was
> possible to use sg_virt() in order to lookup the DMA address in a mapped
> scatter gather table. However, this assumption is incorrect as the DMA
> mapping code may merge multiple entries into one. In that case, the DMA
> address space may have e.g. two consecutive pages which is correctly
> represented by the scatter gather list entry, however the virtual
> addresses for these two pages may differ and the relationship cannot be
> resolved anymore.
> 
> Avoid this problem entirely by working with the offset into the mapped
> area instead of using virtual addresses. With that we only use the DMA
> length and DMA address from the scatter gather list entries. The
> underlying DMA/IOMMU code is therefore free to merge two entries into
> one even if the virtual addresses space for the area is not continuous.
> 
> Fixes: 90db50755228 ("wifi: iwlwifi: use already mapped data when TXing an AMSDU")
> Reported-by: Chris Bainbridge <chris.bainbridge@gmail.com>
> Closes: https://lore.kernel.org/r/ZrNRoEbdkxkKFMBi@debian.local
> Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
> 
> ---
> 
> Note that I was not yet able to fully verify this patch, but will
> probably get results tomorrow. Unfortunately, much of the testing we do
> internally happens on machines that do not reproduce the problem.
> 
> Also, I think Ben already reported the same issue much earlier. At the
> time, I was not yet aware of the internal reproductions and did not take
> the report seriously.
> ---
>   .../wireless/intel/iwlwifi/pcie/internal.h    |  2 +-
>   .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c |  4 ++-
>   drivers/net/wireless/intel/iwlwifi/pcie/tx.c  | 25 +++++++++++--------
>   3 files changed, 19 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
> index b59de4f80b4b..3af9c2b40ef1 100644
> --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
> +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
> @@ -639,7 +639,7 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
>   int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq,
>   		       int slots_num, bool cmd_queue);
>   
> -dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, void *addr);
> +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);
> diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
> index 2e780fb2da42..54d26523f692 100644
> --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
> +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
> @@ -168,6 +168,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans,
>   	struct ieee80211_hdr *hdr = (void *)skb->data;
>   	unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
>   	unsigned int mss = skb_shinfo(skb)->gso_size;
> +	unsigned int data_offset = 0;
>   	dma_addr_t start_hdr_phys;
>   	u16 length, amsdu_pad;
>   	u8 *start_hdr;
> @@ -260,7 +261,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans,
>   			int ret;
>   
>   			tb_len = min_t(unsigned int, tso.size, data_left);
> -			tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, tso.data);
> +			tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, data_offset);
>   			/* Not a real mapping error, use direct comparison */
>   			if (unlikely(tb_phys == DMA_MAPPING_ERROR))
>   				goto out_err;
> @@ -272,6 +273,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans,
>   				goto out_err;
>   
>   			data_left -= tb_len;
> +			data_offset += tb_len;
>   			tso_build_data(skb, &tso, tb_len);
>   		}
>   	}
> diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
> index 22d482ae53d9..78f417cdb9ac 100644
> --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
> +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
> @@ -1814,23 +1814,24 @@ static void *iwl_pcie_get_page_hdr(struct iwl_trans *trans,
>   /**
>    * iwl_pcie_get_sgt_tb_phys - Find TB address in mapped SG list
>    * @sgt: scatter gather table
> - * @addr: Virtual address
> + * @offset: Offset into the mapped memory (i.e. SKB payload data)
>    *
> - * Find the entry that includes the address for the given address and return
> - * correct physical address for the TB entry.
> + * Find the DMA address that corresponds to the SKB payload data at the
> + * position given by @offset.
>    *
>    * Returns: Address for TB entry
>    */
> -dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, void *addr)
> +dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset)
>   {
>   	struct scatterlist *sg;
> +	unsigned int sg_offset = 0;
>   	int i;
>   
>   	for_each_sgtable_dma_sg(sgt, sg, i) {
> -		if (addr >= sg_virt(sg) &&
> -		    (u8 *)addr < (u8 *)sg_virt(sg) + sg_dma_len(sg))
> -			return sg_dma_address(sg) +
> -			       ((unsigned long)addr - (unsigned long)sg_virt(sg));
> +		if (offset >= sg_offset && offset < sg_offset + sg_dma_len(sg))
> +			return sg_dma_address(sg) + offset - sg_offset;
> +
> +		sg_offset += sg_dma_len(sg);
>   	}
>   
>   	WARN_ON_ONCE(1);
> @@ -1875,7 +1876,9 @@ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb,
>   
>   	sg_init_table(sgt->sgl, skb_shinfo(skb)->nr_frags + 1);
>   
> -	sgt->orig_nents = skb_to_sgvec(skb, sgt->sgl, 0, skb->len);
> +	/* 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);
>   	if (WARN_ON_ONCE(sgt->orig_nents <= 0))
>   		return NULL;
>   
> @@ -1900,6 +1903,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
>   	struct ieee80211_hdr *hdr = (void *)skb->data;
>   	unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
>   	unsigned int mss = skb_shinfo(skb)->gso_size;
> +	unsigned int data_offset = 0;
>   	u16 length, iv_len, amsdu_pad;
>   	dma_addr_t start_hdr_phys;
>   	u8 *start_hdr, *pos_hdr;
> @@ -2000,7 +2004,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
>   						  data_left);
>   			dma_addr_t tb_phys;
>   
> -			tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, tso.data);
> +			tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, data_offset);
>   			/* Not a real mapping error, use direct comparison */
>   			if (unlikely(tb_phys == DMA_MAPPING_ERROR))
>   				return -EINVAL;
> @@ -2011,6 +2015,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
>   						tb_phys, size);
>   
>   			data_left -= size;
> +			data_offset += size;
>   			tso_build_data(skb, &tso, size);
>   		}
>   	}

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com



  reply	other threads:[~2024-08-08 17:37 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-08 17:29 [PATCH] wifi: iwlwifi: correctly lookup DMA address in SG table Benjamin Berg
2024-08-08 17:36 ` Ben Greear [this message]
2024-08-09 18:03   ` Rory Little
2024-08-08 18:39 ` Kalle Valo
2024-08-08 20:33 ` Chris Bainbridge
2024-08-12 11:30 ` Kalle Valo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=85f652fa-7dc1-44ca-e185-6ecfc6269de7@candelatech.com \
    --to=greearb@candelatech.com \
    --cc=benjamin.berg@intel.com \
    --cc=benjamin@sipsolutions.net \
    --cc=chris.bainbridge@gmail.com \
    --cc=johannes@sipsolutions.net \
    --cc=kvalo@kernel.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=miriam.rachel.korenblit@intel.com \
    --cc=regressions@lists.linux.dev \
    --cc=rory.little@candelatech.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox