Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e56d512 authored by Ashok Raj Nagarajan's avatar Ashok Raj Nagarajan Committed by Kalle Valo
Browse files

ath10k: fix diag_read to collect data for larger memory



diag_read uses dma_alloc_coherent to allocate memory requested by the
caller. If this memory requested is larger, more than DIAG_TRANSFER_LIMIT
(2K), then it is likely that we may not get the requested memory and we
would fail.

To solve this, request dma_alloc_coherent for only DIAG_TRANSFER_LIMIT, and
reuse this buffer multiple times as needed to copy the data requested in
smaller chunks of size not more than DIAG_TRANSFER_LIMIT. Previously we
were reading into the caller's only after getting the complete requested
data.

Fixes: 68c03249 ('ath10k: convert pci_alloc_consistent() to dma_alloc_coherent()')
Signed-off-by: default avatarAshok Raj Nagarajan <arnagara@qti.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 8a0a36cf
Loading
Loading
Loading
Loading
+16 −12
Original line number Original line Diff line number Diff line
@@ -869,7 +869,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
	int ret = 0;
	int ret = 0;
	u32 *buf;
	u32 *buf;
	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
	unsigned int completed_nbytes, alloc_nbytes, remaining_bytes;
	struct ath10k_ce_pipe *ce_diag;
	struct ath10k_ce_pipe *ce_diag;
	/* Host buffer address in CE space */
	/* Host buffer address in CE space */
	u32 ce_data;
	u32 ce_data;
@@ -887,9 +887,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
	 *   1) 4-byte alignment
	 *   1) 4-byte alignment
	 *   2) Buffer in DMA-able space
	 *   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,
	data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
						       orig_nbytes,
						       alloc_nbytes,
						       &ce_data_base,
						       &ce_data_base,
						       GFP_ATOMIC);
						       GFP_ATOMIC);


@@ -897,9 +898,9 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto done;
		goto done;
	}
	}
	memset(data_buf, 0, orig_nbytes);
	memset(data_buf, 0, alloc_nbytes);


	remaining_bytes = orig_nbytes;
	remaining_bytes = nbytes;
	ce_data = ce_data_base;
	ce_data = ce_data_base;
	while (remaining_bytes) {
	while (remaining_bytes) {
		nbytes = min_t(unsigned int, remaining_bytes,
		nbytes = min_t(unsigned int, remaining_bytes,
@@ -959,19 +960,22 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
		}
		}


		remaining_bytes -= nbytes;
		remaining_bytes -= nbytes;

		if (ret) {
			ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
				    address, ret);
			break;
		}
		memcpy(data, data_buf, nbytes);

		address += nbytes;
		address += nbytes;
		ce_data += nbytes;
		data += nbytes;
	}
	}


done:
done:
	if (ret == 0)
		memcpy(data, data_buf, orig_nbytes);
	else
		ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
			    address, ret);


	if (data_buf)
	if (data_buf)
		dma_free_coherent(ar->dev, orig_nbytes, data_buf,
		dma_free_coherent(ar->dev, alloc_nbytes, data_buf,
				  ce_data_base);
				  ce_data_base);


	spin_unlock_bh(&ar_pci->ce_lock);
	spin_unlock_bh(&ar_pci->ce_lock);