xref: /wlan-driver/qca-wifi-host-cmn/hif/src/ce/ce_diag.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name #include "targcfg.h"
21*5113495bSYour Name #include "target_type.h"
22*5113495bSYour Name #include "qdf_lock.h"
23*5113495bSYour Name #include "qdf_status.h"
24*5113495bSYour Name #include "qdf_status.h"
25*5113495bSYour Name #include <qdf_atomic.h>         /* qdf_atomic_read */
26*5113495bSYour Name #include <targaddrs.h>
27*5113495bSYour Name #include "hif_io32.h"
28*5113495bSYour Name #include <hif.h>
29*5113495bSYour Name #include "regtable.h"
30*5113495bSYour Name #include <a_debug.h>
31*5113495bSYour Name #include "hif_main.h"
32*5113495bSYour Name #include "ce_api.h"
33*5113495bSYour Name #include "qdf_trace.h"
34*5113495bSYour Name #include "hif_debug.h"
35*5113495bSYour Name #include "qdf_module.h"
36*5113495bSYour Name 
37*5113495bSYour Name void
hif_ce_dump_target_memory(struct hif_softc * scn,void * ramdump_base,uint32_t address,uint32_t size)38*5113495bSYour Name hif_ce_dump_target_memory(struct hif_softc *scn, void *ramdump_base,
39*5113495bSYour Name 						uint32_t address, uint32_t size)
40*5113495bSYour Name {
41*5113495bSYour Name 	uint32_t loc = address;
42*5113495bSYour Name 	uint32_t val = 0;
43*5113495bSYour Name 	uint32_t j = 0;
44*5113495bSYour Name 	u8 *temp = ramdump_base;
45*5113495bSYour Name 
46*5113495bSYour Name 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
47*5113495bSYour Name 		return;
48*5113495bSYour Name 
49*5113495bSYour Name 	while (j < size) {
50*5113495bSYour Name 		val = hif_read32_mb(scn, scn->mem + loc + j);
51*5113495bSYour Name 		qdf_mem_copy(temp, &val, 4);
52*5113495bSYour Name 		j += 4;
53*5113495bSYour Name 		temp += 4;
54*5113495bSYour Name 	}
55*5113495bSYour Name 
56*5113495bSYour Name 	Q_TARGET_ACCESS_END(scn);
57*5113495bSYour Name }
58*5113495bSYour Name /*
59*5113495bSYour Name  * TBDXXX: Should be a function call specific to each Target-type.
60*5113495bSYour Name  * This convoluted macro converts from Target CPU Virtual Address
61*5113495bSYour Name  * Space to CE Address Space. As part of this process, we
62*5113495bSYour Name  * conservatively fetch the current PCIE_BAR. MOST of the time,
63*5113495bSYour Name  * this should match the upper bits of PCI space for this device;
64*5113495bSYour Name  * but that's not guaranteed.
65*5113495bSYour Name  */
66*5113495bSYour Name #ifdef QCA_WIFI_3_0
67*5113495bSYour Name #define TARG_CPU_SPACE_TO_CE_SPACE(sc, pci_addr, addr) \
68*5113495bSYour Name 	(scn->mem_pa + addr)
69*5113495bSYour Name #else
70*5113495bSYour Name #define TARG_CPU_SPACE_TO_CE_SPACE(sc, pci_addr, addr) \
71*5113495bSYour Name 	(((hif_read32_mb(sc, (pci_addr) + \
72*5113495bSYour Name 	(SOC_CORE_BASE_ADDRESS|CORE_CTRL_ADDRESS)) & 0x7ff) << 21) \
73*5113495bSYour Name 	 | 0x100000 | ((addr) & 0xfffff))
74*5113495bSYour Name #endif
75*5113495bSYour Name 
76*5113495bSYour Name #define TARG_CPU_SPACE_TO_CE_SPACE_AR900B(scn, pci_addr, addr) \
77*5113495bSYour Name 	(hif_read32_mb(scn, (pci_addr) + (WIFICMN_PCIE_BAR_REG_ADDRESS)) \
78*5113495bSYour Name 	| 0x100000 | ((addr) & 0xfffff))
79*5113495bSYour Name 
80*5113495bSYour Name #define SRAM_BASE_ADDRESS 0xc0000
81*5113495bSYour Name #define SRAM_END_ADDRESS 0x100000
82*5113495bSYour Name 
83*5113495bSYour Name /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
84*5113495bSYour Name #define DIAG_ACCESS_CE_TIMEOUT_MS 10
85*5113495bSYour Name 
86*5113495bSYour Name /**
87*5113495bSYour Name  * get_ce_phy_addr() - get the physical address of an soc virtual address
88*5113495bSYour Name  * @sc: hif context
89*5113495bSYour Name  * @address: soc virtual address
90*5113495bSYour Name  * @target_type: target type being used.
91*5113495bSYour Name  *
92*5113495bSYour Name  * Return: soc physical address
93*5113495bSYour Name  */
get_ce_phy_addr(struct hif_softc * sc,uint32_t address,unsigned int target_type)94*5113495bSYour Name static qdf_dma_addr_t get_ce_phy_addr(struct hif_softc *sc, uint32_t  address,
95*5113495bSYour Name 				      unsigned int target_type)
96*5113495bSYour Name {
97*5113495bSYour Name 	qdf_dma_addr_t ce_phy_addr;
98*5113495bSYour Name 	struct hif_softc *scn = sc;
99*5113495bSYour Name 
100*5113495bSYour Name 	if ((target_type == TARGET_TYPE_AR900B) ||
101*5113495bSYour Name 	    (target_type == TARGET_TYPE_QCA9984) ||
102*5113495bSYour Name 	    (target_type == TARGET_TYPE_QCA9888)) {
103*5113495bSYour Name 		ce_phy_addr =
104*5113495bSYour Name 		    TARG_CPU_SPACE_TO_CE_SPACE_AR900B(sc, sc->mem, address);
105*5113495bSYour Name 	} else {
106*5113495bSYour Name 		ce_phy_addr =
107*5113495bSYour Name 		    TARG_CPU_SPACE_TO_CE_SPACE(sc, sc->mem, address);
108*5113495bSYour Name 	}
109*5113495bSYour Name 
110*5113495bSYour Name 	return ce_phy_addr;
111*5113495bSYour Name }
112*5113495bSYour Name 
113*5113495bSYour Name /*
114*5113495bSYour Name  * Diagnostic read/write access is provided for startup/config/debug usage.
115*5113495bSYour Name  * Caller must guarantee proper alignment, when applicable, and single user
116*5113495bSYour Name  * at any moment.
117*5113495bSYour Name  */
118*5113495bSYour Name 
119*5113495bSYour Name #define FW_SRAM_ADDRESS     0x000C0000
120*5113495bSYour Name 
hif_diag_read_mem(struct hif_opaque_softc * hif_ctx,uint32_t address,uint8_t * data,int nbytes)121*5113495bSYour Name QDF_STATUS hif_diag_read_mem(struct hif_opaque_softc *hif_ctx,
122*5113495bSYour Name 			     uint32_t address, uint8_t *data, int nbytes)
123*5113495bSYour Name {
124*5113495bSYour Name 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
125*5113495bSYour Name 
126*5113495bSYour Name 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
127*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
128*5113495bSYour Name 	qdf_dma_addr_t buf;
129*5113495bSYour Name 	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
130*5113495bSYour Name 	unsigned int id;
131*5113495bSYour Name 	unsigned int flags;
132*5113495bSYour Name 	struct CE_handle *ce_diag;
133*5113495bSYour Name 	qdf_dma_addr_t CE_data;      /* Host buffer address in CE space */
134*5113495bSYour Name 	qdf_dma_addr_t CE_data_base = 0;
135*5113495bSYour Name 	void *data_buf = NULL;
136*5113495bSYour Name 	int i;
137*5113495bSYour Name 	unsigned int mux_id = 0;
138*5113495bSYour Name 	unsigned int transaction_id = 0xffff;
139*5113495bSYour Name 	qdf_dma_addr_t ce_phy_addr = address;
140*5113495bSYour Name 	unsigned int toeplitz_hash_result;
141*5113495bSYour Name 	unsigned int user_flags = 0;
142*5113495bSYour Name 	unsigned int target_type = 0;
143*5113495bSYour Name 	unsigned int boundary_addr = 0;
144*5113495bSYour Name 
145*5113495bSYour Name 	ce_diag = hif_state->ce_diag;
146*5113495bSYour Name 	if (!ce_diag) {
147*5113495bSYour Name 		hif_err("DIAG CE not present");
148*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
149*5113495bSYour Name 	}
150*5113495bSYour Name 	/* not supporting diag ce on srng based systems, therefore we know this
151*5113495bSYour Name 	 * isn't an srng based system */
152*5113495bSYour Name 
153*5113495bSYour Name 	transaction_id = (mux_id & MUX_ID_MASK) |
154*5113495bSYour Name 		 (transaction_id & TRANSACTION_ID_MASK);
155*5113495bSYour Name #ifdef QCA_WIFI_3_0
156*5113495bSYour Name 	user_flags &= DESC_DATA_FLAG_MASK;
157*5113495bSYour Name #endif
158*5113495bSYour Name 	target_type = (hif_get_target_info_handle(hif_ctx))->target_type;
159*5113495bSYour Name 
160*5113495bSYour Name 	/* This code cannot handle reads to non-memory space. Redirect to the
161*5113495bSYour Name 	 * register read fn but preserve the multi word read capability of
162*5113495bSYour Name 	 * this fn
163*5113495bSYour Name 	 */
164*5113495bSYour Name 	if ((target_type == TARGET_TYPE_AR900B)  ||
165*5113495bSYour Name 	    (target_type == TARGET_TYPE_QCA9984) ||
166*5113495bSYour Name 	    (target_type == TARGET_TYPE_AR9888) ||
167*5113495bSYour Name 	    (target_type == TARGET_TYPE_QCA9888))
168*5113495bSYour Name 		boundary_addr = FW_SRAM_ADDRESS;
169*5113495bSYour Name 	else
170*5113495bSYour Name 		boundary_addr = DRAM_BASE_ADDRESS;
171*5113495bSYour Name 
172*5113495bSYour Name 	if (address < boundary_addr) {
173*5113495bSYour Name 
174*5113495bSYour Name 		if ((address & 0x3) || ((uintptr_t) data & 0x3))
175*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
176*5113495bSYour Name 
177*5113495bSYour Name 		while ((nbytes >= 4) &&
178*5113495bSYour Name 		       (QDF_STATUS_SUCCESS == (status =
179*5113495bSYour Name 				 hif_diag_read_access(hif_ctx, address,
180*5113495bSYour Name 				       (uint32_t *)data)))) {
181*5113495bSYour Name 
182*5113495bSYour Name 			nbytes -= sizeof(uint32_t);
183*5113495bSYour Name 			address += sizeof(uint32_t);
184*5113495bSYour Name 			data += sizeof(uint32_t);
185*5113495bSYour Name 
186*5113495bSYour Name 		}
187*5113495bSYour Name 
188*5113495bSYour Name 		return status;
189*5113495bSYour Name 	}
190*5113495bSYour Name 
191*5113495bSYour Name 	A_TARGET_ACCESS_LIKELY(scn);
192*5113495bSYour Name 
193*5113495bSYour Name 	/*
194*5113495bSYour Name 	 * Allocate a temporary bounce buffer to hold caller's data
195*5113495bSYour Name 	 * to be DMA'ed from Target. This guarantees
196*5113495bSYour Name 	 *   1) 4-byte alignment
197*5113495bSYour Name 	 *   2) Buffer in DMA-able space
198*5113495bSYour Name 	 */
199*5113495bSYour Name 	orig_nbytes = nbytes;
200*5113495bSYour Name 	data_buf = qdf_mem_alloc_consistent(scn->qdf_dev, scn->qdf_dev->dev,
201*5113495bSYour Name 				    orig_nbytes, &CE_data_base);
202*5113495bSYour Name 	if (!data_buf) {
203*5113495bSYour Name 		status = QDF_STATUS_E_NOMEM;
204*5113495bSYour Name 		goto done;
205*5113495bSYour Name 	}
206*5113495bSYour Name 	qdf_mem_zero(data_buf, orig_nbytes);
207*5113495bSYour Name 
208*5113495bSYour Name 	remaining_bytes = orig_nbytes;
209*5113495bSYour Name 	CE_data = CE_data_base;
210*5113495bSYour Name 	while (remaining_bytes) {
211*5113495bSYour Name 		nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT);
212*5113495bSYour Name 		{
213*5113495bSYour Name 			status = ce_recv_buf_enqueue(ce_diag, NULL, CE_data);
214*5113495bSYour Name 			if (status != QDF_STATUS_SUCCESS)
215*5113495bSYour Name 				goto done;
216*5113495bSYour Name 		}
217*5113495bSYour Name 
218*5113495bSYour Name 		if (Q_TARGET_ACCESS_BEGIN(scn) < 0) {
219*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
220*5113495bSYour Name 			goto done;
221*5113495bSYour Name 		}
222*5113495bSYour Name 
223*5113495bSYour Name 		/* convert soc virtual address to physical address */
224*5113495bSYour Name 		ce_phy_addr = get_ce_phy_addr(scn, address, target_type);
225*5113495bSYour Name 
226*5113495bSYour Name 		if (Q_TARGET_ACCESS_END(scn) < 0) {
227*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
228*5113495bSYour Name 			goto done;
229*5113495bSYour Name 		}
230*5113495bSYour Name 
231*5113495bSYour Name 		/* Request CE to send from Target(!)
232*5113495bSYour Name 		 * address to Host buffer
233*5113495bSYour Name 		 */
234*5113495bSYour Name 		status = ce_send(ce_diag, NULL, ce_phy_addr, nbytes,
235*5113495bSYour Name 				transaction_id, 0, user_flags);
236*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
237*5113495bSYour Name 			goto done;
238*5113495bSYour Name 
239*5113495bSYour Name 		i = 0;
240*5113495bSYour Name 		while (ce_completed_send_next(ce_diag, NULL, NULL, &buf,
241*5113495bSYour Name 				&completed_nbytes, &id, NULL, NULL,
242*5113495bSYour Name 				&toeplitz_hash_result) != QDF_STATUS_SUCCESS) {
243*5113495bSYour Name 			qdf_mdelay(1);
244*5113495bSYour Name 			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
245*5113495bSYour Name 				status = QDF_STATUS_E_BUSY;
246*5113495bSYour Name 				goto done;
247*5113495bSYour Name 			}
248*5113495bSYour Name 		}
249*5113495bSYour Name 		if (nbytes != completed_nbytes) {
250*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
251*5113495bSYour Name 			goto done;
252*5113495bSYour Name 		}
253*5113495bSYour Name 		if (buf != ce_phy_addr) {
254*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
255*5113495bSYour Name 			goto done;
256*5113495bSYour Name 		}
257*5113495bSYour Name 
258*5113495bSYour Name 		i = 0;
259*5113495bSYour Name 		while (ce_completed_recv_next
260*5113495bSYour Name 				(ce_diag, NULL, NULL, &buf,
261*5113495bSYour Name 				&completed_nbytes, &id,
262*5113495bSYour Name 				 &flags) != QDF_STATUS_SUCCESS) {
263*5113495bSYour Name 			qdf_mdelay(1);
264*5113495bSYour Name 			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
265*5113495bSYour Name 				status = QDF_STATUS_E_BUSY;
266*5113495bSYour Name 				goto done;
267*5113495bSYour Name 			}
268*5113495bSYour Name 		}
269*5113495bSYour Name 		if (nbytes != completed_nbytes) {
270*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
271*5113495bSYour Name 			goto done;
272*5113495bSYour Name 		}
273*5113495bSYour Name 		if (buf != CE_data) {
274*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
275*5113495bSYour Name 			goto done;
276*5113495bSYour Name 		}
277*5113495bSYour Name 
278*5113495bSYour Name 		remaining_bytes -= nbytes;
279*5113495bSYour Name 		address += nbytes;
280*5113495bSYour Name 		CE_data += nbytes;
281*5113495bSYour Name 	}
282*5113495bSYour Name 
283*5113495bSYour Name done:
284*5113495bSYour Name 	A_TARGET_ACCESS_UNLIKELY(scn);
285*5113495bSYour Name 
286*5113495bSYour Name 	if (status == QDF_STATUS_SUCCESS)
287*5113495bSYour Name 		qdf_mem_copy(data, data_buf, orig_nbytes);
288*5113495bSYour Name 	else
289*5113495bSYour Name 		hif_err("Failure (0x%x)", address);
290*5113495bSYour Name 
291*5113495bSYour Name 	if (data_buf)
292*5113495bSYour Name 		qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev,
293*5113495bSYour Name 				orig_nbytes, data_buf, CE_data_base, 0);
294*5113495bSYour Name 
295*5113495bSYour Name 	return status;
296*5113495bSYour Name }
297*5113495bSYour Name qdf_export_symbol(hif_diag_read_mem);
298*5113495bSYour Name 
299*5113495bSYour Name /* Read 4-byte aligned data from Target memory or register */
hif_diag_read_access(struct hif_opaque_softc * hif_ctx,uint32_t address,uint32_t * data)300*5113495bSYour Name QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *hif_ctx,
301*5113495bSYour Name 				uint32_t address, uint32_t *data)
302*5113495bSYour Name {
303*5113495bSYour Name 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
304*5113495bSYour Name 
305*5113495bSYour Name 	if (address >= DRAM_BASE_ADDRESS) {
306*5113495bSYour Name 		/* Assume range doesn't cross this boundary */
307*5113495bSYour Name 		return hif_diag_read_mem(hif_ctx, address, (uint8_t *) data,
308*5113495bSYour Name 					 sizeof(uint32_t));
309*5113495bSYour Name 	} else {
310*5113495bSYour Name 		if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
311*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
312*5113495bSYour Name 		*data = A_TARGET_READ(scn, address);
313*5113495bSYour Name 		if (Q_TARGET_ACCESS_END(scn) < 0)
314*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
315*5113495bSYour Name 
316*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
317*5113495bSYour Name 	}
318*5113495bSYour Name }
319*5113495bSYour Name 
320*5113495bSYour Name /**
321*5113495bSYour Name  * hif_diag_write_mem() - write data into the soc memory
322*5113495bSYour Name  * @hif_ctx: hif context
323*5113495bSYour Name  * @address: soc virtual address
324*5113495bSYour Name  * @data: data to copy into the soc address
325*5113495bSYour Name  * @nbytes: number of bytes to copy
326*5113495bSYour Name  */
hif_diag_write_mem(struct hif_opaque_softc * hif_ctx,uint32_t address,uint8_t * data,int nbytes)327*5113495bSYour Name QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *hif_ctx,
328*5113495bSYour Name 			      uint32_t address, uint8_t *data, int nbytes)
329*5113495bSYour Name {
330*5113495bSYour Name 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
331*5113495bSYour Name 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
332*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
333*5113495bSYour Name 	qdf_dma_addr_t buf;
334*5113495bSYour Name 	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
335*5113495bSYour Name 	unsigned int id;
336*5113495bSYour Name 	unsigned int flags;
337*5113495bSYour Name 	struct CE_handle *ce_diag;
338*5113495bSYour Name 	void *data_buf = NULL;
339*5113495bSYour Name 	qdf_dma_addr_t CE_data;      /* Host buffer address in CE space */
340*5113495bSYour Name 	qdf_dma_addr_t CE_data_base = 0;
341*5113495bSYour Name 	int i;
342*5113495bSYour Name 	unsigned int mux_id = 0;
343*5113495bSYour Name 	unsigned int transaction_id = 0xffff;
344*5113495bSYour Name 	qdf_dma_addr_t ce_phy_addr = address;
345*5113495bSYour Name 	unsigned int toeplitz_hash_result;
346*5113495bSYour Name 	unsigned int user_flags = 0;
347*5113495bSYour Name 	unsigned int target_type = 0;
348*5113495bSYour Name 
349*5113495bSYour Name 	ce_diag = hif_state->ce_diag;
350*5113495bSYour Name 	if (!ce_diag) {
351*5113495bSYour Name 		hif_err("DIAG CE not present");
352*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
353*5113495bSYour Name 	}
354*5113495bSYour Name 	/* not supporting diag ce on srng based systems, therefore we know this
355*5113495bSYour Name 	 * isn't an srng based system */
356*5113495bSYour Name 
357*5113495bSYour Name 	transaction_id = (mux_id & MUX_ID_MASK) |
358*5113495bSYour Name 		(transaction_id & TRANSACTION_ID_MASK);
359*5113495bSYour Name #ifdef QCA_WIFI_3_0
360*5113495bSYour Name 	user_flags &= DESC_DATA_FLAG_MASK;
361*5113495bSYour Name #endif
362*5113495bSYour Name 
363*5113495bSYour Name 	A_TARGET_ACCESS_LIKELY(scn);
364*5113495bSYour Name 
365*5113495bSYour Name 	/*
366*5113495bSYour Name 	 * Allocate a temporary bounce buffer to hold caller's data
367*5113495bSYour Name 	 * to be DMA'ed to Target. This guarantees
368*5113495bSYour Name 	 *   1) 4-byte alignment
369*5113495bSYour Name 	 *   2) Buffer in DMA-able space
370*5113495bSYour Name 	 */
371*5113495bSYour Name 	orig_nbytes = nbytes;
372*5113495bSYour Name 	data_buf = qdf_mem_alloc_consistent(scn->qdf_dev, scn->qdf_dev->dev,
373*5113495bSYour Name 				    orig_nbytes, &CE_data_base);
374*5113495bSYour Name 	if (!data_buf) {
375*5113495bSYour Name 		status = QDF_STATUS_E_NOMEM;
376*5113495bSYour Name 		goto done;
377*5113495bSYour Name 	}
378*5113495bSYour Name 
379*5113495bSYour Name 	/* Copy caller's data to allocated DMA buf */
380*5113495bSYour Name 	qdf_mem_copy(data_buf, data, orig_nbytes);
381*5113495bSYour Name 	qdf_mem_dma_sync_single_for_device(scn->qdf_dev, CE_data_base,
382*5113495bSYour Name 				       orig_nbytes, DMA_TO_DEVICE);
383*5113495bSYour Name 
384*5113495bSYour Name 	target_type = (hif_get_target_info_handle(hif_ctx))->target_type;
385*5113495bSYour Name 
386*5113495bSYour Name 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0) {
387*5113495bSYour Name 		status = QDF_STATUS_E_FAILURE;
388*5113495bSYour Name 		goto done;
389*5113495bSYour Name 	}
390*5113495bSYour Name 
391*5113495bSYour Name 	/* convert soc virtual address to physical address */
392*5113495bSYour Name 	ce_phy_addr = get_ce_phy_addr(scn, address, target_type);
393*5113495bSYour Name 
394*5113495bSYour Name 	if (Q_TARGET_ACCESS_END(scn) < 0) {
395*5113495bSYour Name 		status = QDF_STATUS_E_FAILURE;
396*5113495bSYour Name 		goto done;
397*5113495bSYour Name 	}
398*5113495bSYour Name 
399*5113495bSYour Name 	remaining_bytes = orig_nbytes;
400*5113495bSYour Name 	CE_data = CE_data_base;
401*5113495bSYour Name 	while (remaining_bytes) {
402*5113495bSYour Name 		nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT);
403*5113495bSYour Name 
404*5113495bSYour Name 		/* Set up to receive directly into Target(!) address */
405*5113495bSYour Name 		status = ce_recv_buf_enqueue(ce_diag, NULL, ce_phy_addr);
406*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
407*5113495bSYour Name 			goto done;
408*5113495bSYour Name 
409*5113495bSYour Name 		/*
410*5113495bSYour Name 		 * Request CE to send caller-supplied data that
411*5113495bSYour Name 		 * was copied to bounce buffer to Target(!) address.
412*5113495bSYour Name 		 */
413*5113495bSYour Name 		status = ce_send(ce_diag, NULL, (qdf_dma_addr_t) CE_data,
414*5113495bSYour Name 				 nbytes, transaction_id, 0, user_flags);
415*5113495bSYour Name 
416*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
417*5113495bSYour Name 			goto done;
418*5113495bSYour Name 
419*5113495bSYour Name 		/* poll for transfer complete */
420*5113495bSYour Name 		i = 0;
421*5113495bSYour Name 		while (ce_completed_send_next(ce_diag, NULL, NULL, &buf,
422*5113495bSYour Name 			    &completed_nbytes, &id,
423*5113495bSYour Name 			    NULL, NULL, &toeplitz_hash_result) !=
424*5113495bSYour Name 			    QDF_STATUS_SUCCESS) {
425*5113495bSYour Name 			qdf_mdelay(1);
426*5113495bSYour Name 			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
427*5113495bSYour Name 				status = QDF_STATUS_E_BUSY;
428*5113495bSYour Name 				goto done;
429*5113495bSYour Name 			}
430*5113495bSYour Name 		}
431*5113495bSYour Name 
432*5113495bSYour Name 		if (nbytes != completed_nbytes) {
433*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
434*5113495bSYour Name 			goto done;
435*5113495bSYour Name 		}
436*5113495bSYour Name 
437*5113495bSYour Name 		if (buf != CE_data) {
438*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
439*5113495bSYour Name 			goto done;
440*5113495bSYour Name 		}
441*5113495bSYour Name 
442*5113495bSYour Name 		i = 0;
443*5113495bSYour Name 		while (ce_completed_recv_next
444*5113495bSYour Name 			(ce_diag, NULL, NULL, &buf,
445*5113495bSYour Name 			&completed_nbytes, &id,
446*5113495bSYour Name 			&flags) != QDF_STATUS_SUCCESS) {
447*5113495bSYour Name 			qdf_mdelay(1);
448*5113495bSYour Name 			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
449*5113495bSYour Name 				status = QDF_STATUS_E_BUSY;
450*5113495bSYour Name 				goto done;
451*5113495bSYour Name 			}
452*5113495bSYour Name 		}
453*5113495bSYour Name 
454*5113495bSYour Name 		if (nbytes != completed_nbytes) {
455*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
456*5113495bSYour Name 			goto done;
457*5113495bSYour Name 		}
458*5113495bSYour Name 
459*5113495bSYour Name 		if (buf != ce_phy_addr) {
460*5113495bSYour Name 			status = QDF_STATUS_E_FAILURE;
461*5113495bSYour Name 			goto done;
462*5113495bSYour Name 		}
463*5113495bSYour Name 
464*5113495bSYour Name 		remaining_bytes -= nbytes;
465*5113495bSYour Name 		address += nbytes;
466*5113495bSYour Name 		CE_data += nbytes;
467*5113495bSYour Name 	}
468*5113495bSYour Name 
469*5113495bSYour Name done:
470*5113495bSYour Name 	A_TARGET_ACCESS_UNLIKELY(scn);
471*5113495bSYour Name 
472*5113495bSYour Name 	if (data_buf) {
473*5113495bSYour Name 		qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev,
474*5113495bSYour Name 				orig_nbytes, data_buf, CE_data_base, 0);
475*5113495bSYour Name 	}
476*5113495bSYour Name 
477*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
478*5113495bSYour Name 		hif_err("Failure (0x%llx)", (uint64_t)ce_phy_addr);
479*5113495bSYour Name 	}
480*5113495bSYour Name 
481*5113495bSYour Name 	return status;
482*5113495bSYour Name }
483*5113495bSYour Name 
484*5113495bSYour Name /* Write 4B data to Target memory or register */
hif_diag_write_access(struct hif_opaque_softc * hif_ctx,uint32_t address,uint32_t data)485*5113495bSYour Name QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *hif_ctx,
486*5113495bSYour Name 				 uint32_t address, uint32_t data)
487*5113495bSYour Name {
488*5113495bSYour Name 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
489*5113495bSYour Name 
490*5113495bSYour Name 	if (address >= DRAM_BASE_ADDRESS) {
491*5113495bSYour Name 		/* Assume range doesn't cross this boundary */
492*5113495bSYour Name 		uint32_t data_buf = data;
493*5113495bSYour Name 
494*5113495bSYour Name 		return hif_diag_write_mem(hif_ctx, address,
495*5113495bSYour Name 					  (uint8_t *) &data_buf,
496*5113495bSYour Name 					  sizeof(uint32_t));
497*5113495bSYour Name 	} else {
498*5113495bSYour Name 		if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
499*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
500*5113495bSYour Name 		A_TARGET_WRITE(scn, address, data);
501*5113495bSYour Name 		if (Q_TARGET_ACCESS_END(scn) < 0)
502*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
503*5113495bSYour Name 
504*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
505*5113495bSYour Name 	}
506*5113495bSYour Name }
507