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