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