blob: c078f218b01a43e295ccbe90bc9a4254bb684fcc [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2015 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 <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
50#include <cds_get_bin.h>
51#include "hif_debug.h"
52#include "epping_main.h"
53
54void hif_dump_target_memory(struct ol_softc *scn, void *ramdump_base,
55 uint32_t address, uint32_t size)
56{
57 uint32_t loc = address;
58 uint32_t val = 0;
59 uint32_t j = 0;
60 u8 *temp = ramdump_base;
61
62 A_TARGET_ACCESS_BEGIN(scn);
63 while (j < size) {
64 val = hif_read32_mb(scn->mem + loc + j);
65 cdf_mem_copy(temp, &val, 4);
66 j += 4;
67 temp += 4;
68 }
69 A_TARGET_ACCESS_END(scn);
70}
71/*
72 * TBDXXX: Should be a function call specific to each Target-type.
73 * This convoluted macro converts from Target CPU Virtual Address
74 * Space to CE Address Space. As part of this process, we
75 * conservatively fetch the current PCIE_BAR. MOST of the time,
76 * this should match the upper bits of PCI space for this device;
77 * but that's not guaranteed.
78 */
79#ifdef QCA_WIFI_3_0
80#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \
81 (scn->mem_pa + addr)
82#else
83#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \
84 (((hif_read32_mb((pci_addr) + \
85 (SOC_CORE_BASE_ADDRESS|CORE_CTRL_ADDRESS)) & 0x7ff) << 21) \
86 | 0x100000 | ((addr) & 0xfffff))
87#endif
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 * Diagnostic read/write access is provided for startup/config/debug usage.
93 * Caller must guarantee proper alignment, when applicable, and single user
94 * at any moment.
95 */
96
97CDF_STATUS
98hif_diag_read_mem(struct ol_softc *scn, uint32_t address, uint8_t *data,
99 int nbytes)
100{
101 struct HIF_CE_state *hif_state;
102 CDF_STATUS status = CDF_STATUS_SUCCESS;
103 cdf_dma_addr_t buf;
104 unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
105 unsigned int id;
106 unsigned int flags;
107 struct CE_handle *ce_diag;
108 cdf_dma_addr_t CE_data; /* Host buffer address in CE space */
109 cdf_dma_addr_t CE_data_base = 0;
110 void *data_buf = NULL;
111 int i;
112 unsigned int mux_id = 0;
113 unsigned int transaction_id = 0xffff;
114 cdf_dma_addr_t ce_phy_addr = address;
115 unsigned int toeplitz_hash_result;
116 unsigned int user_flags = 0;
117
118 hif_state = (struct HIF_CE_state *)scn->hif_hdl;
119
120 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 =
137 hif_diag_read_access(scn, address,
138 (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 */
263CDF_STATUS hif_diag_read_access(struct ol_softc *scn,
264 uint32_t address, uint32_t *data)
265{
266 struct HIF_CE_state *hif_state;
267
268 hif_state = (struct HIF_CE_state *)scn->hif_hdl;
269 if (address >= DRAM_BASE_ADDRESS) {
270 /* Assume range doesn't cross this boundary */
271 return hif_diag_read_mem(scn, address, (uint8_t *) data,
272 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
282CDF_STATUS hif_diag_write_mem(struct ol_softc *scn,
283 uint32_t address, uint8_t *data, int nbytes)
284{
285 struct HIF_CE_state *hif_state;
286 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
302 hif_state = (struct HIF_CE_state *)scn->hif_hdl;
303 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 */
436CDF_STATUS
437hif_diag_write_access(struct ol_softc *scn, uint32_t address, uint32_t data)
438{
439 struct HIF_CE_state *hif_state;
440
441 hif_state = (struct HIF_CE_state *)scn->hif_hdl;
442 if (address >= DRAM_BASE_ADDRESS) {
443 /* Assume range doesn't cross this boundary */
444 uint32_t data_buf = data;
445
446 return hif_diag_write_mem(scn, address,
447 (uint8_t *) &data_buf,
448 sizeof(uint32_t));
449 } else {
450 A_TARGET_ACCESS_BEGIN_RET(scn);
451 A_TARGET_WRITE(scn, address, data);
452 A_TARGET_ACCESS_END_RET(scn);
453
454 return CDF_STATUS_SUCCESS;
455 }
456}