Skip to content

Commit

Permalink
ath10k: allocate small size dma memory in ath10k_pci_diag_write_mem
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  • Loading branch information
Carl Huang authored and Kalle Valo committed Oct 13, 2018
1 parent 9de4162 commit 0738b49
Showing 1 changed file with 11 additions and 12 deletions.
23 changes: 11 additions & 12 deletions drivers/net/wireless/ath/ath10k/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -1088,19 +1087,17 @@ 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) {
ret = -ENOMEM;
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.
Expand All @@ -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)
Expand All @@ -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, ce_data_base,
nbytes, 0, 0);
if (ret != 0)
goto done;
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 0738b49

Please sign in to comment.