blob: de32d0b924b7f3c22bcd6227da0f0302f5d7d82f [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Komal Seelam02cf2f82016-02-22 20:44:25 +05302 * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
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 <osdep.h>
29#include "a_types.h"
30#include "athdefs.h"
31#include "osapi_linux.h"
32#include "targcfg.h"
33#include "cdf_lock.h"
34#include "cdf_status.h"
35#include <cdf_atomic.h> /* cdf_atomic_read */
36#include <targaddrs.h>
37#include <bmi_msg.h>
38#include "hif_io32.h"
39#include <hif.h>
40#include <htc_services.h>
41#include "regtable.h"
42#include <a_debug.h>
43#include "hif_main.h"
44#include "ce_api.h"
45#include "cdf_trace.h"
46#include "cds_api.h"
47#ifdef CONFIG_CNSS
48#include <net/cnss.h>
49#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080050#include "hif_debug.h"
51#include "epping_main.h"
Chandrasekaran, Manishekar0d814c72015-11-05 10:42:48 +053052#include "cds_concurrency.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053
Komal Seelam5584a7c2016-02-24 19:22:48 +053054void
55hif_dump_target_memory(struct hif_opaque_softc *hif_ctx, void *ramdump_base,
56 uint32_t address, uint32_t size)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080057{
Komal Seelam644263d2016-02-22 20:45:49 +053058 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059 uint32_t loc = address;
60 uint32_t val = 0;
61 uint32_t j = 0;
62 u8 *temp = ramdump_base;
63
64 A_TARGET_ACCESS_BEGIN(scn);
65 while (j < size) {
66 val = hif_read32_mb(scn->mem + loc + j);
67 cdf_mem_copy(temp, &val, 4);
68 j += 4;
69 temp += 4;
70 }
71 A_TARGET_ACCESS_END(scn);
72}
73/*
74 * TBDXXX: Should be a function call specific to each Target-type.
75 * This convoluted macro converts from Target CPU Virtual Address
76 * Space to CE Address Space. As part of this process, we
77 * conservatively fetch the current PCIE_BAR. MOST of the time,
78 * this should match the upper bits of PCI space for this device;
79 * but that's not guaranteed.
80 */
81#ifdef QCA_WIFI_3_0
82#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \
83 (scn->mem_pa + addr)
84#else
85#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \
86 (((hif_read32_mb((pci_addr) + \
87 (SOC_CORE_BASE_ADDRESS|CORE_CTRL_ADDRESS)) & 0x7ff) << 21) \
88 | 0x100000 | ((addr) & 0xfffff))
89#endif
90/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
91#define DIAG_ACCESS_CE_TIMEOUT_MS 10
92
93/*
94 * Diagnostic read/write access is provided for startup/config/debug usage.
95 * Caller must guarantee proper alignment, when applicable, and single user
96 * at any moment.
97 */
98
99CDF_STATUS
Komal Seelam5584a7c2016-02-24 19:22:48 +0530100hif_diag_read_mem(struct hif_opaque_softc *hif_ctx, uint32_t address,
101 uint8_t *data, int nbytes)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800102{
Komal Seelam644263d2016-02-22 20:45:49 +0530103 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Komal Seelam02cf2f82016-02-22 20:44:25 +0530104 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800105 CDF_STATUS status = CDF_STATUS_SUCCESS;
106 cdf_dma_addr_t buf;
107 unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
108 unsigned int id;
109 unsigned int flags;
110 struct CE_handle *ce_diag;
111 cdf_dma_addr_t CE_data; /* Host buffer address in CE space */
112 cdf_dma_addr_t CE_data_base = 0;
113 void *data_buf = NULL;
114 int i;
115 unsigned int mux_id = 0;
116 unsigned int transaction_id = 0xffff;
117 cdf_dma_addr_t ce_phy_addr = address;
118 unsigned int toeplitz_hash_result;
119 unsigned int user_flags = 0;
120
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800121 transaction_id = (mux_id & MUX_ID_MASK) |
122 (transaction_id & TRANSACTION_ID_MASK);
123#ifdef QCA_WIFI_3_0
124 user_flags &= DESC_DATA_FLAG_MASK;
125#endif
126
127 /* This code cannot handle reads to non-memory space. Redirect to the
128 * register read fn but preserve the multi word read capability of
129 * this fn
130 */
131 if (address < DRAM_BASE_ADDRESS) {
132
133 if ((address & 0x3) || ((uintptr_t) data & 0x3))
134 return CDF_STATUS_E_INVAL;
135
136 while ((nbytes >= 4) &&
137 (CDF_STATUS_SUCCESS == (status =
Komal Seelam644263d2016-02-22 20:45:49 +0530138 hif_diag_read_access(hif_ctx, address,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800139 (uint32_t *)data)))) {
140
141 nbytes -= sizeof(uint32_t);
142 address += sizeof(uint32_t);
143 data += sizeof(uint32_t);
144
145 }
146
147 return status;
148 }
149 ce_diag = hif_state->ce_diag;
150
151 A_TARGET_ACCESS_LIKELY(scn);
152
153 /*
154 * Allocate a temporary bounce buffer to hold caller's data
155 * to be DMA'ed from Target. This guarantees
156 * 1) 4-byte alignment
157 * 2) Buffer in DMA-able space
158 */
159 orig_nbytes = nbytes;
160 data_buf = cdf_os_mem_alloc_consistent(scn->cdf_dev,
161 orig_nbytes, &CE_data_base, 0);
162 if (!data_buf) {
163 status = CDF_STATUS_E_NOMEM;
164 goto done;
165 }
166 cdf_mem_set(data_buf, orig_nbytes, 0);
167 cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_data_base,
168 orig_nbytes, DMA_FROM_DEVICE);
169
170 remaining_bytes = orig_nbytes;
171 CE_data = CE_data_base;
172 while (remaining_bytes) {
173 nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT);
174 {
175 status = ce_recv_buf_enqueue(ce_diag, NULL, CE_data);
176 if (status != CDF_STATUS_SUCCESS)
177 goto done;
178 }
179
180 { /* Request CE to send from Target(!)
181 * address to Host buffer */
182 /*
183 * The address supplied by the caller is in the
184 * Target CPU virtual address space.
185 *
186 * In order to use this address with the diagnostic CE,
187 * convert it from
188 * Target CPU virtual address space
189 * to
190 * CE address space
191 */
192 A_TARGET_ACCESS_BEGIN_RET(scn);
193 ce_phy_addr =
194 TARG_CPU_SPACE_TO_CE_SPACE(scn->mem, address);
195 A_TARGET_ACCESS_END_RET(scn);
196
197 status =
198 ce_send(ce_diag, NULL, ce_phy_addr, nbytes,
199 transaction_id, 0, user_flags);
200 if (status != CDF_STATUS_SUCCESS)
201 goto done;
202 }
203
204 i = 0;
205 while (ce_completed_send_next(ce_diag, NULL, NULL, &buf,
206 &completed_nbytes, &id, NULL, NULL,
207 &toeplitz_hash_result) != CDF_STATUS_SUCCESS) {
208 cdf_mdelay(1);
209 if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
210 status = CDF_STATUS_E_BUSY;
211 goto done;
212 }
213 }
214 if (nbytes != completed_nbytes) {
215 status = CDF_STATUS_E_FAILURE;
216 goto done;
217 }
218 if (buf != ce_phy_addr) {
219 status = CDF_STATUS_E_FAILURE;
220 goto done;
221 }
222
223 i = 0;
224 while (ce_completed_recv_next
225 (ce_diag, NULL, NULL, &buf,
226 &completed_nbytes, &id,
227 &flags) != CDF_STATUS_SUCCESS) {
228 cdf_mdelay(1);
229 if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
230 status = CDF_STATUS_E_BUSY;
231 goto done;
232 }
233 }
234 if (nbytes != completed_nbytes) {
235 status = CDF_STATUS_E_FAILURE;
236 goto done;
237 }
238 if (buf != CE_data) {
239 status = CDF_STATUS_E_FAILURE;
240 goto done;
241 }
242
243 remaining_bytes -= nbytes;
244 address += nbytes;
245 CE_data += nbytes;
246 }
247
248done:
249 A_TARGET_ACCESS_UNLIKELY(scn);
250
251 if (status == CDF_STATUS_SUCCESS)
252 cdf_mem_copy(data, data_buf, orig_nbytes);
253 else
254 HIF_ERROR("%s failure (0x%x)", __func__, address);
255
256 if (data_buf)
257 cdf_os_mem_free_consistent(scn->cdf_dev, orig_nbytes,
258 data_buf, CE_data_base, 0);
259
260 return status;
261}
262
263/* Read 4-byte aligned data from Target memory or register */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530264CDF_STATUS hif_diag_read_access(struct hif_opaque_softc *hif_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800265 uint32_t address, uint32_t *data)
266{
Komal Seelam644263d2016-02-22 20:45:49 +0530267 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800268
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800269 if (address >= DRAM_BASE_ADDRESS) {
270 /* Assume range doesn't cross this boundary */
Komal Seelam644263d2016-02-22 20:45:49 +0530271 return hif_diag_read_mem(hif_ctx, address, (uint8_t *) data,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800272 sizeof(uint32_t));
273 } else {
274 A_TARGET_ACCESS_BEGIN_RET(scn);
275 *data = A_TARGET_READ(scn, address);
276 A_TARGET_ACCESS_END_RET(scn);
277
278 return CDF_STATUS_SUCCESS;
279 }
280}
281
Komal Seelam5584a7c2016-02-24 19:22:48 +0530282CDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *hif_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800283 uint32_t address, uint8_t *data, int nbytes)
284{
Komal Seelam644263d2016-02-22 20:45:49 +0530285 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Komal Seelam02cf2f82016-02-22 20:44:25 +0530286 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800287 CDF_STATUS status = CDF_STATUS_SUCCESS;
288 cdf_dma_addr_t buf;
289 unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
290 unsigned int id;
291 unsigned int flags;
292 struct CE_handle *ce_diag;
293 void *data_buf = NULL;
294 cdf_dma_addr_t CE_data; /* Host buffer address in CE space */
295 cdf_dma_addr_t CE_data_base = 0;
296 int i;
297 unsigned int mux_id = 0;
298 unsigned int transaction_id = 0xffff;
299 cdf_dma_addr_t ce_phy_addr = address;
300 unsigned int toeplitz_hash_result;
301 unsigned int user_flags = 0;
302
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800303 ce_diag = hif_state->ce_diag;
304 transaction_id = (mux_id & MUX_ID_MASK) |
305 (transaction_id & TRANSACTION_ID_MASK);
306#ifdef QCA_WIFI_3_0
307 user_flags &= DESC_DATA_FLAG_MASK;
308#endif
309
310 A_TARGET_ACCESS_LIKELY(scn);
311
312 /*
313 * Allocate a temporary bounce buffer to hold caller's data
314 * to be DMA'ed to Target. This guarantees
315 * 1) 4-byte alignment
316 * 2) Buffer in DMA-able space
317 */
318 orig_nbytes = nbytes;
319 data_buf = cdf_os_mem_alloc_consistent(scn->cdf_dev,
320 orig_nbytes, &CE_data_base, 0);
321 if (!data_buf) {
322 status = A_NO_MEMORY;
323 goto done;
324 }
325
326 /* Copy caller's data to allocated DMA buf */
327 cdf_mem_copy(data_buf, data, orig_nbytes);
328 cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_data_base,
329 orig_nbytes, DMA_TO_DEVICE);
330
331 /*
332 * The address supplied by the caller is in the
333 * Target CPU virtual address space.
334 *
335 * In order to use this address with the diagnostic CE,
336 * convert it from
337 * Target CPU virtual address space
338 * to
339 * CE address space
340 */
341 A_TARGET_ACCESS_BEGIN_RET(scn);
342 ce_phy_addr = TARG_CPU_SPACE_TO_CE_SPACE(scn->mem, address);
343 A_TARGET_ACCESS_END_RET(scn);
344
345 remaining_bytes = orig_nbytes;
346 CE_data = CE_data_base;
347 while (remaining_bytes) {
348 nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT);
349
350 { /* Set up to receive directly into Target(!) address */
351 status = ce_recv_buf_enqueue(ce_diag,
352 NULL, ce_phy_addr);
353 if (status != CDF_STATUS_SUCCESS)
354 goto done;
355 }
356
357 {
358 /*
359 * Request CE to send caller-supplied data that
360 * was copied to bounce buffer to Target(!) address.
361 */
362 status =
363 ce_send(ce_diag, NULL,
364 (cdf_dma_addr_t) CE_data, nbytes,
365 transaction_id, 0, user_flags);
366 if (status != CDF_STATUS_SUCCESS)
367 goto done;
368 }
369
370 i = 0;
371 while (ce_completed_send_next(ce_diag, NULL, NULL, &buf,
372 &completed_nbytes, &id,
373 NULL, NULL, &toeplitz_hash_result) !=
374 CDF_STATUS_SUCCESS) {
375 cdf_mdelay(1);
376 if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
377 status = CDF_STATUS_E_BUSY;
378 goto done;
379 }
380 }
381
382 if (nbytes != completed_nbytes) {
383 status = CDF_STATUS_E_FAILURE;
384 goto done;
385 }
386
387 if (buf != CE_data) {
388 status = CDF_STATUS_E_FAILURE;
389 goto done;
390 }
391
392 i = 0;
393 while (ce_completed_recv_next
394 (ce_diag, NULL, NULL, &buf,
395 &completed_nbytes, &id,
396 &flags) != CDF_STATUS_SUCCESS) {
397 cdf_mdelay(1);
398 if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
399 status = CDF_STATUS_E_BUSY;
400 goto done;
401 }
402 }
403
404 if (nbytes != completed_nbytes) {
405 status = CDF_STATUS_E_FAILURE;
406 goto done;
407 }
408
409 if (buf != ce_phy_addr) {
410 status = CDF_STATUS_E_FAILURE;
411 goto done;
412 }
413
414 remaining_bytes -= nbytes;
415 address += nbytes;
416 CE_data += nbytes;
417 }
418
419done:
420 A_TARGET_ACCESS_UNLIKELY(scn);
421
422 if (data_buf) {
423 cdf_os_mem_free_consistent(scn->cdf_dev, orig_nbytes,
424 data_buf, CE_data_base, 0);
425 }
426
427 if (status != CDF_STATUS_SUCCESS) {
428 HIF_ERROR("%s failure (0x%llu)", __func__,
429 (uint64_t)ce_phy_addr);
430 }
431
432 return status;
433}
434
435/* Write 4B data to Target memory or register */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530436CDF_STATUS hif_diag_write_access(struct hif_opaque_softc *hif_ctx,
437 uint32_t address, uint32_t data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800438{
Komal Seelam644263d2016-02-22 20:45:49 +0530439 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800440
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800441 if (address >= DRAM_BASE_ADDRESS) {
442 /* Assume range doesn't cross this boundary */
443 uint32_t data_buf = data;
444
Komal Seelam644263d2016-02-22 20:45:49 +0530445 return hif_diag_write_mem(hif_ctx, address,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800446 (uint8_t *) &data_buf,
447 sizeof(uint32_t));
448 } else {
449 A_TARGET_ACCESS_BEGIN_RET(scn);
450 A_TARGET_WRITE(scn, address, data);
451 A_TARGET_ACCESS_END_RET(scn);
452
453 return CDF_STATUS_SUCCESS;
454 }
455}