xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/ce/ce_diag.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2015-2018 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->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(pci_addr, addr) \
67 	(scn->mem_pa + addr)
68 #else
69 #define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \
70 	(((hif_read32_mb((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(pci_addr, addr) \
76 	(hif_read32_mb((pci_addr)+(WIFICMN_PCIE_BAR_REG_ADDRESS)) \
77 	| ((addr) & 0xfffff))
78 
79 #define TARG_CPU_SPACE_TO_CE_SPACE_AR900B(pci_addr, addr) \
80 	(hif_read32_mb((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 =
117 			TARG_CPU_SPACE_TO_CE_SPACE_IPQ4019(sc->mem, 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->mem, address);
124 	} else {
125 		ce_phy_addr =
126 		    TARG_CPU_SPACE_TO_CE_SPACE(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 == NULL) {
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_set(data_buf, orig_nbytes, 0);
227 	qdf_mem_dma_sync_single_for_device(scn->qdf_dev, CE_data_base,
228 				       orig_nbytes, DMA_FROM_DEVICE);
229 
230 	remaining_bytes = orig_nbytes;
231 	CE_data = CE_data_base;
232 	while (remaining_bytes) {
233 		nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT);
234 		{
235 			status = ce_recv_buf_enqueue(ce_diag, NULL, CE_data);
236 			if (status != QDF_STATUS_SUCCESS)
237 				goto done;
238 		}
239 
240 		if (Q_TARGET_ACCESS_BEGIN(scn) < 0) {
241 			status = QDF_STATUS_E_FAILURE;
242 			goto done;
243 		}
244 
245 		/* convert soc virtual address to physical address */
246 		ce_phy_addr = get_ce_phy_addr(scn, address, target_type);
247 
248 		if (Q_TARGET_ACCESS_END(scn) < 0) {
249 			status = QDF_STATUS_E_FAILURE;
250 			goto done;
251 		}
252 
253 		/* Request CE to send from Target(!)
254 		 * address to Host buffer
255 		 */
256 		status = ce_send(ce_diag, NULL, ce_phy_addr, nbytes,
257 				transaction_id, 0, user_flags);
258 		if (status != QDF_STATUS_SUCCESS)
259 			goto done;
260 
261 		i = 0;
262 		while (ce_completed_send_next(ce_diag, NULL, NULL, &buf,
263 				&completed_nbytes, &id, NULL, NULL,
264 				&toeplitz_hash_result) != QDF_STATUS_SUCCESS) {
265 			qdf_mdelay(1);
266 			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
267 				status = QDF_STATUS_E_BUSY;
268 				goto done;
269 			}
270 		}
271 		if (nbytes != completed_nbytes) {
272 			status = QDF_STATUS_E_FAILURE;
273 			goto done;
274 		}
275 		if (buf != ce_phy_addr) {
276 			status = QDF_STATUS_E_FAILURE;
277 			goto done;
278 		}
279 
280 		i = 0;
281 		while (ce_completed_recv_next
282 				(ce_diag, NULL, NULL, &buf,
283 				&completed_nbytes, &id,
284 				 &flags) != QDF_STATUS_SUCCESS) {
285 			qdf_mdelay(1);
286 			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
287 				status = QDF_STATUS_E_BUSY;
288 				goto done;
289 			}
290 		}
291 		if (nbytes != completed_nbytes) {
292 			status = QDF_STATUS_E_FAILURE;
293 			goto done;
294 		}
295 		if (buf != CE_data) {
296 			status = QDF_STATUS_E_FAILURE;
297 			goto done;
298 		}
299 
300 		remaining_bytes -= nbytes;
301 		address += nbytes;
302 		CE_data += nbytes;
303 	}
304 
305 done:
306 	A_TARGET_ACCESS_UNLIKELY(scn);
307 
308 	if (status == QDF_STATUS_SUCCESS)
309 		qdf_mem_copy(data, data_buf, orig_nbytes);
310 	else
311 		HIF_ERROR("%s failure (0x%x)", __func__, address);
312 
313 	if (data_buf)
314 		qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev,
315 				orig_nbytes, data_buf, CE_data_base, 0);
316 
317 	return status;
318 }
319 qdf_export_symbol(hif_diag_read_mem);
320 
321 /* Read 4-byte aligned data from Target memory or register */
322 QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *hif_ctx,
323 				uint32_t address, uint32_t *data)
324 {
325 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
326 
327 	if (address >= DRAM_BASE_ADDRESS) {
328 		/* Assume range doesn't cross this boundary */
329 		return hif_diag_read_mem(hif_ctx, address, (uint8_t *) data,
330 					 sizeof(uint32_t));
331 	} else {
332 		if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
333 			return QDF_STATUS_E_FAILURE;
334 		*data = A_TARGET_READ(scn, address);
335 		if (Q_TARGET_ACCESS_END(scn) < 0)
336 			return QDF_STATUS_E_FAILURE;
337 
338 		return QDF_STATUS_SUCCESS;
339 	}
340 }
341 
342 /**
343  * hif_diag_write_mem() - write data into the soc memory
344  * @hif_ctx: hif context
345  * @address: soc virtual address
346  * @data: data to copy into the soc address
347  * @nbytes: number of bytes to coppy
348  */
349 QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *hif_ctx,
350 			      uint32_t address, uint8_t *data, int nbytes)
351 {
352 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
353 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
354 	QDF_STATUS status = QDF_STATUS_SUCCESS;
355 	qdf_dma_addr_t buf;
356 	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
357 	unsigned int id;
358 	unsigned int flags;
359 	struct CE_handle *ce_diag;
360 	void *data_buf = NULL;
361 	qdf_dma_addr_t CE_data;      /* Host buffer address in CE space */
362 	qdf_dma_addr_t CE_data_base = 0;
363 	int i;
364 	unsigned int mux_id = 0;
365 	unsigned int transaction_id = 0xffff;
366 	qdf_dma_addr_t ce_phy_addr = address;
367 	unsigned int toeplitz_hash_result;
368 	unsigned int user_flags = 0;
369 	unsigned int target_type = 0;
370 
371 	ce_diag = hif_state->ce_diag;
372 	if (ce_diag == NULL) {
373 		HIF_ERROR("%s: DIAG CE not present", __func__);
374 		return QDF_STATUS_E_INVAL;
375 	}
376 	/* not supporting diag ce on srng based systems, therefore we know this
377 	 * isn't an srng based system */
378 
379 	transaction_id = (mux_id & MUX_ID_MASK) |
380 		(transaction_id & TRANSACTION_ID_MASK);
381 #ifdef QCA_WIFI_3_0
382 	user_flags &= DESC_DATA_FLAG_MASK;
383 #endif
384 
385 	A_TARGET_ACCESS_LIKELY(scn);
386 
387 	/*
388 	 * Allocate a temporary bounce buffer to hold caller's data
389 	 * to be DMA'ed to Target. This guarantees
390 	 *   1) 4-byte alignment
391 	 *   2) Buffer in DMA-able space
392 	 */
393 	orig_nbytes = nbytes;
394 	data_buf = qdf_mem_alloc_consistent(scn->qdf_dev, scn->qdf_dev->dev,
395 				    orig_nbytes, &CE_data_base);
396 	if (!data_buf) {
397 		status = QDF_STATUS_E_NOMEM;
398 		goto done;
399 	}
400 
401 	/* Copy caller's data to allocated DMA buf */
402 	qdf_mem_copy(data_buf, data, orig_nbytes);
403 	qdf_mem_dma_sync_single_for_device(scn->qdf_dev, CE_data_base,
404 				       orig_nbytes, DMA_TO_DEVICE);
405 
406 	target_type = (hif_get_target_info_handle(hif_ctx))->target_type;
407 
408 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0) {
409 		status = QDF_STATUS_E_FAILURE;
410 		goto done;
411 	}
412 
413 	/* convert soc virtual address to physical address */
414 	ce_phy_addr = get_ce_phy_addr(scn, address, target_type);
415 
416 	if (Q_TARGET_ACCESS_END(scn) < 0) {
417 		status = QDF_STATUS_E_FAILURE;
418 		goto done;
419 	}
420 
421 	remaining_bytes = orig_nbytes;
422 	CE_data = CE_data_base;
423 	while (remaining_bytes) {
424 		nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT);
425 
426 		/* Set up to receive directly into Target(!) address */
427 		status = ce_recv_buf_enqueue(ce_diag, NULL, ce_phy_addr);
428 		if (status != QDF_STATUS_SUCCESS)
429 			goto done;
430 
431 		/*
432 		 * Request CE to send caller-supplied data that
433 		 * was copied to bounce buffer to Target(!) address.
434 		 */
435 		status = ce_send(ce_diag, NULL, (qdf_dma_addr_t) CE_data,
436 				 nbytes, transaction_id, 0, user_flags);
437 
438 		if (status != QDF_STATUS_SUCCESS)
439 			goto done;
440 
441 		/* poll for transfer complete */
442 		i = 0;
443 		while (ce_completed_send_next(ce_diag, NULL, NULL, &buf,
444 			    &completed_nbytes, &id,
445 			    NULL, NULL, &toeplitz_hash_result) !=
446 			    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_data) {
460 			status = QDF_STATUS_E_FAILURE;
461 			goto done;
462 		}
463 
464 		i = 0;
465 		while (ce_completed_recv_next
466 			(ce_diag, NULL, NULL, &buf,
467 			&completed_nbytes, &id,
468 			&flags) != QDF_STATUS_SUCCESS) {
469 			qdf_mdelay(1);
470 			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
471 				status = QDF_STATUS_E_BUSY;
472 				goto done;
473 			}
474 		}
475 
476 		if (nbytes != completed_nbytes) {
477 			status = QDF_STATUS_E_FAILURE;
478 			goto done;
479 		}
480 
481 		if (buf != ce_phy_addr) {
482 			status = QDF_STATUS_E_FAILURE;
483 			goto done;
484 		}
485 
486 		remaining_bytes -= nbytes;
487 		address += nbytes;
488 		CE_data += nbytes;
489 	}
490 
491 done:
492 	A_TARGET_ACCESS_UNLIKELY(scn);
493 
494 	if (data_buf) {
495 		qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev,
496 				orig_nbytes, data_buf, CE_data_base, 0);
497 	}
498 
499 	if (status != QDF_STATUS_SUCCESS) {
500 		HIF_ERROR("%s failure (0x%llx)", __func__,
501 			(uint64_t)ce_phy_addr);
502 	}
503 
504 	return status;
505 }
506 
507 /* Write 4B data to Target memory or register */
508 QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *hif_ctx,
509 				 uint32_t address, uint32_t data)
510 {
511 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
512 
513 	if (address >= DRAM_BASE_ADDRESS) {
514 		/* Assume range doesn't cross this boundary */
515 		uint32_t data_buf = data;
516 
517 		return hif_diag_write_mem(hif_ctx, address,
518 					  (uint8_t *) &data_buf,
519 					  sizeof(uint32_t));
520 	} else {
521 		if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
522 			return QDF_STATUS_E_FAILURE;
523 		A_TARGET_WRITE(scn, address, data);
524 		if (Q_TARGET_ACCESS_END(scn) < 0)
525 			return QDF_STATUS_E_FAILURE;
526 
527 		return QDF_STATUS_SUCCESS;
528 	}
529 }
530