linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V2] ath10k: allocate small size dma memory in ath10k_pci_diag_write_mem
@ 2018-10-10 11:34 Carl Huang
  2018-10-10 18:20 ` Brian Norris
  0 siblings, 1 reply; 2+ messages in thread
From: Carl Huang @ 2018-10-10 11:34 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless

ath10k_pci_diag_write_mem may allocate big size of the dma memory
based on the parameter nbytes. Take firmware diag download as
example, the biggest size is about 500K. In some systems, the
allocation is likely to fail because it can't acquire such a large
contiguous dma memory.

The fix is to allocate a small size dma memory. In the loop,
driver copies the data to the allocated dma memory and writes to
the destination until all the data is written.

Tested with QCA6174 PCI with
firmware-6.bin_WLAN.RM.4.4.1-00119-QCARMSWP-1, this also affects
QCA9377 PCI.

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
Reviewed-by: Brian Norris <briannorris@chomium.org>
---
V2:
  *addressed Brian's comment. Removed ce_data variable.

 drivers/net/wireless/ath/ath10k/pci.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 873dbb6..a269077 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1071,10 +1071,9 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
 	struct ath10k_ce *ce = ath10k_ce_priv(ar);
 	int ret = 0;
 	u32 *buf;
-	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
+	unsigned int completed_nbytes, alloc_nbytes, remaining_bytes;
 	struct ath10k_ce_pipe *ce_diag;
 	void *data_buf = NULL;
-	u32 ce_data;	/* Host buffer address in CE space */
 	dma_addr_t ce_data_base = 0;
 	int i;
 
@@ -1088,9 +1087,10 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
 	 *   1) 4-byte alignment
 	 *   2) Buffer in DMA-able space
 	 */
-	orig_nbytes = nbytes;
+	alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT);
+
 	data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
-						       orig_nbytes,
+						       alloc_nbytes,
 						       &ce_data_base,
 						       GFP_ATOMIC);
 	if (!data_buf) {
@@ -1098,9 +1098,6 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
 		goto done;
 	}
 
-	/* Copy caller's data to allocated DMA buf */
-	memcpy(data_buf, data, orig_nbytes);
-
 	/*
 	 * The address supplied by the caller is in the
 	 * Target CPU virtual address space.
@@ -1113,12 +1110,14 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
 	 */
 	address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);
 
-	remaining_bytes = orig_nbytes;
-	ce_data = ce_data_base;
+	remaining_bytes = nbytes;
 	while (remaining_bytes) {
 		/* FIXME: check cast */
 		nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
 
+		/* Copy caller's data to allocated DMA buf */
+		memcpy(data_buf, data, nbytes);
+
 		/* Set up to receive directly into Target(!) address */
 		ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &address, address);
 		if (ret != 0)
@@ -1128,7 +1127,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
 		 * Request CE to send caller-supplied data that
 		 * was copied to bounce buffer to Target(!) address.
 		 */
-		ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data,
+		ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data_base,
 					    nbytes, 0, 0);
 		if (ret != 0)
 			goto done;
@@ -1171,12 +1170,12 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
 
 		remaining_bytes -= nbytes;
 		address += nbytes;
-		ce_data += nbytes;
+		data += nbytes;
 	}
 
 done:
 	if (data_buf) {
-		dma_free_coherent(ar->dev, orig_nbytes, data_buf,
+		dma_free_coherent(ar->dev, alloc_nbytes, data_buf,
 				  ce_data_base);
 	}
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH V2] ath10k: allocate small size dma memory in ath10k_pci_diag_write_mem
  2018-10-10 11:34 [PATCH V2] ath10k: allocate small size dma memory in ath10k_pci_diag_write_mem Carl Huang
@ 2018-10-10 18:20 ` Brian Norris
  0 siblings, 0 replies; 2+ messages in thread
From: Brian Norris @ 2018-10-10 18:20 UTC (permalink / raw)
  To: Carl Huang; +Cc: ath10k, linux-wireless

Hi Carl,

On Wed, Oct 10, 2018 at 07:34:29PM +0800, Carl Huang wrote:
> --- a/drivers/net/wireless/ath/ath10k/pci.c
> +++ b/drivers/net/wireless/ath/ath10k/pci.c
> @@ -1071,10 +1071,9 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
>  	struct ath10k_ce *ce = ath10k_ce_priv(ar);
>  	int ret = 0;
>  	u32 *buf;
> -	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
> +	unsigned int completed_nbytes, alloc_nbytes, remaining_bytes;
>  	struct ath10k_ce_pipe *ce_diag;
>  	void *data_buf = NULL;
> -	u32 ce_data;	/* Host buffer address in CE space */
>  	dma_addr_t ce_data_base = 0;
>  	int i;
>  

...

> @@ -1128,7 +1127,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
>  		 * Request CE to send caller-supplied data that
>  		 * was copied to bounce buffer to Target(!) address.
>  		 */
> -		ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data,
> +		ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data_base,

The (u32) cast isn't necessary, is it? ath10k_ce_send_nolock() takes a
dma_addr_t for the 3rd argument.

Incidentally, that'd probably help if you start supporting PCI devices
with >32-bit addressing.

Brian

>  					    nbytes, 0, 0);
>  		if (ret != 0)
>  			goto done;
...

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-10-10 18:20 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-10 11:34 [PATCH V2] ath10k: allocate small size dma memory in ath10k_pci_diag_write_mem Carl Huang
2018-10-10 18:20 ` Brian Norris

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).