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