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