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