Commit | Line | Data |
---|---|---|
635d2b00 GKH |
1 | /***************************************************************************** |
2 | ||
95edd09e | 3 | (c) Cambridge Silicon Radio Limited 2012 |
635d2b00 GKH |
4 | All rights reserved and confidential information of CSR |
5 | ||
6 | Refer to LICENSE.txt included with this source for details | |
7 | on the license terms. | |
8 | ||
9 | *****************************************************************************/ | |
10 | ||
11 | /* | |
12 | * --------------------------------------------------------------------------- | |
13 | * FILE: csr_wifi_hip_card_sdio.c | |
14 | * | |
15 | * PURPOSE: Implementation of the Card API for SDIO. | |
16 | * | |
17 | * NOTES: | |
18 | * CardInit() is called from the SDIO probe callback when a card is | |
19 | * inserted. This performs the basic SDIO initialisation, enabling i/o | |
20 | * etc. | |
21 | * | |
22 | * --------------------------------------------------------------------------- | |
23 | */ | |
4fe9db37 | 24 | #include <linux/slab.h> |
635d2b00 GKH |
25 | #include "csr_wifi_hip_unifi.h" |
26 | #include "csr_wifi_hip_conversions.h" | |
27 | #include "csr_wifi_hip_unifiversion.h" | |
28 | #include "csr_wifi_hip_card.h" | |
29 | #include "csr_wifi_hip_card_sdio.h" | |
30 | #include "csr_wifi_hip_chiphelper.h" | |
31 | ||
32 | ||
33 | /* Time to wait between attempts to read MAILBOX0 */ | |
34 | #define MAILBOX1_TIMEOUT 10 /* in millisecs */ | |
35 | #define MAILBOX1_ATTEMPTS 200 /* 2 seconds */ | |
36 | ||
37 | #define MAILBOX2_TIMEOUT 5 /* in millisecs */ | |
38 | #define MAILBOX2_ATTEMPTS 10 /* 50ms */ | |
39 | ||
635d2b00 GKH |
40 | #define RESET_SETTLE_DELAY 25 /* in millisecs */ |
41 | ||
42 | static CsrResult card_init_slots(card_t *card); | |
43 | static CsrResult card_hw_init(card_t *card); | |
44 | static CsrResult firmware_present_in_flash(card_t *card); | |
45 | static void bootstrap_chip_hw(card_t *card); | |
46 | static CsrResult unifi_reset_hardware(card_t *card); | |
47 | static CsrResult unifi_hip_init(card_t *card); | |
48 | static CsrResult card_access_panic(card_t *card); | |
49 | static CsrResult unifi_read_chip_version(card_t *card); | |
50 | ||
51 | /* | |
52 | * --------------------------------------------------------------------------- | |
53 | * unifi_alloc_card | |
54 | * | |
55 | * Allocate and initialise the card context structure. | |
56 | * | |
57 | * Arguments: | |
58 | * sdio Pointer to SDIO context pointer to pass to low | |
59 | * level i/o functions. | |
60 | * ospriv Pointer to O/S private struct to pass when calling | |
61 | * callbacks to the higher level system. | |
62 | * | |
63 | * Returns: | |
64 | * Pointer to card struct, which represents the driver context or | |
65 | * NULL if the allocation failed. | |
66 | * --------------------------------------------------------------------------- | |
67 | */ | |
68 | card_t* unifi_alloc_card(CsrSdioFunction *sdio, void *ospriv) | |
69 | { | |
70 | card_t *card; | |
26a6b2e1 | 71 | u32 i; |
635d2b00 | 72 | |
635d2b00 | 73 | |
70128792 | 74 | card = kzalloc(sizeof(card_t), GFP_KERNEL); |
635d2b00 GKH |
75 | if (card == NULL) |
76 | { | |
77 | return NULL; | |
78 | } | |
635d2b00 GKH |
79 | |
80 | card->sdio_if = sdio; | |
81 | card->ospriv = ospriv; | |
82 | ||
83 | card->unifi_interrupt_seq = 1; | |
84 | ||
85 | /* Make these invalid. */ | |
26a6b2e1 GKH |
86 | card->proc_select = (u32)(-1); |
87 | card->dmem_page = (u32)(-1); | |
88 | card->pmem_page = (u32)(-1); | |
635d2b00 GKH |
89 | |
90 | card->bh_reason_host = 0; | |
91 | card->bh_reason_unifi = 0; | |
92 | ||
93 | for (i = 0; i < sizeof(card->tx_q_paused_flag) / sizeof(card->tx_q_paused_flag[0]); i++) | |
94 | { | |
95 | card->tx_q_paused_flag[i] = 0; | |
96 | } | |
97 | card->memory_resources_allocated = 0; | |
98 | ||
99 | card->low_power_mode = UNIFI_LOW_POWER_DISABLED; | |
100 | card->periodic_wake_mode = UNIFI_PERIODIC_WAKE_HOST_DISABLED; | |
101 | ||
102 | card->host_state = UNIFI_HOST_STATE_AWAKE; | |
103 | card->intmode = CSR_WIFI_INTMODE_DEFAULT; | |
104 | ||
105 | /* | |
106 | * Memory resources for buffers are allocated when the chip is initialised | |
107 | * because we need configuration information from the firmware. | |
108 | */ | |
109 | ||
110 | /* | |
111 | * Initialise wait queues and lists | |
112 | */ | |
113 | card->fh_command_queue.q_body = card->fh_command_q_body; | |
114 | card->fh_command_queue.q_length = UNIFI_SOFT_COMMAND_Q_LENGTH; | |
115 | ||
116 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) | |
117 | { | |
118 | card->fh_traffic_queue[i].q_body = card->fh_traffic_q_body[i]; | |
119 | card->fh_traffic_queue[i].q_length = UNIFI_SOFT_TRAFFIC_Q_LENGTH; | |
120 | } | |
121 | ||
122 | ||
123 | /* Initialise mini-coredump pointers in case no coredump buffers | |
124 | * are requested by the OS layer. | |
125 | */ | |
126 | card->request_coredump_on_reset = 0; | |
127 | card->dump_next_write = NULL; | |
128 | card->dump_cur_read = NULL; | |
129 | card->dump_buf = NULL; | |
130 | ||
131 | #ifdef UNIFI_DEBUG | |
132 | /* Determine offset of LSB in pointer for later alignment sanity check. | |
133 | * Synergy integer types have specific widths, which cause compiler | |
134 | * warnings when casting pointer types, e.g. on 64-bit systems. | |
135 | */ | |
136 | { | |
26a6b2e1 | 137 | u32 val = 0x01234567; |
635d2b00 | 138 | |
7e6f5794 | 139 | if (*((u8 *)&val) == 0x01) |
635d2b00 GKH |
140 | { |
141 | card->lsb = sizeof(void *) - 1; /* BE */ | |
142 | } | |
143 | else | |
144 | { | |
145 | card->lsb = 0; /* LE */ | |
146 | } | |
147 | } | |
148 | #endif | |
635d2b00 GKH |
149 | return card; |
150 | } /* unifi_alloc_card() */ | |
151 | ||
152 | ||
153 | /* | |
154 | * --------------------------------------------------------------------------- | |
155 | * unifi_init_card | |
156 | * | |
157 | * Reset the hardware and perform HIP initialization | |
158 | * | |
159 | * Arguments: | |
160 | * card Pointer to card struct | |
161 | * | |
162 | * Returns: | |
163 | * CsrResult code | |
164 | * CSR_RESULT_SUCCESS if successful | |
165 | * --------------------------------------------------------------------------- | |
166 | */ | |
95e326c2 | 167 | CsrResult unifi_init_card(card_t *card, s32 led_mask) |
635d2b00 GKH |
168 | { |
169 | CsrResult r; | |
170 | ||
635d2b00 GKH |
171 | |
172 | if (card == NULL) | |
173 | { | |
635d2b00 GKH |
174 | return CSR_WIFI_HIP_RESULT_INVALID_VALUE; |
175 | } | |
176 | ||
177 | r = unifi_init(card); | |
178 | if (r != CSR_RESULT_SUCCESS) | |
179 | { | |
635d2b00 GKH |
180 | return r; |
181 | } | |
182 | ||
183 | r = unifi_hip_init(card); | |
184 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
185 | { | |
635d2b00 GKH |
186 | return r; |
187 | } | |
188 | if (r != CSR_RESULT_SUCCESS) | |
189 | { | |
190 | unifi_error(card->ospriv, "Failed to start host protocol.\n"); | |
635d2b00 GKH |
191 | return r; |
192 | } | |
193 | ||
635d2b00 GKH |
194 | return CSR_RESULT_SUCCESS; |
195 | } | |
196 | ||
197 | ||
198 | /* | |
199 | * --------------------------------------------------------------------------- | |
200 | * unifi_init | |
201 | * | |
202 | * Init the hardware. | |
203 | * | |
204 | * Arguments: | |
205 | * card Pointer to card struct | |
206 | * | |
207 | * Returns: | |
208 | * CsrResult code | |
209 | * CSR_RESULT_SUCCESS if successful | |
210 | * --------------------------------------------------------------------------- | |
211 | */ | |
212 | CsrResult unifi_init(card_t *card) | |
213 | { | |
214 | CsrResult r; | |
215 | CsrResult csrResult; | |
216 | ||
635d2b00 GKH |
217 | if (card == NULL) |
218 | { | |
635d2b00 GKH |
219 | return CSR_WIFI_HIP_RESULT_INVALID_VALUE; |
220 | } | |
221 | ||
222 | /* | |
223 | * Disable the SDIO interrupts while initialising UniFi. | |
224 | * Re-enable them when f/w is running. | |
225 | */ | |
226 | csrResult = CsrSdioInterruptDisable(card->sdio_if); | |
227 | if (csrResult == CSR_SDIO_RESULT_NO_DEVICE) | |
228 | { | |
229 | return CSR_WIFI_HIP_RESULT_NO_DEVICE; | |
230 | } | |
231 | ||
232 | /* | |
233 | * UniFi's PLL may start with a slow clock (~ 1 MHz) so initially | |
234 | * set the SDIO bus clock to a similar value or SDIO accesses may | |
235 | * fail. | |
236 | */ | |
237 | csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_SAFE_HZ); | |
238 | if (csrResult != CSR_RESULT_SUCCESS) | |
239 | { | |
240 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
635d2b00 GKH |
241 | return r; |
242 | } | |
243 | card->sdio_clock_speed = UNIFI_SDIO_CLOCK_SAFE_HZ; | |
244 | ||
245 | /* | |
246 | * Reset UniFi. Note, this only resets the WLAN function part of the chip, | |
247 | * the SDIO interface is not reset. | |
248 | */ | |
249 | unifi_trace(card->ospriv, UDBG1, "Resetting UniFi\n"); | |
250 | r = unifi_reset_hardware(card); | |
251 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
252 | { | |
253 | return r; | |
254 | } | |
255 | if (r != CSR_RESULT_SUCCESS) | |
256 | { | |
257 | unifi_error(card->ospriv, "Failed to reset UniFi\n"); | |
635d2b00 GKH |
258 | return r; |
259 | } | |
260 | ||
261 | /* Reset the power save mode, to be active until the MLME-reset is complete */ | |
262 | r = unifi_configure_low_power_mode(card, | |
263 | UNIFI_LOW_POWER_DISABLED, UNIFI_PERIODIC_WAKE_HOST_DISABLED); | |
264 | if (r != CSR_RESULT_SUCCESS) | |
265 | { | |
266 | unifi_error(card->ospriv, "Failed to set power save mode\n"); | |
635d2b00 GKH |
267 | return r; |
268 | } | |
269 | ||
270 | /* | |
271 | * Set initial value of page registers. | |
272 | * The page registers will be maintained by unifi_read...() and | |
273 | * unifi_write...(). | |
274 | */ | |
26a6b2e1 GKH |
275 | card->proc_select = (u32)(-1); |
276 | card->dmem_page = (u32)(-1); | |
277 | card->pmem_page = (u32)(-1); | |
635d2b00 GKH |
278 | r = unifi_write_direct16(card, ChipHelper_HOST_WINDOW3_PAGE(card->helper) * 2, 0); |
279 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
280 | { | |
281 | return r; | |
282 | } | |
283 | if (r != CSR_RESULT_SUCCESS) | |
284 | { | |
285 | unifi_error(card->ospriv, "Failed to write SHARED_DMEM_PAGE\n"); | |
635d2b00 GKH |
286 | return r; |
287 | } | |
288 | r = unifi_write_direct16(card, ChipHelper_HOST_WINDOW2_PAGE(card->helper) * 2, 0); | |
289 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
290 | { | |
291 | return r; | |
292 | } | |
293 | if (r != CSR_RESULT_SUCCESS) | |
294 | { | |
295 | unifi_error(card->ospriv, "Failed to write PROG_MEM2_PAGE\n"); | |
635d2b00 GKH |
296 | return r; |
297 | } | |
298 | ||
299 | /* | |
300 | * If the driver has reset UniFi due to previous SDIO failure, this may | |
301 | * have been due to a chip watchdog reset. In this case, the driver may | |
302 | * have requested a mini-coredump which needs to be captured now the | |
303 | * SDIO interface is alive. | |
304 | */ | |
95edd09e | 305 | (void)unifi_coredump_handle_request(card); |
635d2b00 GKH |
306 | |
307 | /* | |
308 | * Probe to see if the UniFi has ROM/flash to boot from. CSR6xxx should do. | |
309 | */ | |
310 | r = firmware_present_in_flash(card); | |
311 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
312 | { | |
313 | return r; | |
314 | } | |
315 | if (r == CSR_WIFI_HIP_RESULT_NOT_FOUND) | |
316 | { | |
317 | unifi_error(card->ospriv, "No firmware found\n"); | |
318 | } | |
319 | else if (r != CSR_RESULT_SUCCESS) | |
320 | { | |
321 | unifi_error(card->ospriv, "Probe for Flash failed\n"); | |
322 | } | |
323 | ||
635d2b00 GKH |
324 | return r; |
325 | } /* unifi_init() */ | |
326 | ||
327 | ||
328 | /* | |
329 | * --------------------------------------------------------------------------- | |
330 | * unifi_download | |
331 | * | |
332 | * Load the firmware. | |
333 | * | |
334 | * Arguments: | |
335 | * card Pointer to card struct | |
336 | * led_mask Loader LED mask | |
337 | * | |
338 | * Returns: | |
339 | * CSR_RESULT_SUCCESS on success | |
340 | * CsrResult error code on failure. | |
341 | * --------------------------------------------------------------------------- | |
342 | */ | |
95e326c2 | 343 | CsrResult unifi_download(card_t *card, s32 led_mask) |
635d2b00 GKH |
344 | { |
345 | CsrResult r; | |
346 | void *dlpriv; | |
347 | ||
635d2b00 GKH |
348 | if (card == NULL) |
349 | { | |
635d2b00 GKH |
350 | return CSR_WIFI_HIP_RESULT_INVALID_VALUE; |
351 | } | |
352 | ||
353 | /* Set the loader led mask */ | |
354 | card->loader_led_mask = led_mask; | |
355 | ||
356 | /* Get the firmware file information */ | |
357 | unifi_trace(card->ospriv, UDBG1, "downloading firmware...\n"); | |
358 | ||
359 | dlpriv = unifi_dl_fw_read_start(card, UNIFI_FW_STA); | |
360 | if (dlpriv == NULL) | |
361 | { | |
635d2b00 GKH |
362 | return CSR_WIFI_HIP_RESULT_NOT_FOUND; |
363 | } | |
364 | ||
365 | /* Download the firmware. */ | |
366 | r = unifi_dl_firmware(card, dlpriv); | |
367 | if (r != CSR_RESULT_SUCCESS) | |
368 | { | |
369 | unifi_error(card->ospriv, "Failed to download firmware\n"); | |
635d2b00 GKH |
370 | return r; |
371 | } | |
372 | ||
373 | /* Free the firmware file information. */ | |
374 | unifi_fw_read_stop(card->ospriv, dlpriv); | |
375 | ||
635d2b00 GKH |
376 | return CSR_RESULT_SUCCESS; |
377 | } /* unifi_download() */ | |
378 | ||
379 | ||
380 | /* | |
381 | * --------------------------------------------------------------------------- | |
382 | * unifi_hip_init | |
383 | * | |
384 | * This function performs the f/w initialisation sequence as described | |
385 | * in the Unifi Host Interface Protocol Specification. | |
386 | * It allocates memory for host-side slot data and signal queues. | |
387 | * | |
388 | * Arguments: | |
389 | * card Pointer to card struct | |
390 | * | |
391 | * Returns: | |
392 | * CSR_RESULT_SUCCESS on success or else a CSR error code | |
393 | * | |
394 | * Notes: | |
395 | * The firmware must have been downloaded. | |
396 | * --------------------------------------------------------------------------- | |
397 | */ | |
398 | static CsrResult unifi_hip_init(card_t *card) | |
399 | { | |
400 | CsrResult r; | |
401 | CsrResult csrResult; | |
402 | ||
635d2b00 GKH |
403 | r = card_hw_init(card); |
404 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
405 | { | |
406 | return r; | |
407 | } | |
408 | if (r != CSR_RESULT_SUCCESS) | |
409 | { | |
410 | unifi_error(card->ospriv, "Failed to establish communication with UniFi\n"); | |
635d2b00 GKH |
411 | return r; |
412 | } | |
413 | #ifdef CSR_PRE_ALLOC_NET_DATA | |
414 | /* if there is any preallocated netdata left from the prev session free it now */ | |
415 | prealloc_netdata_free(card); | |
416 | #endif | |
417 | /* | |
418 | * Allocate memory for host-side slot data and signal queues. | |
419 | * We need the config info read from the firmware to know how much | |
420 | * memory to allocate. | |
421 | */ | |
422 | r = card_init_slots(card); | |
423 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
424 | { | |
425 | return r; | |
426 | } | |
427 | if (r != CSR_RESULT_SUCCESS) | |
428 | { | |
429 | unifi_error(card->ospriv, "Init slots failed: %d\n", r); | |
635d2b00 GKH |
430 | return r; |
431 | } | |
432 | ||
433 | unifi_trace(card->ospriv, UDBG2, "Sending first UniFi interrupt\n"); | |
434 | ||
435 | r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE); | |
436 | if (r != CSR_RESULT_SUCCESS) | |
437 | { | |
635d2b00 GKH |
438 | return r; |
439 | } | |
440 | ||
441 | /* Enable the SDIO interrupts now that the f/w is running. */ | |
442 | csrResult = CsrSdioInterruptEnable(card->sdio_if); | |
443 | if (csrResult == CSR_SDIO_RESULT_NO_DEVICE) | |
444 | { | |
445 | return CSR_WIFI_HIP_RESULT_NO_DEVICE; | |
446 | } | |
447 | ||
448 | /* Signal the UniFi to start handling messages */ | |
449 | r = CardGenInt(card); | |
450 | if (r != CSR_RESULT_SUCCESS) | |
451 | { | |
635d2b00 GKH |
452 | return r; |
453 | } | |
454 | ||
635d2b00 GKH |
455 | return CSR_RESULT_SUCCESS; |
456 | } /* unifi_hip_init() */ | |
457 | ||
458 | ||
459 | /* | |
460 | * --------------------------------------------------------------------------- | |
461 | * _build_sdio_config_data | |
462 | * | |
463 | * Unpack the SDIO configuration information from a buffer read from | |
464 | * UniFi into a host structure. | |
465 | * The data is byte-swapped for a big-endian host if necessary by the | |
466 | * UNPACK... macros. | |
467 | * | |
468 | * Arguments: | |
469 | * card Pointer to card struct | |
470 | * cfg_data Destination structure to unpack into. | |
471 | * cfg_data_buf Source buffer to read from. This should be the raw | |
472 | * data read from UniFi. | |
473 | * | |
474 | * Returns: | |
475 | * None. | |
476 | * --------------------------------------------------------------------------- | |
477 | */ | |
478 | static void _build_sdio_config_data(sdio_config_data_t *cfg_data, | |
7e6f5794 | 479 | const u8 *cfg_data_buf) |
635d2b00 | 480 | { |
ab2b8c73 | 481 | s16 offset = 0; |
635d2b00 GKH |
482 | |
483 | cfg_data->version = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
484 | offset += SIZEOF_UINT16; | |
485 | ||
486 | cfg_data->sdio_ctrl_offset = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
487 | offset += SIZEOF_UINT16; | |
488 | ||
489 | cfg_data->fromhost_sigbuf_handle = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
490 | offset += SIZEOF_UINT16; | |
491 | ||
492 | cfg_data->tohost_sigbuf_handle = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
493 | offset += SIZEOF_UINT16; | |
494 | ||
495 | cfg_data->num_fromhost_sig_frags = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
496 | offset += SIZEOF_UINT16; | |
497 | ||
498 | cfg_data->num_tohost_sig_frags = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
499 | offset += SIZEOF_UINT16; | |
500 | ||
501 | cfg_data->num_fromhost_data_slots = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
502 | offset += SIZEOF_UINT16; | |
503 | ||
504 | cfg_data->num_tohost_data_slots = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
505 | offset += SIZEOF_UINT16; | |
506 | ||
507 | cfg_data->data_slot_size = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
508 | offset += SIZEOF_UINT16; | |
509 | ||
510 | cfg_data->initialised = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
511 | offset += SIZEOF_UINT16; | |
512 | ||
513 | cfg_data->overlay_size = CSR_GET_UINT32_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
514 | offset += SIZEOF_UINT32; | |
515 | ||
516 | cfg_data->data_slot_round = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
517 | offset += SIZEOF_UINT16; | |
518 | ||
519 | cfg_data->sig_frag_size = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
520 | offset += SIZEOF_UINT16; | |
521 | ||
522 | cfg_data->tohost_signal_padding = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(cfg_data_buf + offset); | |
523 | } /* _build_sdio_config_data() */ | |
524 | ||
525 | ||
526 | /* | |
527 | * - Function ---------------------------------------------------------------- | |
528 | * card_hw_init() | |
529 | * | |
530 | * Perform the initialisation procedure described in the UniFi Host | |
531 | * Interface Protocol document (section 3.3.8) and read the run-time | |
532 | * configuration information from the UniFi. This is stuff like number | |
533 | * of bulk data slots etc. | |
534 | * | |
535 | * The card enumeration and SD initialisation has already been done by | |
536 | * the SDIO library, see card_sdio_init(). | |
537 | * | |
538 | * The initialisation is done when firmware is ready, i.e. this may need | |
539 | * to be called after a f/w download operation. | |
540 | * | |
541 | * The initialisation procedure goes like this: | |
542 | * - Wait for UniFi to start-up by polling SHARED_MAILBOX1 | |
543 | * - Find the symbol table and look up SLT_SDIO_SLOT_CONFIG | |
544 | * - Read the config structure | |
545 | * - Check the "SDIO initialised" flag, if not zero do a h/w reset and | |
546 | * start again | |
547 | * - Decide the number of bulk data slots to allocate, allocate them and | |
548 | * set "SDIO initialised" flag (and generate an interrupt) to say so. | |
549 | * | |
550 | * Arguments: | |
551 | * card Pointer to card struct | |
552 | * | |
553 | * Returns: | |
554 | * CSR_RESULT_SUCEESS on success, | |
555 | * a CSR error code on failure | |
556 | * | |
557 | * Notes: | |
558 | * All data in the f/w is stored in a little endian format, without any | |
559 | * padding bytes. Every read from this memory has to be transformed in | |
560 | * host (cpu specific) format, before it is stored in driver's parameters | |
561 | * or/and structures. Athough unifi_card_read16() and unifi_read32() do perform | |
58af42a4 | 562 | * the conversion internally, unifi_readn() does not. |
635d2b00 GKH |
563 | * --------------------------------------------------------------------------- |
564 | */ | |
565 | static CsrResult card_hw_init(card_t *card) | |
566 | { | |
26a6b2e1 | 567 | u32 slut_address; |
8c87f69a GKH |
568 | u16 initialised; |
569 | u16 finger_print; | |
635d2b00 GKH |
570 | symbol_t slut; |
571 | sdio_config_data_t *cfg_data; | |
7e6f5794 | 572 | u8 cfg_data_buf[SDIO_CONFIG_DATA_SIZE]; |
635d2b00 GKH |
573 | CsrResult r; |
574 | void *dlpriv; | |
ab2b8c73 GKH |
575 | s16 major, minor; |
576 | s16 search_4slut_again; | |
635d2b00 GKH |
577 | CsrResult csrResult; |
578 | ||
635d2b00 GKH |
579 | /* |
580 | * The device revision from the TPLMID_MANF and TPLMID_CARD fields | |
581 | * of the CIS are available as | |
582 | * card->sdio_if->pDevice->ManfID | |
583 | * card->sdio_if->pDevice->AppID | |
584 | */ | |
585 | ||
586 | /* | |
587 | * Run in a loop so we can patch. | |
588 | */ | |
589 | do | |
590 | { | |
591 | /* Reset these each time around the loop. */ | |
592 | search_4slut_again = 0; | |
593 | cfg_data = NULL; | |
594 | ||
595 | r = card_wait_for_firmware_to_start(card, &slut_address); | |
596 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
597 | { | |
598 | return r; | |
599 | } | |
600 | if (r != CSR_RESULT_SUCCESS) | |
601 | { | |
602 | unifi_error(card->ospriv, "Firmware hasn't started\n"); | |
635d2b00 GKH |
603 | return r; |
604 | } | |
605 | unifi_trace(card->ospriv, UDBG4, "SLUT addr 0x%lX\n", slut_address); | |
606 | ||
607 | /* | |
608 | * Firmware has started, but doesn't know full clock configuration yet | |
609 | * as some of the information may be in the MIB. Therefore we set an | |
610 | * initial SDIO clock speed, faster than UNIFI_SDIO_CLOCK_SAFE_HZ, for | |
611 | * the patch download and subsequent firmware initialisation, and | |
612 | * full speed UNIFI_SDIO_CLOCK_MAX_HZ will be set once the f/w tells us | |
613 | * that it is ready. | |
614 | */ | |
615 | csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_INIT_HZ); | |
616 | if (csrResult != CSR_RESULT_SUCCESS) | |
617 | { | |
618 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
635d2b00 GKH |
619 | return r; |
620 | } | |
621 | card->sdio_clock_speed = UNIFI_SDIO_CLOCK_INIT_HZ; | |
622 | ||
623 | /* | |
624 | * Check the SLUT fingerprint. | |
625 | * The slut_address is a generic pointer so we must use unifi_card_read16(). | |
626 | */ | |
627 | unifi_trace(card->ospriv, UDBG4, "Looking for SLUT finger print\n"); | |
628 | finger_print = 0; | |
629 | r = unifi_card_read16(card, slut_address, &finger_print); | |
630 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
631 | { | |
632 | return r; | |
633 | } | |
634 | if (r != CSR_RESULT_SUCCESS) | |
635 | { | |
636 | unifi_error(card->ospriv, "Failed to read SLUT finger print\n"); | |
635d2b00 GKH |
637 | return r; |
638 | } | |
639 | ||
640 | if (finger_print != SLUT_FINGERPRINT) | |
641 | { | |
642 | unifi_error(card->ospriv, "Failed to find Symbol lookup table fingerprint\n"); | |
635d2b00 GKH |
643 | return CSR_RESULT_FAILURE; |
644 | } | |
645 | ||
646 | /* Symbol table starts imedately after the fingerprint */ | |
647 | slut_address += 2; | |
648 | ||
649 | /* Search the table until either the end marker is found, or the | |
650 | * loading of patch firmware invalidates the current table. | |
651 | */ | |
652 | while (!search_4slut_again) | |
653 | { | |
8c87f69a | 654 | u16 s; |
26a6b2e1 | 655 | u32 l; |
635d2b00 GKH |
656 | |
657 | r = unifi_card_read16(card, slut_address, &s); | |
658 | if (r != CSR_RESULT_SUCCESS) | |
659 | { | |
635d2b00 GKH |
660 | return r; |
661 | } | |
662 | slut_address += 2; | |
663 | ||
664 | if (s == CSR_SLT_END) | |
665 | { | |
666 | unifi_trace(card->ospriv, UDBG3, " found CSR_SLT_END\n"); | |
667 | break; | |
668 | } | |
669 | ||
670 | r = unifi_read32(card, slut_address, &l); | |
671 | if (r != CSR_RESULT_SUCCESS) | |
672 | { | |
635d2b00 GKH |
673 | return r; |
674 | } | |
675 | slut_address += 4; | |
676 | ||
677 | slut.id = s; | |
678 | slut.obj = l; | |
679 | ||
680 | unifi_trace(card->ospriv, UDBG3, " found SLUT id %02d.%08lx\n", slut.id, slut.obj); | |
681 | switch (slut.id) | |
682 | { | |
683 | case CSR_SLT_SDIO_SLOT_CONFIG: | |
684 | cfg_data = &card->config_data; | |
685 | /* | |
686 | * unifi_card_readn reads n bytes from the card, where data is stored | |
687 | * in a little endian format, without any padding bytes. So, we | |
688 | * can not just pass the cfg_data pointer or use the | |
689 | * sizeof(sdio_config_data_t) since the structure in the host can | |
690 | * be big endian formatted or have padding bytes for alignment. | |
691 | * We use a char buffer to read the data from the card. | |
692 | */ | |
693 | r = unifi_card_readn(card, slut.obj, cfg_data_buf, SDIO_CONFIG_DATA_SIZE); | |
694 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
695 | { | |
696 | return r; | |
697 | } | |
698 | if (r != CSR_RESULT_SUCCESS) | |
699 | { | |
700 | unifi_error(card->ospriv, "Failed to read config data\n"); | |
635d2b00 GKH |
701 | return r; |
702 | } | |
703 | /* .. and then we copy the data to the host structure */ | |
704 | _build_sdio_config_data(cfg_data, cfg_data_buf); | |
705 | ||
706 | /* Make sure the from host data slots are what we expect | |
707 | we reserve 2 for commands and there should be at least | |
708 | 1 left for each access category */ | |
709 | if ((cfg_data->num_fromhost_data_slots < UNIFI_RESERVED_COMMAND_SLOTS) | |
710 | || (cfg_data->num_fromhost_data_slots - UNIFI_RESERVED_COMMAND_SLOTS) / UNIFI_NO_OF_TX_QS == 0) | |
711 | { | |
712 | unifi_error(card->ospriv, "From host data slots %d\n", cfg_data->num_fromhost_data_slots); | |
713 | unifi_error(card->ospriv, "need to be (queues * x + 2) (UNIFI_RESERVED_COMMAND_SLOTS for commands)\n"); | |
635d2b00 GKH |
714 | return CSR_RESULT_FAILURE; |
715 | } | |
716 | ||
717 | /* Configure SDIO to-block-size padding */ | |
718 | if (card->sdio_io_block_pad) | |
719 | { | |
720 | /* | |
721 | * Firmware limits the maximum padding size via data_slot_round. | |
722 | * Therefore when padding to whole block sizes, the block size | |
723 | * must be configured correctly by adjusting CSR_WIFI_HIP_SDIO_BLOCK_SIZE. | |
724 | */ | |
725 | if (cfg_data->data_slot_round < card->sdio_io_block_size) | |
726 | { | |
727 | unifi_error(card->ospriv, | |
728 | "Configuration error: Block size of %d exceeds f/w data_slot_round of %d\n", | |
729 | card->sdio_io_block_size, cfg_data->data_slot_round); | |
730 | return CSR_WIFI_HIP_RESULT_INVALID_VALUE; | |
731 | } | |
732 | ||
733 | /* | |
734 | * To force the To-Host signals to be rounded up to the SDIO block | |
735 | * size, we need to write the To-Host Signal Padding Fragments | |
736 | * field of the SDIO configuration in UniFi. | |
737 | */ | |
738 | if ((card->sdio_io_block_size % cfg_data->sig_frag_size) != 0) | |
739 | { | |
740 | unifi_error(card->ospriv, "Configuration error: Can not pad to-host signals.\n"); | |
635d2b00 GKH |
741 | return CSR_WIFI_HIP_RESULT_INVALID_VALUE; |
742 | } | |
8c87f69a | 743 | cfg_data->tohost_signal_padding = (u16) (card->sdio_io_block_size / cfg_data->sig_frag_size); |
635d2b00 GKH |
744 | unifi_info(card->ospriv, "SDIO block size %d requires %d padding chunks\n", |
745 | card->sdio_io_block_size, cfg_data->tohost_signal_padding); | |
746 | r = unifi_card_write16(card, slut.obj + SDIO_TO_HOST_SIG_PADDING_OFFSET, cfg_data->tohost_signal_padding); | |
747 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
748 | { | |
749 | return r; | |
750 | } | |
751 | if (r != CSR_RESULT_SUCCESS) | |
752 | { | |
753 | unifi_error(card->ospriv, "Failed to write To-Host Signal Padding Fragments\n"); | |
635d2b00 GKH |
754 | return r; |
755 | } | |
756 | } | |
757 | ||
758 | /* Reconstruct the Generic Pointer address of the | |
759 | * SDIO Control Data Struct. | |
760 | */ | |
761 | card->sdio_ctrl_addr = cfg_data->sdio_ctrl_offset | (UNIFI_SH_DMEM << 24); | |
762 | card->init_flag_addr = slut.obj + SDIO_INIT_FLAG_OFFSET; | |
763 | break; | |
764 | ||
765 | case CSR_SLT_BUILD_ID_NUMBER: | |
766 | { | |
26a6b2e1 | 767 | u32 n; |
635d2b00 GKH |
768 | r = unifi_read32(card, slut.obj, &n); |
769 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
770 | { | |
771 | return r; | |
772 | } | |
773 | if (r != CSR_RESULT_SUCCESS) | |
774 | { | |
775 | unifi_error(card->ospriv, "Failed to read build id\n"); | |
635d2b00 GKH |
776 | return r; |
777 | } | |
778 | card->build_id = n; | |
779 | } | |
780 | break; | |
781 | ||
782 | case CSR_SLT_BUILD_ID_STRING: | |
783 | r = unifi_readnz(card, slut.obj, card->build_id_string, | |
784 | sizeof(card->build_id_string)); | |
785 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
786 | { | |
787 | return r; | |
788 | } | |
789 | if (r != CSR_RESULT_SUCCESS) | |
790 | { | |
791 | unifi_error(card->ospriv, "Failed to read build string\n"); | |
635d2b00 GKH |
792 | return r; |
793 | } | |
794 | break; | |
795 | ||
796 | case CSR_SLT_PERSISTENT_STORE_DB: | |
797 | break; | |
798 | ||
799 | case CSR_SLT_BOOT_LOADER_CONTROL: | |
800 | ||
801 | /* This command copies most of the station firmware | |
802 | * image from ROM into program RAM. It also clears | |
803 | * out the zerod data and sets up the initialised | |
804 | * data. */ | |
805 | r = unifi_do_loader_op(card, slut.obj + 6, UNIFI_BOOT_LOADER_LOAD_STA); | |
806 | if (r != CSR_RESULT_SUCCESS) | |
807 | { | |
808 | unifi_error(card->ospriv, "Failed to write loader load image command\n"); | |
635d2b00 GKH |
809 | return r; |
810 | } | |
811 | ||
812 | dlpriv = unifi_dl_fw_read_start(card, UNIFI_FW_STA); | |
813 | ||
814 | /* dlpriv might be NULL, we still need to do the do_loader_op step. */ | |
815 | if (dlpriv != NULL) | |
816 | { | |
817 | /* Download the firmware. */ | |
818 | r = unifi_dl_patch(card, dlpriv, slut.obj); | |
819 | ||
820 | /* Free the firmware file information. */ | |
821 | unifi_fw_read_stop(card->ospriv, dlpriv); | |
822 | ||
823 | if (r != CSR_RESULT_SUCCESS) | |
824 | { | |
825 | unifi_error(card->ospriv, "Failed to patch firmware\n"); | |
635d2b00 GKH |
826 | return r; |
827 | } | |
828 | } | |
829 | ||
830 | /* This command starts the firmware image that we want (the | |
831 | * station by default) with any patches required applied. */ | |
832 | r = unifi_do_loader_op(card, slut.obj + 6, UNIFI_BOOT_LOADER_RESTART); | |
833 | if (r != CSR_RESULT_SUCCESS) | |
834 | { | |
835 | unifi_error(card->ospriv, "Failed to write loader restart command\n"); | |
635d2b00 GKH |
836 | return r; |
837 | } | |
838 | ||
839 | /* The now running patch f/w defines a new SLUT data structure - | |
840 | * the current one is no longer valid. We must drop out of the | |
841 | * processing loop and enumerate the new SLUT (which may appear | |
842 | * at a different offset). | |
843 | */ | |
844 | search_4slut_again = 1; | |
845 | break; | |
846 | ||
847 | case CSR_SLT_PANIC_DATA_PHY: | |
848 | card->panic_data_phy_addr = slut.obj; | |
849 | break; | |
850 | ||
851 | case CSR_SLT_PANIC_DATA_MAC: | |
852 | card->panic_data_mac_addr = slut.obj; | |
853 | break; | |
854 | ||
855 | default: | |
856 | /* do nothing */ | |
857 | break; | |
858 | } | |
859 | } /* while */ | |
860 | } while (search_4slut_again); | |
861 | ||
862 | /* Did we find the Config Data ? */ | |
863 | if (cfg_data == NULL) | |
864 | { | |
865 | unifi_error(card->ospriv, "Failed to find SDIO_SLOT_CONFIG Symbol\n"); | |
635d2b00 GKH |
866 | return CSR_RESULT_FAILURE; |
867 | } | |
868 | ||
869 | /* | |
870 | * Has ths card already been initialised? | |
871 | * If so, return an error so we do a h/w reset and start again. | |
872 | */ | |
873 | r = unifi_card_read16(card, card->init_flag_addr, &initialised); | |
874 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
875 | { | |
876 | return r; | |
877 | } | |
878 | if (r != CSR_RESULT_SUCCESS) | |
879 | { | |
880 | unifi_error(card->ospriv, "Failed to read init flag at %08lx\n", | |
881 | card->init_flag_addr); | |
635d2b00 GKH |
882 | return r; |
883 | } | |
884 | if (initialised != 0) | |
885 | { | |
635d2b00 GKH |
886 | return CSR_RESULT_FAILURE; |
887 | } | |
888 | ||
889 | ||
890 | /* | |
891 | * Now check the UniFi firmware version | |
892 | */ | |
893 | major = (cfg_data->version >> 8) & 0xFF; | |
894 | minor = cfg_data->version & 0xFF; | |
895 | unifi_info(card->ospriv, "UniFi f/w protocol version %d.%d (driver %d.%d)\n", | |
896 | major, minor, | |
897 | UNIFI_HIP_MAJOR_VERSION, UNIFI_HIP_MINOR_VERSION); | |
898 | ||
899 | unifi_info(card->ospriv, "Firmware build %u: %s\n", | |
900 | card->build_id, card->build_id_string); | |
901 | ||
902 | if (major != UNIFI_HIP_MAJOR_VERSION) | |
903 | { | |
904 | unifi_error(card->ospriv, "UniFi f/w protocol major version (%d) is different from driver (v%d.%d)\n", | |
905 | major, UNIFI_HIP_MAJOR_VERSION, UNIFI_HIP_MINOR_VERSION); | |
906 | #ifndef CSR_WIFI_DISABLE_HIP_VERSION_CHECK | |
635d2b00 GKH |
907 | return CSR_RESULT_FAILURE; |
908 | #endif | |
909 | } | |
910 | if (minor < UNIFI_HIP_MINOR_VERSION) | |
911 | { | |
912 | unifi_error(card->ospriv, "UniFi f/w protocol version (v%d.%d) is older than minimum required by driver (v%d.%d).\n", | |
913 | major, minor, | |
914 | UNIFI_HIP_MAJOR_VERSION, UNIFI_HIP_MINOR_VERSION); | |
915 | #ifndef CSR_WIFI_DISABLE_HIP_VERSION_CHECK | |
635d2b00 GKH |
916 | return CSR_RESULT_FAILURE; |
917 | #endif | |
918 | } | |
919 | ||
920 | /* Read panic codes from a previous firmware panic. If the firmware has | |
921 | * not panicked since power was applied (e.g. power-off hard reset) | |
922 | * the stored panic codes will not be updated. | |
923 | */ | |
924 | unifi_read_panic(card); | |
925 | ||
635d2b00 GKH |
926 | return CSR_RESULT_SUCCESS; |
927 | } /* card_hw_init() */ | |
928 | ||
929 | ||
930 | /* | |
931 | * --------------------------------------------------------------------------- | |
932 | * card_wait_for_unifi_to_reset | |
933 | * | |
934 | * Waits for a reset to complete by polling the WLAN function enable | |
935 | * bit (which is cleared on reset). | |
936 | * | |
937 | * Arguments: | |
938 | * card Pointer to card struct | |
939 | * | |
940 | * Returns: | |
941 | * CSR_RESULT_SUCCESS on success, CSR error code on failure. | |
942 | * --------------------------------------------------------------------------- | |
943 | */ | |
944 | static CsrResult card_wait_for_unifi_to_reset(card_t *card) | |
945 | { | |
ab2b8c73 | 946 | s16 i; |
635d2b00 | 947 | CsrResult r; |
7e6f5794 | 948 | u8 io_enable; |
635d2b00 GKH |
949 | CsrResult csrResult; |
950 | ||
635d2b00 GKH |
951 | r = CSR_RESULT_SUCCESS; |
952 | for (i = 0; i < MAILBOX2_ATTEMPTS; i++) | |
953 | { | |
954 | unifi_trace(card->ospriv, UDBG1, "waiting for reset to complete, attempt %d\n", i); | |
955 | if (card->chip_id > SDIO_CARD_ID_UNIFI_2) | |
956 | { | |
957 | /* It's quite likely that this read will timeout for the | |
958 | * first few tries - especially if we have reset via | |
959 | * DBG_RESET. | |
960 | */ | |
961 | #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE) | |
962 | unifi_debug_log_to_buf("m0@%02X=", SDIO_IO_READY); | |
963 | #endif | |
964 | csrResult = CsrSdioF0Read8(card->sdio_if, SDIO_IO_READY, &io_enable); | |
965 | #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE) | |
966 | if (csrResult != CSR_RESULT_SUCCESS) | |
967 | { | |
968 | unifi_debug_log_to_buf("error=%X\n", csrResult); | |
969 | } | |
970 | else | |
971 | { | |
972 | unifi_debug_log_to_buf("%X\n", io_enable); | |
973 | } | |
974 | #endif | |
975 | if (csrResult == CSR_SDIO_RESULT_NO_DEVICE) | |
976 | { | |
977 | return CSR_WIFI_HIP_RESULT_NO_DEVICE; | |
978 | } | |
979 | r = CSR_RESULT_SUCCESS; | |
980 | if (csrResult != CSR_RESULT_SUCCESS) | |
981 | { | |
982 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
983 | } | |
984 | } | |
985 | else | |
986 | { | |
987 | r = sdio_read_f0(card, SDIO_IO_ENABLE, &io_enable); | |
988 | } | |
989 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
990 | { | |
991 | return r; | |
992 | } | |
993 | if (r == CSR_RESULT_SUCCESS) | |
994 | { | |
8c87f69a | 995 | u16 mbox2; |
ab2b8c73 | 996 | s16 enabled = io_enable & (1 << card->function); |
635d2b00 GKH |
997 | |
998 | if (!enabled) | |
999 | { | |
1000 | unifi_trace(card->ospriv, UDBG1, | |
1001 | "Reset complete (function %d is disabled) in ~ %u msecs\n", | |
1002 | card->function, i * MAILBOX2_TIMEOUT); | |
1003 | ||
1004 | /* Enable WLAN function and verify MAILBOX2 is zero'd */ | |
1005 | csrResult = CsrSdioFunctionEnable(card->sdio_if); | |
1006 | if (csrResult != CSR_RESULT_SUCCESS) | |
1007 | { | |
1008 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
1009 | unifi_error(card->ospriv, "CsrSdioFunctionEnable failed %d\n", r); | |
1010 | break; | |
1011 | } | |
1012 | } | |
1013 | ||
1014 | r = unifi_read_direct16(card, ChipHelper_SDIO_HIP_HANDSHAKE(card->helper) * 2, &mbox2); | |
1015 | if (r != CSR_RESULT_SUCCESS) | |
1016 | { | |
1017 | unifi_error(card->ospriv, "read HIP_HANDSHAKE failed %d\n", r); | |
1018 | break; | |
1019 | } | |
1020 | if (mbox2 != 0) | |
1021 | { | |
1022 | unifi_error(card->ospriv, "MAILBOX2 non-zero after reset (mbox2 = %04x)\n", mbox2); | |
1023 | r = CSR_RESULT_FAILURE; | |
1024 | } | |
1025 | break; | |
1026 | } | |
1027 | else | |
1028 | { | |
1029 | if (card->chip_id > SDIO_CARD_ID_UNIFI_2) | |
1030 | { | |
1031 | /* We ignore read failures for the first few reads, | |
1032 | * they are probably benign. */ | |
1033 | if (i > MAILBOX2_ATTEMPTS / 4) | |
1034 | { | |
1035 | unifi_trace(card->ospriv, UDBG1, "Failed to read CCCR IO Ready register while polling for reset\n"); | |
1036 | } | |
1037 | } | |
1038 | else | |
1039 | { | |
1040 | unifi_trace(card->ospriv, UDBG1, "Failed to read CCCR IO Enable register while polling for reset\n"); | |
1041 | } | |
1042 | } | |
1043 | CsrThreadSleep(MAILBOX2_TIMEOUT); | |
1044 | } | |
1045 | ||
1046 | if (r == CSR_RESULT_SUCCESS && i == MAILBOX2_ATTEMPTS) | |
1047 | { | |
1048 | unifi_trace(card->ospriv, UDBG1, "Timeout waiting for UniFi to complete reset\n"); | |
1049 | r = CSR_RESULT_FAILURE; | |
1050 | } | |
1051 | ||
635d2b00 GKH |
1052 | return r; |
1053 | } /* card_wait_for_unifi_to_reset() */ | |
1054 | ||
1055 | ||
1056 | /* | |
1057 | * --------------------------------------------------------------------------- | |
1058 | * card_wait_for_unifi_to_disable | |
1059 | * | |
1060 | * Waits for the function to become disabled by polling the | |
1061 | * IO_READY bit. | |
1062 | * | |
1063 | * Arguments: | |
1064 | * card Pointer to card struct | |
1065 | * | |
1066 | * Returns: | |
1067 | * CSR_RESULT_SUCCESS on success, CSR error code on failure. | |
1068 | * | |
1069 | * Notes: This function can only be used with | |
1070 | * card->chip_id > SDIO_CARD_ID_UNIFI_2 | |
1071 | * --------------------------------------------------------------------------- | |
1072 | */ | |
1073 | static CsrResult card_wait_for_unifi_to_disable(card_t *card) | |
1074 | { | |
ab2b8c73 | 1075 | s16 i; |
635d2b00 | 1076 | CsrResult r; |
7e6f5794 | 1077 | u8 io_enable; |
635d2b00 GKH |
1078 | CsrResult csrResult; |
1079 | ||
635d2b00 GKH |
1080 | if (card->chip_id <= SDIO_CARD_ID_UNIFI_2) |
1081 | { | |
1082 | unifi_error(card->ospriv, | |
1083 | "Function reset method not supported for chip_id=%d\n", | |
1084 | card->chip_id); | |
635d2b00 GKH |
1085 | return CSR_RESULT_FAILURE; |
1086 | } | |
1087 | ||
1088 | r = CSR_RESULT_SUCCESS; | |
1089 | for (i = 0; i < MAILBOX2_ATTEMPTS; i++) | |
1090 | { | |
1091 | unifi_trace(card->ospriv, UDBG1, "waiting for disable to complete, attempt %d\n", i); | |
1092 | ||
1093 | /* | |
1094 | * It's quite likely that this read will timeout for the | |
1095 | * first few tries - especially if we have reset via | |
1096 | * DBG_RESET. | |
1097 | */ | |
1098 | #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE) | |
1099 | unifi_debug_log_to_buf("r0@%02X=", SDIO_IO_READY); | |
1100 | #endif | |
1101 | csrResult = CsrSdioF0Read8(card->sdio_if, SDIO_IO_READY, &io_enable); | |
1102 | #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_SDIO_TRACE) | |
1103 | if (csrResult != CSR_RESULT_SUCCESS) | |
1104 | { | |
1105 | unifi_debug_log_to_buf("error=%X\n", csrResult); | |
1106 | } | |
1107 | else | |
1108 | { | |
1109 | unifi_debug_log_to_buf("%X\n", io_enable); | |
1110 | } | |
1111 | #endif | |
1112 | if (csrResult == CSR_SDIO_RESULT_NO_DEVICE) | |
1113 | { | |
1114 | return CSR_WIFI_HIP_RESULT_NO_DEVICE; | |
1115 | } | |
1116 | if (csrResult == CSR_RESULT_SUCCESS) | |
1117 | { | |
ab2b8c73 | 1118 | s16 enabled = io_enable & (1 << card->function); |
635d2b00 GKH |
1119 | r = CSR_RESULT_SUCCESS; |
1120 | if (!enabled) | |
1121 | { | |
1122 | unifi_trace(card->ospriv, UDBG1, | |
1123 | "Disable complete (function %d is disabled) in ~ %u msecs\n", | |
1124 | card->function, i * MAILBOX2_TIMEOUT); | |
1125 | ||
1126 | break; | |
1127 | } | |
1128 | } | |
1129 | else | |
1130 | { | |
1131 | /* | |
1132 | * We ignore read failures for the first few reads, | |
1133 | * they are probably benign. | |
1134 | */ | |
1135 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
1136 | if (i > (MAILBOX2_ATTEMPTS / 4)) | |
1137 | { | |
1138 | unifi_trace(card->ospriv, UDBG1, | |
1139 | "Failed to read CCCR IO Ready register while polling for disable\n"); | |
1140 | } | |
1141 | } | |
1142 | CsrThreadSleep(MAILBOX2_TIMEOUT); | |
1143 | } | |
1144 | ||
1145 | if ((r == CSR_RESULT_SUCCESS) && (i == MAILBOX2_ATTEMPTS)) | |
1146 | { | |
1147 | unifi_trace(card->ospriv, UDBG1, "Timeout waiting for UniFi to complete disable\n"); | |
1148 | r = CSR_RESULT_FAILURE; | |
1149 | } | |
1150 | ||
635d2b00 GKH |
1151 | return r; |
1152 | } /* card_wait_for_unifi_to_reset() */ | |
1153 | ||
1154 | ||
1155 | /* | |
1156 | * --------------------------------------------------------------------------- | |
1157 | * card_wait_for_firmware_to_start | |
1158 | * | |
1159 | * Polls the MAILBOX1 register for a non-zero value. | |
1160 | * Then reads MAILBOX0 and forms the two values into a 32-bit address | |
1161 | * which is returned to the caller. | |
1162 | * | |
1163 | * Arguments: | |
1164 | * card Pointer to card struct | |
1165 | * paddr Pointer to receive the UniFi address formed | |
1166 | * by concatenating MAILBOX1 and MAILBOX0. | |
1167 | * | |
1168 | * Returns: | |
1169 | * CSR_RESULT_SUCCESS on success, CSR error code on failure. | |
1170 | * --------------------------------------------------------------------------- | |
1171 | */ | |
26a6b2e1 | 1172 | CsrResult card_wait_for_firmware_to_start(card_t *card, u32 *paddr) |
635d2b00 | 1173 | { |
95e326c2 | 1174 | s32 i; |
8c87f69a | 1175 | u16 mbox0, mbox1; |
635d2b00 GKH |
1176 | CsrResult r; |
1177 | ||
635d2b00 GKH |
1178 | /* |
1179 | * Wait for UniFi to initialise its data structures by polling | |
1180 | * the SHARED_MAILBOX1 register. | |
1181 | * Experience shows this is typically 120ms. | |
1182 | */ | |
1183 | CsrThreadSleep(MAILBOX1_TIMEOUT); | |
1184 | ||
1185 | mbox1 = 0; | |
1186 | unifi_trace(card->ospriv, UDBG1, "waiting for MAILBOX1 to be non-zero...\n"); | |
1187 | for (i = 0; i < MAILBOX1_ATTEMPTS; i++) | |
1188 | { | |
1189 | r = unifi_read_direct16(card, ChipHelper_MAILBOX1(card->helper) * 2, &mbox1); | |
1190 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1191 | { | |
1192 | return r; | |
1193 | } | |
1194 | if (r != CSR_RESULT_SUCCESS) | |
1195 | { | |
1196 | /* These reads can fail if UniFi isn't up yet, so try again */ | |
1197 | unifi_warning(card->ospriv, "Failed to read UniFi Mailbox1 register\n"); | |
1198 | } | |
1199 | ||
1200 | if ((r == CSR_RESULT_SUCCESS) && (mbox1 != 0)) | |
1201 | { | |
1202 | unifi_trace(card->ospriv, UDBG1, "MAILBOX1 ready (0x%04X) in %u millisecs\n", | |
1203 | mbox1, i * MAILBOX1_TIMEOUT); | |
1204 | ||
1205 | /* Read the MAILBOX1 again in case we caught the value as it | |
1206 | * changed. */ | |
1207 | r = unifi_read_direct16(card, ChipHelper_MAILBOX1(card->helper) * 2, &mbox1); | |
1208 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1209 | { | |
1210 | return r; | |
1211 | } | |
1212 | if (r != CSR_RESULT_SUCCESS) | |
1213 | { | |
1214 | unifi_error(card->ospriv, "Failed to read UniFi Mailbox1 register for second time\n"); | |
635d2b00 GKH |
1215 | return r; |
1216 | } | |
1217 | unifi_trace(card->ospriv, UDBG1, "MAILBOX1 value=0x%04X\n", mbox1); | |
1218 | ||
1219 | break; | |
1220 | } | |
1221 | ||
1222 | CsrThreadSleep(MAILBOX1_TIMEOUT); | |
1223 | if ((i % 100) == 99) | |
1224 | { | |
1225 | unifi_trace(card->ospriv, UDBG2, "MAILBOX1 not ready (0x%X), still trying...\n", mbox1); | |
1226 | } | |
1227 | } | |
1228 | ||
1229 | if ((r == CSR_RESULT_SUCCESS) && (mbox1 == 0)) | |
1230 | { | |
1231 | unifi_trace(card->ospriv, UDBG1, "Timeout waiting for firmware to start, Mailbox1 still 0 after %d ms\n", | |
1232 | MAILBOX1_ATTEMPTS * MAILBOX1_TIMEOUT); | |
635d2b00 GKH |
1233 | return CSR_RESULT_FAILURE; |
1234 | } | |
1235 | ||
1236 | ||
1237 | /* | |
1238 | * Complete the reset handshake by setting MAILBOX2 to 0xFFFF | |
1239 | */ | |
1240 | r = unifi_write_direct16(card, ChipHelper_SDIO_HIP_HANDSHAKE(card->helper) * 2, 0xFFFF); | |
1241 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1242 | { | |
1243 | return r; | |
1244 | } | |
1245 | if (r != CSR_RESULT_SUCCESS) | |
1246 | { | |
1247 | unifi_error(card->ospriv, "Failed to write f/w startup handshake to MAILBOX2\n"); | |
635d2b00 GKH |
1248 | return r; |
1249 | } | |
1250 | ||
1251 | ||
1252 | /* | |
1253 | * Read the Symbol Look Up Table (SLUT) offset. | |
1254 | * Top 16 bits are in mbox1, read the lower 16 bits from mbox0. | |
1255 | */ | |
1256 | mbox0 = 0; | |
1257 | r = unifi_read_direct16(card, ChipHelper_MAILBOX0(card->helper) * 2, &mbox0); | |
1258 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1259 | { | |
1260 | return r; | |
1261 | } | |
1262 | if (r != CSR_RESULT_SUCCESS) | |
1263 | { | |
1264 | unifi_error(card->ospriv, "Failed to read UniFi Mailbox0 register\n"); | |
635d2b00 GKH |
1265 | return r; |
1266 | } | |
1267 | ||
26a6b2e1 | 1268 | *paddr = (((u32)mbox1 << 16) | mbox0); |
635d2b00 | 1269 | |
635d2b00 GKH |
1270 | return CSR_RESULT_SUCCESS; |
1271 | } /* card_wait_for_firmware_to_start() */ | |
1272 | ||
1273 | ||
1274 | /* | |
1275 | * --------------------------------------------------------------------------- | |
1276 | * unifi_capture_panic | |
1277 | * | |
1278 | * Attempt to capture panic codes from the firmware. This may involve | |
1279 | * warm reset of the chip to regain access following a watchdog reset. | |
1280 | * | |
1281 | * Arguments: | |
1282 | * card Pointer to card struct | |
1283 | * | |
1284 | * Returns: | |
1285 | * CSR_RESULT_SUCCESS if panic codes were captured, or none available | |
1286 | * CSR_RESULT_FAILURE if the driver could not access function 1 | |
1287 | * --------------------------------------------------------------------------- | |
1288 | */ | |
1289 | CsrResult unifi_capture_panic(card_t *card) | |
1290 | { | |
635d2b00 GKH |
1291 | |
1292 | /* The firmware must have previously initialised to read the panic addresses | |
1293 | * from the SLUT | |
1294 | */ | |
1295 | if (!card->panic_data_phy_addr || !card->panic_data_mac_addr) | |
1296 | { | |
635d2b00 GKH |
1297 | return CSR_RESULT_SUCCESS; |
1298 | } | |
1299 | ||
1300 | /* Ensure we can access function 1 following a panic/watchdog reset */ | |
1301 | if (card_access_panic(card) == CSR_RESULT_SUCCESS) | |
1302 | { | |
1303 | /* Read the panic codes */ | |
1304 | unifi_read_panic(card); | |
1305 | } | |
1306 | else | |
1307 | { | |
1308 | unifi_info(card->ospriv, "Unable to read panic codes"); | |
1309 | } | |
1310 | ||
635d2b00 GKH |
1311 | return CSR_RESULT_SUCCESS; |
1312 | } | |
1313 | ||
1314 | ||
1315 | /* | |
1316 | * --------------------------------------------------------------------------- | |
1317 | * card_access_panic | |
1318 | * Attempt to read the WLAN SDIO function in order to read panic codes | |
1319 | * and perform various reset steps to regain access if the read fails. | |
1320 | * | |
1321 | * Arguments: | |
1322 | * card Pointer to card struct | |
1323 | * | |
1324 | * Returns: | |
1325 | * CSR_RESULT_SUCCESS if panic codes can be read | |
1326 | * CSR error code if panic codes can not be read | |
1327 | * --------------------------------------------------------------------------- | |
1328 | */ | |
1329 | static CsrResult card_access_panic(card_t *card) | |
1330 | { | |
8c87f69a | 1331 | u16 data_u16 = 0; |
95e326c2 | 1332 | s32 i; |
635d2b00 GKH |
1333 | CsrResult r, sr; |
1334 | ||
58af42a4 | 1335 | /* A chip version of zero means that the version never got successfully read |
635d2b00 GKH |
1336 | * during reset. In this case give up because it will not be possible to |
1337 | * verify the chip version. | |
1338 | */ | |
1339 | if (!card->chip_version) | |
1340 | { | |
1341 | unifi_info(card->ospriv, "Unknown chip version\n"); | |
1342 | return CSR_RESULT_FAILURE; | |
1343 | } | |
1344 | ||
1345 | /* Ensure chip is awake or access to function 1 will fail */ | |
1346 | r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE); | |
1347 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1348 | { | |
1349 | return r; | |
1350 | } | |
1351 | if (r != CSR_RESULT_SUCCESS) | |
1352 | { | |
1353 | unifi_error(card->ospriv, "unifi_set_host_state() failed %d\n", r); | |
1354 | return CSR_RESULT_FAILURE; /* Card is probably unpowered */ | |
1355 | } | |
1356 | CsrThreadSleep(20); | |
1357 | ||
1358 | for (i = 0; i < 3; i++) | |
1359 | { | |
1360 | sr = CsrSdioRead16(card->sdio_if, CHIP_HELPER_UNIFI_GBL_CHIP_VERSION * 2, &data_u16); | |
1361 | if (sr != CSR_RESULT_SUCCESS || data_u16 != card->chip_version) | |
1362 | { | |
1363 | unifi_info(card->ospriv, "Failed to read valid chip version sr=%d (0x%04x want 0x%04x) try %d\n", | |
1364 | sr, data_u16, card->chip_version, i); | |
1365 | ||
1366 | /* Set clock speed low */ | |
1367 | sr = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_SAFE_HZ); | |
1368 | if (sr != CSR_RESULT_SUCCESS) | |
1369 | { | |
1370 | unifi_error(card->ospriv, "CsrSdioMaxBusClockFrequencySet() failed1 %d\n", sr); | |
1371 | r = ConvertCsrSdioToCsrHipResult(card, sr); | |
1372 | } | |
1373 | card->sdio_clock_speed = UNIFI_SDIO_CLOCK_SAFE_HZ; | |
1374 | ||
1375 | /* First try re-enabling function in case a f/w watchdog reset disabled it */ | |
1376 | if (i == 0) | |
1377 | { | |
1378 | unifi_info(card->ospriv, "Try function enable\n"); | |
1379 | sr = CsrSdioFunctionEnable(card->sdio_if); | |
1380 | if (sr != CSR_RESULT_SUCCESS) | |
1381 | { | |
1382 | r = ConvertCsrSdioToCsrHipResult(card, sr); | |
1383 | unifi_error(card->ospriv, "CsrSdioFunctionEnable failed %d (HIP %d)\n", sr, r); | |
1384 | } | |
1385 | continue; | |
1386 | } | |
1387 | ||
1388 | /* Second try, set awake */ | |
1389 | unifi_info(card->ospriv, "Try set awake\n"); | |
1390 | ||
1391 | /* Ensure chip is awake */ | |
1392 | r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE); | |
1393 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1394 | { | |
1395 | return r; | |
1396 | } | |
1397 | if (r != CSR_RESULT_SUCCESS) | |
1398 | { | |
1399 | unifi_error(card->ospriv, "unifi_set_host_state() failed2 %d\n", r); | |
1400 | } | |
1401 | ||
1402 | /* Set clock speed low in case setting the host state raised it, which | |
1403 | * would only happen if host state was previously TORPID | |
1404 | */ | |
1405 | sr = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_SAFE_HZ); | |
1406 | if (sr != CSR_RESULT_SUCCESS) | |
1407 | { | |
1408 | unifi_error(card->ospriv, "CsrSdioMaxBusClockFrequencySet() failed2 %d\n", sr); | |
1409 | } | |
1410 | card->sdio_clock_speed = UNIFI_SDIO_CLOCK_SAFE_HZ; | |
1411 | ||
1412 | if (i == 1) | |
1413 | { | |
1414 | continue; | |
1415 | } | |
1416 | ||
1417 | /* Perform a s/w reset to preserve as much as the card state as possible, | |
1418 | * (mainly the preserve RAM). The context will be lost for coredump - but as we | |
1419 | * were unable to access the WLAN function for panic, the coredump would have | |
1420 | * also failed without a reset. | |
1421 | */ | |
1422 | unifi_info(card->ospriv, "Try s/w reset\n"); | |
1423 | ||
1424 | r = unifi_card_hard_reset(card); | |
1425 | if (r != CSR_RESULT_SUCCESS) | |
1426 | { | |
1427 | unifi_error(card->ospriv, "unifi_card_hard_reset() failed %d\n", r); | |
1428 | } | |
1429 | } | |
1430 | else | |
1431 | { | |
1432 | if (i > 0) | |
1433 | { | |
1434 | unifi_info(card->ospriv, "Read chip version 0x%x after %d retries\n", data_u16, i); | |
1435 | } | |
1436 | break; | |
1437 | } | |
1438 | } | |
1439 | ||
1440 | r = ConvertCsrSdioToCsrHipResult(card, sr); | |
635d2b00 GKH |
1441 | return r; |
1442 | } | |
1443 | ||
1444 | ||
1445 | /* | |
1446 | * --------------------------------------------------------------------------- | |
1447 | * unifi_read_panic | |
1448 | * Reads, saves and prints panic codes stored by the firmware in UniFi's | |
1449 | * preserve RAM by the last panic that occurred since chip was powered. | |
1450 | * Nothing is saved if the panic codes are read as zero. | |
1451 | * | |
1452 | * Arguments: | |
1453 | * card Pointer to card struct | |
1454 | * | |
1455 | * Returns: | |
1456 | * --------------------------------------------------------------------------- | |
1457 | */ | |
1458 | void unifi_read_panic(card_t *card) | |
1459 | { | |
1460 | CsrResult r; | |
8c87f69a | 1461 | u16 p_code, p_arg; |
635d2b00 | 1462 | |
635d2b00 GKH |
1463 | /* The firmware must have previously initialised to read the panic addresses |
1464 | * from the SLUT | |
1465 | */ | |
1466 | if (!card->panic_data_phy_addr || !card->panic_data_mac_addr) | |
1467 | { | |
1468 | return; | |
1469 | } | |
1470 | ||
1471 | /* Get the panic data from PHY */ | |
1472 | r = unifi_card_read16(card, card->panic_data_phy_addr, &p_code); | |
1473 | if (r != CSR_RESULT_SUCCESS) | |
1474 | { | |
1475 | unifi_error(card->ospriv, "capture_panic: unifi_read16 %08x failed %d\n", card->panic_data_phy_addr, r); | |
1476 | p_code = 0; | |
1477 | } | |
1478 | if (p_code) | |
1479 | { | |
1480 | r = unifi_card_read16(card, card->panic_data_phy_addr + 2, &p_arg); | |
1481 | if (r != CSR_RESULT_SUCCESS) | |
1482 | { | |
1483 | unifi_error(card->ospriv, "capture_panic: unifi_read16 %08x failed %d\n", card->panic_data_phy_addr + 2, r); | |
1484 | } | |
1485 | unifi_error(card->ospriv, "Last UniFi PHY PANIC %04x arg %04x\n", p_code, p_arg); | |
1486 | card->last_phy_panic_code = p_code; | |
1487 | card->last_phy_panic_arg = p_arg; | |
1488 | } | |
1489 | ||
1490 | /* Get the panic data from MAC */ | |
1491 | r = unifi_card_read16(card, card->panic_data_mac_addr, &p_code); | |
1492 | if (r != CSR_RESULT_SUCCESS) | |
1493 | { | |
1494 | unifi_error(card->ospriv, "capture_panic: unifi_read16 %08x failed %d\n", card->panic_data_mac_addr, r); | |
1495 | p_code = 0; | |
1496 | } | |
1497 | if (p_code) | |
1498 | { | |
1499 | r = unifi_card_read16(card, card->panic_data_mac_addr + 2, &p_arg); | |
1500 | if (r != CSR_RESULT_SUCCESS) | |
1501 | { | |
1502 | unifi_error(card->ospriv, "capture_panic: unifi_read16 %08x failed %d\n", card->panic_data_mac_addr + 2, r); | |
1503 | } | |
1504 | unifi_error(card->ospriv, "Last UniFi MAC PANIC %04x arg %04x\n", p_code, p_arg); | |
1505 | card->last_mac_panic_code = p_code; | |
1506 | card->last_mac_panic_arg = p_arg; | |
1507 | } | |
1508 | ||
635d2b00 GKH |
1509 | } |
1510 | ||
1511 | ||
1512 | /* | |
1513 | * --------------------------------------------------------------------------- | |
1514 | * card_allocate_memory_resources | |
1515 | * | |
1516 | * Allocates memory for the from-host, to-host bulk data slots, | |
1517 | * soft queue buffers and bulk data buffers. | |
1518 | * | |
1519 | * Arguments: | |
1520 | * card Pointer to card struct | |
1521 | * | |
1522 | * Returns: | |
1523 | * CSR_RESULT_SUCCESS on success, CSR error code on failure. | |
1524 | * --------------------------------------------------------------------------- | |
1525 | */ | |
1526 | static CsrResult card_allocate_memory_resources(card_t *card) | |
1527 | { | |
ab2b8c73 | 1528 | s16 n, i, k, r; |
635d2b00 GKH |
1529 | sdio_config_data_t *cfg_data; |
1530 | ||
635d2b00 GKH |
1531 | /* Reset any state carried forward from a previous life */ |
1532 | card->fh_command_queue.q_rd_ptr = 0; | |
1533 | card->fh_command_queue.q_wr_ptr = 0; | |
c4f9e644 | 1534 | (void)scnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH, |
95edd09e | 1535 | "fh_cmd_q"); |
635d2b00 GKH |
1536 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) |
1537 | { | |
1538 | card->fh_traffic_queue[i].q_rd_ptr = 0; | |
1539 | card->fh_traffic_queue[i].q_wr_ptr = 0; | |
c4f9e644 | 1540 | (void)scnprintf(card->fh_traffic_queue[i].name, |
95edd09e | 1541 | UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i); |
635d2b00 GKH |
1542 | } |
1543 | #ifndef CSR_WIFI_HIP_TA_DISABLE | |
1544 | unifi_ta_sampling_init(card); | |
1545 | #endif | |
1546 | /* Convenience short-cut */ | |
1547 | cfg_data = &card->config_data; | |
1548 | ||
1549 | /* | |
1550 | * Allocate memory for the from-host and to-host signal buffers. | |
1551 | */ | |
4becf12d | 1552 | card->fh_buffer.buf = kmalloc(UNIFI_FH_BUF_SIZE, GFP_KERNEL); |
635d2b00 GKH |
1553 | if (card->fh_buffer.buf == NULL) |
1554 | { | |
1555 | unifi_error(card->ospriv, "Failed to allocate memory for F-H signals\n"); | |
635d2b00 GKH |
1556 | return CSR_WIFI_HIP_RESULT_NO_MEMORY; |
1557 | } | |
1558 | card->fh_buffer.bufsize = UNIFI_FH_BUF_SIZE; | |
1559 | card->fh_buffer.ptr = card->fh_buffer.buf; | |
1560 | card->fh_buffer.count = 0; | |
1561 | ||
4becf12d | 1562 | card->th_buffer.buf = kmalloc(UNIFI_FH_BUF_SIZE, GFP_KERNEL); |
635d2b00 GKH |
1563 | if (card->th_buffer.buf == NULL) |
1564 | { | |
1565 | unifi_error(card->ospriv, "Failed to allocate memory for T-H signals\n"); | |
635d2b00 GKH |
1566 | return CSR_WIFI_HIP_RESULT_NO_MEMORY; |
1567 | } | |
1568 | card->th_buffer.bufsize = UNIFI_FH_BUF_SIZE; | |
1569 | card->th_buffer.ptr = card->th_buffer.buf; | |
1570 | card->th_buffer.count = 0; | |
1571 | ||
1572 | ||
1573 | /* | |
1574 | * Allocate memory for the from-host and to-host bulk data slots. | |
786eeeb3 | 1575 | * This is done as separate kmallocs because lots of smaller |
635d2b00 GKH |
1576 | * allocations are more likely to succeed than one huge one. |
1577 | */ | |
1578 | ||
1579 | /* Allocate memory for the array of pointers */ | |
1580 | n = cfg_data->num_fromhost_data_slots; | |
1581 | ||
1582 | unifi_trace(card->ospriv, UDBG3, "Alloc from-host resources, %d slots.\n", n); | |
70128792 | 1583 | card->from_host_data = kmalloc(n * sizeof(slot_desc_t), GFP_KERNEL); |
635d2b00 GKH |
1584 | if (card->from_host_data == NULL) |
1585 | { | |
1586 | unifi_error(card->ospriv, "Failed to allocate memory for F-H bulk data array\n"); | |
635d2b00 GKH |
1587 | return CSR_WIFI_HIP_RESULT_NO_MEMORY; |
1588 | } | |
1589 | ||
1590 | /* Initialise from-host bulk data slots */ | |
1591 | for (i = 0; i < n; i++) | |
1592 | { | |
1593 | UNIFI_INIT_BULK_DATA(&card->from_host_data[i].bd); | |
1594 | } | |
1595 | ||
1596 | /* Allocate memory for the array used for slot host tag mapping */ | |
70128792 | 1597 | card->fh_slot_host_tag_record = kmalloc(n * sizeof(u32), GFP_KERNEL); |
635d2b00 GKH |
1598 | |
1599 | if (card->fh_slot_host_tag_record == NULL) | |
1600 | { | |
1601 | unifi_error(card->ospriv, "Failed to allocate memory for F-H slot host tag mapping array\n"); | |
635d2b00 GKH |
1602 | return CSR_WIFI_HIP_RESULT_NO_MEMORY; |
1603 | } | |
1604 | ||
95edd09e GKH |
1605 | /* Initialise host tag entries for from-host bulk data slots */ |
1606 | for (i = 0; i < n; i++) | |
1607 | { | |
1608 | card->fh_slot_host_tag_record[i] = CSR_WIFI_HIP_RESERVED_HOST_TAG; | |
1609 | } | |
1610 | ||
635d2b00 GKH |
1611 | |
1612 | /* Allocate memory for the array of pointers */ | |
1613 | n = cfg_data->num_tohost_data_slots; | |
1614 | ||
1615 | unifi_trace(card->ospriv, UDBG3, "Alloc to-host resources, %d slots.\n", n); | |
70128792 | 1616 | card->to_host_data = kmalloc(n * sizeof(bulk_data_desc_t), GFP_KERNEL); |
635d2b00 GKH |
1617 | if (card->to_host_data == NULL) |
1618 | { | |
1619 | unifi_error(card->ospriv, "Failed to allocate memory for T-H bulk data array\n"); | |
635d2b00 GKH |
1620 | return CSR_WIFI_HIP_RESULT_NO_MEMORY; |
1621 | } | |
1622 | ||
1623 | /* Initialise to-host bulk data slots */ | |
1624 | for (i = 0; i < n; i++) | |
1625 | { | |
1626 | UNIFI_INIT_BULK_DATA(&card->to_host_data[i]); | |
1627 | } | |
1628 | ||
1629 | /* | |
1630 | * Initialise buffers for soft Q | |
1631 | */ | |
1632 | for (i = 0; i < UNIFI_SOFT_COMMAND_Q_LENGTH; i++) | |
1633 | { | |
1634 | for (r = 0; r < UNIFI_MAX_DATA_REFERENCES; r++) | |
1635 | { | |
1636 | UNIFI_INIT_BULK_DATA(&card->fh_command_q_body[i].bulkdata[r]); | |
1637 | } | |
1638 | } | |
1639 | ||
1640 | for (k = 0; k < UNIFI_NO_OF_TX_QS; k++) | |
1641 | { | |
1642 | for (i = 0; i < UNIFI_SOFT_TRAFFIC_Q_LENGTH; i++) | |
1643 | { | |
1644 | for (r = 0; r < UNIFI_MAX_DATA_REFERENCES; r++) | |
1645 | { | |
1646 | UNIFI_INIT_BULK_DATA(&card->fh_traffic_q_body[k][i].bulkdata[r]); | |
1647 | } | |
1648 | } | |
1649 | } | |
1650 | ||
1651 | card->memory_resources_allocated = 1; | |
1652 | ||
635d2b00 GKH |
1653 | return CSR_RESULT_SUCCESS; |
1654 | } /* card_allocate_memory_resources() */ | |
1655 | ||
1656 | ||
1657 | /* | |
1658 | * --------------------------------------------------------------------------- | |
1659 | * unifi_free_bulk_data | |
1660 | * | |
1661 | * Free the data associated to a bulk data structure. | |
1662 | * | |
1663 | * Arguments: | |
1664 | * card Pointer to card struct | |
1665 | * bulk_data_slot Pointer to bulk data structure | |
1666 | * | |
1667 | * Returns: | |
1668 | * None. | |
1669 | * | |
1670 | * --------------------------------------------------------------------------- | |
1671 | */ | |
1672 | static void unifi_free_bulk_data(card_t *card, bulk_data_desc_t *bulk_data_slot) | |
1673 | { | |
1674 | if (bulk_data_slot->data_length != 0) | |
1675 | { | |
1676 | unifi_net_data_free(card->ospriv, bulk_data_slot); | |
1677 | } | |
1678 | } /* unifi_free_bulk_data() */ | |
1679 | ||
1680 | ||
1681 | /* | |
1682 | * --------------------------------------------------------------------------- | |
1683 | * card_free_memory_resources | |
1684 | * | |
1685 | * Frees memory allocated for the from-host, to-host bulk data slots, | |
1686 | * soft queue buffers and bulk data buffers. | |
1687 | * | |
1688 | * Arguments: | |
1689 | * card Pointer to card struct | |
1690 | * | |
1691 | * Returns: | |
1692 | * None. | |
1693 | * --------------------------------------------------------------------------- | |
1694 | */ | |
1695 | static void card_free_memory_resources(card_t *card) | |
1696 | { | |
635d2b00 GKH |
1697 | |
1698 | unifi_trace(card->ospriv, UDBG1, "Freeing card memory resources.\n"); | |
1699 | ||
1700 | /* Clear our internal queues */ | |
1701 | unifi_cancel_pending_signals(card); | |
1702 | ||
1703 | ||
4fe9db37 GKH |
1704 | kfree(card->to_host_data); |
1705 | card->to_host_data = NULL; | |
635d2b00 | 1706 | |
4fe9db37 GKH |
1707 | kfree(card->from_host_data); |
1708 | card->from_host_data = NULL; | |
635d2b00 GKH |
1709 | |
1710 | /* free the memory for slot host tag mapping array */ | |
4fe9db37 GKH |
1711 | kfree(card->fh_slot_host_tag_record); |
1712 | card->fh_slot_host_tag_record = NULL; | |
635d2b00 | 1713 | |
4fe9db37 | 1714 | kfree(card->fh_buffer.buf); |
635d2b00 GKH |
1715 | card->fh_buffer.ptr = card->fh_buffer.buf = NULL; |
1716 | card->fh_buffer.bufsize = 0; | |
1717 | card->fh_buffer.count = 0; | |
1718 | ||
4fe9db37 | 1719 | kfree(card->th_buffer.buf); |
635d2b00 GKH |
1720 | card->th_buffer.ptr = card->th_buffer.buf = NULL; |
1721 | card->th_buffer.bufsize = 0; | |
1722 | card->th_buffer.count = 0; | |
1723 | ||
1724 | ||
1725 | card->memory_resources_allocated = 0; | |
1726 | ||
635d2b00 GKH |
1727 | } /* card_free_memory_resources() */ |
1728 | ||
1729 | ||
1730 | static void card_init_soft_queues(card_t *card) | |
1731 | { | |
ab2b8c73 | 1732 | s16 i; |
635d2b00 | 1733 | |
635d2b00 GKH |
1734 | unifi_trace(card->ospriv, UDBG1, "Initialising internal signal queues.\n"); |
1735 | /* Reset any state carried forward from a previous life */ | |
1736 | card->fh_command_queue.q_rd_ptr = 0; | |
1737 | card->fh_command_queue.q_wr_ptr = 0; | |
c4f9e644 | 1738 | (void)scnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH, |
95edd09e | 1739 | "fh_cmd_q"); |
635d2b00 GKH |
1740 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) |
1741 | { | |
1742 | card->fh_traffic_queue[i].q_rd_ptr = 0; | |
1743 | card->fh_traffic_queue[i].q_wr_ptr = 0; | |
c4f9e644 | 1744 | (void)scnprintf(card->fh_traffic_queue[i].name, |
95edd09e | 1745 | UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i); |
635d2b00 GKH |
1746 | } |
1747 | #ifndef CSR_WIFI_HIP_TA_DISABLE | |
1748 | unifi_ta_sampling_init(card); | |
1749 | #endif | |
635d2b00 GKH |
1750 | } |
1751 | ||
1752 | ||
1753 | /* | |
1754 | * --------------------------------------------------------------------------- | |
1755 | * unifi_cancel_pending_signals | |
1756 | * | |
1757 | * Free the signals and associated bulk data, pending in the core. | |
1758 | * | |
1759 | * Arguments: | |
1760 | * card Pointer to card struct | |
1761 | * | |
1762 | * Returns: | |
1763 | * None. | |
1764 | * --------------------------------------------------------------------------- | |
1765 | */ | |
1766 | void unifi_cancel_pending_signals(card_t *card) | |
1767 | { | |
ab2b8c73 | 1768 | s16 i, n, r; |
635d2b00 GKH |
1769 | |
1770 | unifi_trace(card->ospriv, UDBG1, "Canceling pending signals.\n"); | |
1771 | ||
1772 | if (card->to_host_data) | |
1773 | { | |
1774 | /* | |
1775 | * Free any bulk data buffers allocated for the t-h slots | |
1776 | * This will clear all buffers that did not make it to | |
1777 | * unifi_receive_event() before cancel was request. | |
1778 | */ | |
1779 | n = card->config_data.num_tohost_data_slots; | |
1780 | unifi_trace(card->ospriv, UDBG3, "Freeing to-host resources, %d slots.\n", n); | |
1781 | for (i = 0; i < n; i++) | |
1782 | { | |
1783 | unifi_free_bulk_data(card, &card->to_host_data[i]); | |
1784 | } | |
1785 | } | |
1786 | ||
1787 | /* | |
1788 | * If any of the from-host bulk data has reached the card->from_host_data | |
1789 | * but not UniFi, we need to free the buffers here. | |
1790 | */ | |
1791 | if (card->from_host_data) | |
1792 | { | |
1793 | /* Free any bulk data buffers allocated for the f-h slots */ | |
1794 | n = card->config_data.num_fromhost_data_slots; | |
1795 | unifi_trace(card->ospriv, UDBG3, "Freeing from-host resources, %d slots.\n", n); | |
1796 | for (i = 0; i < n; i++) | |
1797 | { | |
1798 | unifi_free_bulk_data(card, &card->from_host_data[i].bd); | |
1799 | } | |
1800 | ||
1801 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) | |
1802 | { | |
1803 | card->dynamic_slot_data.from_host_used_slots[i] = 0; | |
1804 | card->dynamic_slot_data.from_host_max_slots[i] = 0; | |
1805 | card->dynamic_slot_data.from_host_reserved_slots[i] = 0; | |
1806 | } | |
1807 | } | |
1808 | ||
1809 | /* | |
1810 | * Free any bulk data buffers allocated in the soft queues. | |
1811 | * This covers the case where a bulk data pointer has reached the soft queue | |
1812 | * but not the card->from_host_data. | |
1813 | */ | |
1814 | unifi_trace(card->ospriv, UDBG3, "Freeing cmd q resources.\n"); | |
1815 | for (i = 0; i < UNIFI_SOFT_COMMAND_Q_LENGTH; i++) | |
1816 | { | |
1817 | for (r = 0; r < UNIFI_MAX_DATA_REFERENCES; r++) | |
1818 | { | |
1819 | unifi_free_bulk_data(card, &card->fh_command_q_body[i].bulkdata[r]); | |
1820 | } | |
1821 | } | |
1822 | ||
1823 | unifi_trace(card->ospriv, UDBG3, "Freeing traffic q resources.\n"); | |
1824 | for (n = 0; n < UNIFI_NO_OF_TX_QS; n++) | |
1825 | { | |
1826 | for (i = 0; i < UNIFI_SOFT_TRAFFIC_Q_LENGTH; i++) | |
1827 | { | |
1828 | for (r = 0; r < UNIFI_MAX_DATA_REFERENCES; r++) | |
1829 | { | |
1830 | unifi_free_bulk_data(card, &card->fh_traffic_q_body[n][i].bulkdata[r]); | |
1831 | } | |
1832 | } | |
1833 | } | |
1834 | ||
1835 | card_init_soft_queues(card); | |
1836 | ||
635d2b00 GKH |
1837 | } /* unifi_cancel_pending_signals() */ |
1838 | ||
1839 | ||
1840 | /* | |
1841 | * --------------------------------------------------------------------------- | |
1842 | * unifi_free_card | |
1843 | * | |
1844 | * Free the memory allocated for the card structure and buffers. | |
1845 | * | |
1846 | * Notes: | |
1847 | * The porting layer is responsible for freeing any mini-coredump buffers | |
1848 | * allocated when it called unifi_coredump_init(), by calling | |
1849 | * unifi_coredump_free() before calling this function. | |
1850 | * | |
1851 | * Arguments: | |
1852 | * card Pointer to card struct | |
1853 | * | |
1854 | * Returns: | |
1855 | * None. | |
1856 | * --------------------------------------------------------------------------- | |
1857 | */ | |
1858 | void unifi_free_card(card_t *card) | |
1859 | { | |
635d2b00 GKH |
1860 | #ifdef CSR_PRE_ALLOC_NET_DATA |
1861 | prealloc_netdata_free(card); | |
1862 | #endif | |
1863 | /* Free any memory allocated. */ | |
1864 | card_free_memory_resources(card); | |
1865 | ||
1866 | /* Warn if caller didn't free coredump buffers */ | |
1867 | if (card->dump_buf) | |
1868 | { | |
1869 | unifi_error(card->ospriv, "Caller should call unifi_coredump_free()\n"); | |
1870 | unifi_coredump_free(card); /* free anyway to prevent memory leak */ | |
1871 | } | |
1872 | ||
4fe9db37 | 1873 | kfree(card); |
635d2b00 | 1874 | |
635d2b00 GKH |
1875 | } /* unifi_free_card() */ |
1876 | ||
1877 | ||
1878 | /* | |
1879 | * --------------------------------------------------------------------------- | |
1880 | * card_init_slots | |
1881 | * | |
1882 | * Allocate memory for host-side slot data and signal queues. | |
1883 | * | |
1884 | * Arguments: | |
1885 | * card Pointer to card object | |
1886 | * | |
1887 | * Returns: | |
1888 | * CSR error code. | |
1889 | * --------------------------------------------------------------------------- | |
1890 | */ | |
1891 | static CsrResult card_init_slots(card_t *card) | |
1892 | { | |
1893 | CsrResult r; | |
7e6f5794 | 1894 | u8 i; |
635d2b00 | 1895 | |
635d2b00 GKH |
1896 | /* Allocate the buffers we need, only once. */ |
1897 | if (card->memory_resources_allocated == 1) | |
1898 | { | |
1899 | card_free_memory_resources(card); | |
1900 | } | |
1901 | else | |
1902 | { | |
1903 | /* Initialise our internal command and traffic queues */ | |
1904 | card_init_soft_queues(card); | |
1905 | } | |
1906 | ||
1907 | r = card_allocate_memory_resources(card); | |
1908 | if (r != CSR_RESULT_SUCCESS) | |
1909 | { | |
1910 | unifi_error(card->ospriv, "Failed to allocate card memory resources.\n"); | |
1911 | card_free_memory_resources(card); | |
635d2b00 GKH |
1912 | return r; |
1913 | } | |
1914 | ||
1915 | if (card->sdio_ctrl_addr == 0) | |
1916 | { | |
1917 | unifi_error(card->ospriv, "Failed to find config struct!\n"); | |
635d2b00 GKH |
1918 | return CSR_WIFI_HIP_RESULT_INVALID_VALUE; |
1919 | } | |
1920 | ||
1921 | /* | |
1922 | * Set initial counts. | |
1923 | */ | |
1924 | ||
1925 | card->from_host_data_head = 0; | |
1926 | ||
1927 | /* Get initial signal counts from UniFi, in case it has not been reset. */ | |
1928 | { | |
8c87f69a | 1929 | u16 s; |
635d2b00 GKH |
1930 | |
1931 | /* Get the from-host-signals-written count */ | |
1932 | r = unifi_card_read16(card, card->sdio_ctrl_addr + 0, &s); | |
1933 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1934 | { | |
1935 | return r; | |
1936 | } | |
1937 | if (r != CSR_RESULT_SUCCESS) | |
1938 | { | |
1939 | unifi_error(card->ospriv, "Failed to read from-host sig written count\n"); | |
635d2b00 GKH |
1940 | return r; |
1941 | } | |
ab2b8c73 | 1942 | card->from_host_signals_w = (s16)s; |
635d2b00 GKH |
1943 | |
1944 | /* Get the to-host-signals-written count */ | |
1945 | r = unifi_card_read16(card, card->sdio_ctrl_addr + 6, &s); | |
1946 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1947 | { | |
1948 | return r; | |
1949 | } | |
1950 | if (r != CSR_RESULT_SUCCESS) | |
1951 | { | |
1952 | unifi_error(card->ospriv, "Failed to read to-host sig read count\n"); | |
635d2b00 GKH |
1953 | return r; |
1954 | } | |
ab2b8c73 | 1955 | card->to_host_signals_r = (s16)s; |
635d2b00 GKH |
1956 | } |
1957 | ||
1958 | /* Set Initialised flag. */ | |
1959 | r = unifi_card_write16(card, card->init_flag_addr, 0x0001); | |
1960 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
1961 | { | |
1962 | return r; | |
1963 | } | |
1964 | if (r != CSR_RESULT_SUCCESS) | |
1965 | { | |
1966 | unifi_error(card->ospriv, "Failed to write initialised flag\n"); | |
635d2b00 GKH |
1967 | return r; |
1968 | } | |
1969 | ||
1970 | /* Dynamic queue reservation */ | |
b7244a31 | 1971 | memset(&card->dynamic_slot_data, 0, sizeof(card_dynamic_slot_t)); |
635d2b00 GKH |
1972 | |
1973 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) | |
1974 | { | |
1975 | card->dynamic_slot_data.from_host_max_slots[i] = card->config_data.num_fromhost_data_slots - | |
1976 | UNIFI_RESERVED_COMMAND_SLOTS; | |
1977 | card->dynamic_slot_data.queue_stable[i] = FALSE; | |
1978 | } | |
1979 | ||
1980 | card->dynamic_slot_data.packets_interval = UNIFI_PACKETS_INTERVAL; | |
1981 | ||
635d2b00 GKH |
1982 | return CSR_RESULT_SUCCESS; |
1983 | } /* card_init_slots() */ | |
1984 | ||
1985 | ||
1986 | /* | |
1987 | * --------------------------------------------------------------------------- | |
1988 | * unifi_set_udi_hook | |
1989 | * | |
1990 | * Registers the udi hook that reports the sent signals to the core. | |
1991 | * | |
1992 | * Arguments: | |
1993 | * card Pointer to the card context struct | |
1994 | * udi_fn Pointer to the callback function. | |
1995 | * | |
1996 | * Returns: | |
1997 | * CSR_WIFI_HIP_RESULT_INVALID_VALUE if the card pointer is invalid, | |
1998 | * CSR_RESULT_SUCCESS on success. | |
1999 | * --------------------------------------------------------------------------- | |
2000 | */ | |
2001 | CsrResult unifi_set_udi_hook(card_t *card, udi_func_t udi_fn) | |
2002 | { | |
2003 | if (card == NULL) | |
2004 | { | |
2005 | return CSR_WIFI_HIP_RESULT_INVALID_VALUE; | |
2006 | } | |
2007 | ||
2008 | if (card->udi_hook == NULL) | |
2009 | { | |
2010 | card->udi_hook = udi_fn; | |
2011 | } | |
2012 | ||
2013 | return CSR_RESULT_SUCCESS; | |
2014 | } /* unifi_set_udi_hook() */ | |
2015 | ||
2016 | ||
2017 | /* | |
2018 | * --------------------------------------------------------------------------- | |
2019 | * unifi_remove_udi_hook | |
2020 | * | |
2021 | * Removes the udi hook that reports the sent signals from the core. | |
2022 | * | |
2023 | * Arguments: | |
2024 | * card Pointer to the card context struct | |
2025 | * udi_fn Pointer to the callback function. | |
2026 | * | |
2027 | * Returns: | |
2028 | * CSR_WIFI_HIP_RESULT_INVALID_VALUE if the card pointer is invalid, | |
2029 | * CSR_RESULT_SUCCESS on success. | |
2030 | * --------------------------------------------------------------------------- | |
2031 | */ | |
2032 | CsrResult unifi_remove_udi_hook(card_t *card, udi_func_t udi_fn) | |
2033 | { | |
2034 | if (card == NULL) | |
2035 | { | |
2036 | return CSR_WIFI_HIP_RESULT_INVALID_VALUE; | |
2037 | } | |
2038 | ||
2039 | if (card->udi_hook == udi_fn) | |
2040 | { | |
2041 | card->udi_hook = NULL; | |
2042 | } | |
2043 | ||
2044 | return CSR_RESULT_SUCCESS; | |
2045 | } /* unifi_remove_udi_hook() */ | |
2046 | ||
2047 | ||
2048 | static void CardReassignDynamicReservation(card_t *card) | |
2049 | { | |
7e6f5794 | 2050 | u8 i; |
635d2b00 | 2051 | |
635d2b00 GKH |
2052 | unifi_trace(card->ospriv, UDBG5, "Packets Txed %d %d %d %d\n", |
2053 | card->dynamic_slot_data.packets_txed[0], | |
2054 | card->dynamic_slot_data.packets_txed[1], | |
2055 | card->dynamic_slot_data.packets_txed[2], | |
2056 | card->dynamic_slot_data.packets_txed[3]); | |
2057 | ||
2058 | /* Clear reservation and recalculate max slots */ | |
2059 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) | |
2060 | { | |
2061 | card->dynamic_slot_data.queue_stable[i] = FALSE; | |
2062 | card->dynamic_slot_data.from_host_reserved_slots[i] = 0; | |
2063 | card->dynamic_slot_data.from_host_max_slots[i] = card->config_data.num_fromhost_data_slots - | |
2064 | UNIFI_RESERVED_COMMAND_SLOTS; | |
2065 | card->dynamic_slot_data.packets_txed[i] = 0; | |
2066 | ||
2067 | unifi_trace(card->ospriv, UDBG5, "CardReassignDynamicReservation: queue %d reserved %d Max %d\n", i, | |
2068 | card->dynamic_slot_data.from_host_reserved_slots[i], | |
2069 | card->dynamic_slot_data.from_host_max_slots[i]); | |
2070 | } | |
2071 | ||
2072 | card->dynamic_slot_data.total_packets_txed = 0; | |
635d2b00 GKH |
2073 | } |
2074 | ||
2075 | ||
2076 | /* Algorithm to dynamically reserve slots. The logic is based mainly on the outstanding queue | |
2077 | * length. Slots are reserved for particular queues during an interval and cleared after the interval. | |
2078 | * Each queue has three associated variables.. a) used slots - the number of slots currently occupied | |
2079 | * by the queue b) reserved slots - number of slots reserved specifically for the queue c) max slots - total | |
2080 | * slots that this queue can actually use (may be higher than reserved slots and is dependent on reserved slots | |
2081 | * for other queues). | |
2082 | * This function is called when there are no slots available for a queue. It checks to see if there are enough | |
2083 | * unreserved slots sufficient for this request. If available these slots are reserved for the queue. | |
2084 | * If there are not enough unreserved slots, a fair share for each queue is calculated based on the total slots | |
2085 | * and the number of active queues (any queue with existing reservation is considered active). Queues needing | |
2086 | * less than their fair share are allowed to have the previously reserved slots. The remaining slots are | |
2087 | * distributed evenly among queues that need more than the fair share | |
2088 | * | |
2089 | * A better scheme would take current bandwidth per AC into consideration when reserving slots. An | |
2090 | * implementation scheme could consider the relative time/service period for slots in an AC. If the firmware | |
2091 | * services other ACs faster than a particular AC (packets wait in the slots longer) then it is fair to reserve | |
2092 | * less slots for the AC | |
2093 | */ | |
2094 | static void CardCheckDynamicReservation(card_t *card, unifi_TrafficQueue queue) | |
2095 | { | |
8c87f69a | 2096 | u16 q_len, active_queues = 0, excess_queue_slots, div_extra_slots, |
635d2b00 | 2097 | queue_fair_share, reserved_slots = 0, q, excess_need_queues = 0, unmovable_slots = 0; |
95e326c2 | 2098 | s32 i; |
635d2b00 | 2099 | q_t *sigq; |
8c87f69a | 2100 | u16 num_data_slots = card->config_data.num_fromhost_data_slots - UNIFI_RESERVED_COMMAND_SLOTS; |
635d2b00 | 2101 | |
635d2b00 GKH |
2102 | /* Calculate the pending queue length */ |
2103 | sigq = &card->fh_traffic_queue[queue]; | |
2104 | q_len = CSR_WIFI_HIP_Q_SLOTS_USED(sigq); | |
2105 | ||
2106 | if (q_len <= card->dynamic_slot_data.from_host_reserved_slots[queue]) | |
2107 | { | |
2108 | unifi_trace(card->ospriv, UDBG5, "queue %d q_len %d already has that many reserved slots, exiting\n", queue, q_len); | |
635d2b00 GKH |
2109 | return; |
2110 | } | |
2111 | ||
2112 | /* Upper limit */ | |
2113 | if (q_len > num_data_slots) | |
2114 | { | |
2115 | q_len = num_data_slots; | |
2116 | } | |
2117 | ||
2118 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) | |
2119 | { | |
95e326c2 | 2120 | if (i != (s32)queue) |
635d2b00 GKH |
2121 | { |
2122 | reserved_slots += card->dynamic_slot_data.from_host_reserved_slots[i]; | |
2123 | } | |
95e326c2 | 2124 | if ((i == (s32)queue) || (card->dynamic_slot_data.from_host_reserved_slots[i] > 0)) |
635d2b00 GKH |
2125 | { |
2126 | active_queues++; | |
2127 | } | |
2128 | } | |
2129 | ||
2130 | unifi_trace(card->ospriv, UDBG5, "CardCheckDynamicReservation: queue %d q_len %d\n", queue, q_len); | |
2131 | unifi_trace(card->ospriv, UDBG5, "Active queues %d reserved slots on other queues %d\n", | |
2132 | active_queues, reserved_slots); | |
2133 | ||
2134 | if (reserved_slots + q_len <= num_data_slots) | |
2135 | { | |
2136 | card->dynamic_slot_data.from_host_reserved_slots[queue] = q_len; | |
2137 | if (q_len == num_data_slots) | |
2138 | { | |
2139 | /* This is the common case when just 1 stream is going */ | |
2140 | card->dynamic_slot_data.queue_stable[queue] = TRUE; | |
2141 | } | |
2142 | } | |
2143 | else | |
2144 | { | |
2145 | queue_fair_share = num_data_slots / active_queues; | |
2146 | unifi_trace(card->ospriv, UDBG5, "queue fair share %d\n", queue_fair_share); | |
2147 | ||
2148 | /* Evenly distribute slots among active queues */ | |
2149 | /* Find out the queues that need excess of fair share. Also find slots allocated | |
2150 | * to queues less than their fair share, these slots cannot be reallocated (unmovable slots) */ | |
2151 | ||
2152 | card->dynamic_slot_data.from_host_reserved_slots[queue] = q_len; | |
2153 | ||
2154 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) | |
2155 | { | |
2156 | if (card->dynamic_slot_data.from_host_reserved_slots[i] > queue_fair_share) | |
2157 | { | |
2158 | excess_need_queues++; | |
2159 | } | |
2160 | else | |
2161 | { | |
2162 | unmovable_slots += card->dynamic_slot_data.from_host_reserved_slots[i]; | |
2163 | } | |
2164 | } | |
2165 | ||
2166 | unifi_trace(card->ospriv, UDBG5, "Excess need queues %d\n", excess_need_queues); | |
2167 | ||
2168 | /* Now find the slots per excess demand queue */ | |
2169 | excess_queue_slots = (num_data_slots - unmovable_slots) / excess_need_queues; | |
2170 | div_extra_slots = (num_data_slots - unmovable_slots) - excess_queue_slots * excess_need_queues; | |
2171 | for (i = UNIFI_NO_OF_TX_QS - 1; i >= 0; i--) | |
2172 | { | |
2173 | if (card->dynamic_slot_data.from_host_reserved_slots[i] > excess_queue_slots) | |
2174 | { | |
2175 | card->dynamic_slot_data.from_host_reserved_slots[i] = excess_queue_slots; | |
2176 | if (div_extra_slots > 0) | |
2177 | { | |
2178 | card->dynamic_slot_data.from_host_reserved_slots[i]++; | |
2179 | div_extra_slots--; | |
2180 | } | |
2181 | /* No more slots will be allocated to this queue during the current interval */ | |
2182 | card->dynamic_slot_data.queue_stable[i] = TRUE; | |
2183 | unifi_trace(card->ospriv, UDBG5, "queue stable %d\n", i); | |
2184 | } | |
2185 | } | |
2186 | } | |
2187 | ||
2188 | /* Redistribute max slots */ | |
2189 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) | |
2190 | { | |
2191 | reserved_slots = 0; | |
2192 | for (q = 0; q < UNIFI_NO_OF_TX_QS; q++) | |
2193 | { | |
2194 | if (i != q) | |
2195 | { | |
2196 | reserved_slots += card->dynamic_slot_data.from_host_reserved_slots[q]; | |
2197 | } | |
2198 | } | |
2199 | ||
2200 | card->dynamic_slot_data.from_host_max_slots[i] = num_data_slots - reserved_slots; | |
2201 | unifi_trace(card->ospriv, UDBG5, "queue %d reserved %d Max %d\n", i, | |
2202 | card->dynamic_slot_data.from_host_reserved_slots[i], | |
2203 | card->dynamic_slot_data.from_host_max_slots[i]); | |
2204 | } | |
2205 | ||
635d2b00 GKH |
2206 | } |
2207 | ||
2208 | ||
2209 | /* | |
2210 | * --------------------------------------------------------------------------- | |
2211 | * CardClearFromHostDataSlot | |
2212 | * | |
2213 | * Clear a the given data slot, making it available again. | |
2214 | * | |
2215 | * Arguments: | |
2216 | * card Pointer to Card object | |
2217 | * slot Index of the signal slot to clear. | |
2218 | * | |
2219 | * Returns: | |
2220 | * None. | |
2221 | * --------------------------------------------------------------------------- | |
2222 | */ | |
ab2b8c73 | 2223 | void CardClearFromHostDataSlot(card_t *card, const s16 slot) |
635d2b00 | 2224 | { |
7e6f5794 | 2225 | u8 queue = card->from_host_data[slot].queue; |
635d2b00 GKH |
2226 | const void *os_data_ptr = card->from_host_data[slot].bd.os_data_ptr; |
2227 | ||
635d2b00 GKH |
2228 | if (card->from_host_data[slot].bd.data_length == 0) |
2229 | { | |
2230 | unifi_warning(card->ospriv, | |
2231 | "Surprise: request to clear an already free FH data slot: %d\n", | |
2232 | slot); | |
635d2b00 GKH |
2233 | return; |
2234 | } | |
2235 | ||
2236 | if (os_data_ptr == NULL) | |
2237 | { | |
2238 | unifi_warning(card->ospriv, | |
2239 | "Clearing FH data slot %d: has null payload, len=%d\n", | |
2240 | slot, card->from_host_data[slot].bd.data_length); | |
2241 | } | |
2242 | ||
2243 | /* Free card->from_host_data[slot].bd.os_net_ptr here. */ | |
2244 | /* Mark slot as free by setting length to 0. */ | |
2245 | unifi_free_bulk_data(card, &card->from_host_data[slot].bd); | |
2246 | if (queue < UNIFI_NO_OF_TX_QS) | |
2247 | { | |
2248 | if (card->dynamic_slot_data.from_host_used_slots[queue] == 0) | |
2249 | { | |
2250 | unifi_error(card->ospriv, "Goofed up used slots q = %d used slots = %d\n", | |
2251 | queue, | |
2252 | card->dynamic_slot_data.from_host_used_slots[queue]); | |
2253 | } | |
2254 | else | |
2255 | { | |
2256 | card->dynamic_slot_data.from_host_used_slots[queue]--; | |
2257 | } | |
2258 | card->dynamic_slot_data.packets_txed[queue]++; | |
2259 | card->dynamic_slot_data.total_packets_txed++; | |
2260 | if (card->dynamic_slot_data.total_packets_txed >= card->dynamic_slot_data.packets_interval) | |
2261 | { | |
2262 | CardReassignDynamicReservation(card); | |
2263 | } | |
2264 | } | |
2265 | ||
2266 | unifi_trace(card->ospriv, UDBG4, "CardClearFromHostDataSlot: slot %d recycled %p\n", slot, os_data_ptr); | |
2267 | ||
635d2b00 GKH |
2268 | } /* CardClearFromHostDataSlot() */ |
2269 | ||
2270 | ||
95edd09e GKH |
2271 | #ifdef CSR_WIFI_REQUEUE_PACKET_TO_HAL |
2272 | /* | |
2273 | * --------------------------------------------------------------------------- | |
2274 | * CardClearFromHostDataSlotWithoutFreeingBulkData | |
2275 | * | |
2276 | * Clear the given data slot with out freeing the bulk data. | |
2277 | * | |
2278 | * Arguments: | |
2279 | * card Pointer to Card object | |
2280 | * slot Index of the signal slot to clear. | |
2281 | * | |
2282 | * Returns: | |
2283 | * None. | |
2284 | * --------------------------------------------------------------------------- | |
2285 | */ | |
ab2b8c73 | 2286 | void CardClearFromHostDataSlotWithoutFreeingBulkData(card_t *card, const s16 slot) |
95edd09e | 2287 | { |
7e6f5794 | 2288 | u8 queue = card->from_host_data[slot].queue; |
95edd09e GKH |
2289 | |
2290 | /* Initialise the from_host data slot so it can be re-used, | |
2291 | * Set length field in from_host_data array to 0. | |
2292 | */ | |
2293 | UNIFI_INIT_BULK_DATA(&card->from_host_data[slot].bd); | |
2294 | ||
2295 | queue = card->from_host_data[slot].queue; | |
2296 | ||
2297 | if (queue < UNIFI_NO_OF_TX_QS) | |
2298 | { | |
2299 | if (card->dynamic_slot_data.from_host_used_slots[queue] == 0) | |
2300 | { | |
2301 | unifi_error(card->ospriv, "Goofed up used slots q = %d used slots = %d\n", | |
2302 | queue, | |
2303 | card->dynamic_slot_data.from_host_used_slots[queue]); | |
2304 | } | |
2305 | else | |
2306 | { | |
2307 | card->dynamic_slot_data.from_host_used_slots[queue]--; | |
2308 | } | |
2309 | card->dynamic_slot_data.packets_txed[queue]++; | |
2310 | card->dynamic_slot_data.total_packets_txed++; | |
2311 | if (card->dynamic_slot_data.total_packets_txed >= | |
2312 | card->dynamic_slot_data.packets_interval) | |
2313 | { | |
2314 | CardReassignDynamicReservation(card); | |
2315 | } | |
2316 | } | |
2317 | } /* CardClearFromHostDataSlotWithoutFreeingBulkData() */ | |
2318 | ||
2319 | ||
2320 | #endif | |
2321 | ||
8c87f69a | 2322 | u16 CardGetDataSlotSize(card_t *card) |
635d2b00 GKH |
2323 | { |
2324 | return card->config_data.data_slot_size; | |
2325 | } /* CardGetDataSlotSize() */ | |
2326 | ||
2327 | ||
2328 | /* | |
2329 | * --------------------------------------------------------------------------- | |
2330 | * CardGetFreeFromHostDataSlots | |
2331 | * | |
2332 | * Retrieve the number of from-host bulk data slots available. | |
2333 | * | |
2334 | * Arguments: | |
2335 | * card Pointer to the card context struct | |
2336 | * | |
2337 | * Returns: | |
2338 | * Number of free from-host bulk data slots. | |
2339 | * --------------------------------------------------------------------------- | |
2340 | */ | |
8c87f69a | 2341 | u16 CardGetFreeFromHostDataSlots(card_t *card) |
635d2b00 | 2342 | { |
8c87f69a | 2343 | u16 i, n = 0; |
635d2b00 | 2344 | |
635d2b00 GKH |
2345 | /* First two slots reserved for MLME */ |
2346 | for (i = 0; i < card->config_data.num_fromhost_data_slots; i++) | |
2347 | { | |
2348 | if (card->from_host_data[i].bd.data_length == 0) | |
2349 | { | |
2350 | /* Free slot */ | |
2351 | n++; | |
2352 | } | |
2353 | } | |
2354 | ||
635d2b00 GKH |
2355 | return n; |
2356 | } /* CardGetFreeFromHostDataSlots() */ | |
2357 | ||
2358 | ||
2359 | /* | |
2360 | * --------------------------------------------------------------------------- | |
2361 | * CardAreAllFromHostDataSlotsEmpty | |
2362 | * | |
2363 | * Returns the state of from-host bulk data slots. | |
2364 | * | |
2365 | * Arguments: | |
2366 | * card Pointer to the card context struct | |
2367 | * | |
2368 | * Returns: | |
2369 | * 1 The from-host bulk data slots are all empty (available). | |
2370 | * 0 Some or all the from-host bulk data slots are in use. | |
2371 | * --------------------------------------------------------------------------- | |
2372 | */ | |
8c87f69a | 2373 | u16 CardAreAllFromHostDataSlotsEmpty(card_t *card) |
635d2b00 | 2374 | { |
8c87f69a | 2375 | u16 i; |
635d2b00 GKH |
2376 | |
2377 | for (i = 0; i < card->config_data.num_fromhost_data_slots; i++) | |
2378 | { | |
2379 | if (card->from_host_data[i].bd.data_length != 0) | |
2380 | { | |
2381 | return 0; | |
2382 | } | |
2383 | } | |
2384 | ||
2385 | return 1; | |
2386 | } /* CardGetFreeFromHostDataSlots() */ | |
2387 | ||
2388 | ||
2389 | static CsrResult unifi_identify_hw(card_t *card) | |
2390 | { | |
635d2b00 GKH |
2391 | |
2392 | card->chip_id = card->sdio_if->sdioId.cardId; | |
2393 | card->function = card->sdio_if->sdioId.sdioFunction; | |
2394 | card->sdio_io_block_size = card->sdio_if->blockSize; | |
2395 | ||
2396 | /* If SDIO controller doesn't support byte mode CMD53, pad transfers to block sizes */ | |
2397 | card->sdio_io_block_pad = (card->sdio_if->features & CSR_SDIO_FEATURE_BYTE_MODE)?FALSE : TRUE; | |
2398 | ||
2399 | /* | |
2400 | * Setup the chip helper so that we can access the registers (and | |
2401 | * also tell what sub-type of HIP we should use). | |
2402 | */ | |
7e6f5794 | 2403 | card->helper = ChipHelper_GetVersionSdio((u8)card->chip_id); |
635d2b00 GKH |
2404 | if (!card->helper) |
2405 | { | |
2406 | unifi_error(card->ospriv, "Null ChipHelper\n"); | |
2407 | } | |
2408 | ||
2409 | unifi_info(card->ospriv, "Chip ID 0x%02X Function %u Block Size %u Name %s(%s)\n", | |
2410 | card->chip_id, card->function, card->sdio_io_block_size, | |
2411 | ChipHelper_MarketingName(card->helper), | |
2412 | ChipHelper_FriendlyName(card->helper)); | |
2413 | ||
635d2b00 GKH |
2414 | return CSR_RESULT_SUCCESS; |
2415 | } /* unifi_identify_hw() */ | |
2416 | ||
2417 | ||
2418 | static CsrResult unifi_prepare_hw(card_t *card) | |
2419 | { | |
2420 | CsrResult r; | |
2421 | CsrResult csrResult; | |
2422 | enum unifi_host_state old_state = card->host_state; | |
2423 | ||
635d2b00 GKH |
2424 | r = unifi_identify_hw(card); |
2425 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2426 | { | |
2427 | return r; | |
2428 | } | |
2429 | if (r != CSR_RESULT_SUCCESS) | |
2430 | { | |
2431 | unifi_error(card->ospriv, "Failed to identify hw\n"); | |
635d2b00 GKH |
2432 | return r; |
2433 | } | |
2434 | ||
2435 | unifi_trace(card->ospriv, UDBG1, | |
2436 | "%s mode SDIO\n", card->sdio_io_block_pad?"Block" : "Byte"); | |
2437 | /* | |
2438 | * Chip must be a awake or blocks that are asleep may not get | |
2439 | * reset. We can only do this after we have read the chip_id. | |
2440 | */ | |
2441 | r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE); | |
2442 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2443 | { | |
2444 | return r; | |
2445 | } | |
2446 | ||
2447 | if (old_state == UNIFI_HOST_STATE_TORPID) | |
2448 | { | |
58af42a4 | 2449 | /* Ensure the initial clock rate is set; if a reset occurred when the chip was |
635d2b00 GKH |
2450 | * TORPID, unifi_set_host_state() may have raised it to MAX. |
2451 | */ | |
2452 | csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_INIT_HZ); | |
2453 | if (csrResult != CSR_RESULT_SUCCESS) | |
2454 | { | |
2455 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
635d2b00 GKH |
2456 | return r; |
2457 | } | |
2458 | card->sdio_clock_speed = UNIFI_SDIO_CLOCK_INIT_HZ; | |
2459 | } | |
2460 | ||
2461 | /* | |
2462 | * The WLAN function must be enabled to access MAILBOX2 and DEBUG_RST | |
2463 | * registers. | |
2464 | */ | |
2465 | csrResult = CsrSdioFunctionEnable(card->sdio_if); | |
2466 | if (csrResult == CSR_SDIO_RESULT_NO_DEVICE) | |
2467 | { | |
2468 | return CSR_WIFI_HIP_RESULT_NO_DEVICE; | |
2469 | } | |
2470 | if (csrResult != CSR_RESULT_SUCCESS) | |
2471 | { | |
2472 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
2473 | /* Can't enable WLAN function. Try resetting the SDIO block. */ | |
2474 | unifi_error(card->ospriv, "Failed to re-enable function %d.\n", card->function); | |
635d2b00 GKH |
2475 | return r; |
2476 | } | |
2477 | ||
2478 | /* | |
2479 | * Poke some registers to make sure the PLL has started, | |
2480 | * otherwise memory accesses are likely to fail. | |
2481 | */ | |
2482 | bootstrap_chip_hw(card); | |
2483 | ||
2484 | /* Try to read the chip version from register. */ | |
2485 | r = unifi_read_chip_version(card); | |
2486 | if (r != CSR_RESULT_SUCCESS) | |
2487 | { | |
635d2b00 GKH |
2488 | return r; |
2489 | } | |
2490 | ||
635d2b00 GKH |
2491 | return CSR_RESULT_SUCCESS; |
2492 | } /* unifi_prepare_hw() */ | |
2493 | ||
2494 | ||
2495 | static CsrResult unifi_read_chip_version(card_t *card) | |
2496 | { | |
26a6b2e1 | 2497 | u32 gbl_chip_version; |
635d2b00 | 2498 | CsrResult r; |
8c87f69a | 2499 | u16 ver; |
635d2b00 | 2500 | |
635d2b00 GKH |
2501 | gbl_chip_version = ChipHelper_GBL_CHIP_VERSION(card->helper); |
2502 | ||
2503 | /* Try to read the chip version from register. */ | |
2504 | if (gbl_chip_version != 0) | |
2505 | { | |
2506 | r = unifi_read_direct16(card, gbl_chip_version * 2, &ver); | |
2507 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2508 | { | |
2509 | return r; | |
2510 | } | |
2511 | if (r != CSR_RESULT_SUCCESS) | |
2512 | { | |
2513 | unifi_error(card->ospriv, "Failed to read GBL_CHIP_VERSION\n"); | |
635d2b00 GKH |
2514 | return r; |
2515 | } | |
2516 | card->chip_version = ver; | |
2517 | } | |
2518 | else | |
2519 | { | |
2520 | unifi_info(card->ospriv, "Unknown Chip ID, cannot locate GBL_CHIP_VERSION\n"); | |
2521 | r = CSR_RESULT_FAILURE; | |
2522 | } | |
2523 | ||
2524 | unifi_info(card->ospriv, "Chip Version 0x%04X\n", card->chip_version); | |
2525 | ||
635d2b00 GKH |
2526 | return r; |
2527 | } /* unifi_read_chip_version() */ | |
2528 | ||
2529 | ||
2530 | /* | |
2531 | * --------------------------------------------------------------------------- | |
2532 | * unifi_reset_hardware | |
2533 | * | |
2534 | * Execute the UniFi reset sequence. | |
2535 | * | |
2536 | * Note: This may fail if the chip is going TORPID so retry at | |
2537 | * least once. | |
2538 | * | |
2539 | * Arguments: | |
2540 | * card - pointer to card context structure | |
2541 | * | |
2542 | * Returns: | |
2543 | * CSR_RESULT_SUCCESS on success, CSR error otherwise. | |
2544 | * | |
2545 | * Notes: | |
2546 | * Some platforms (e.g. Windows Vista) do not allow access to registers | |
2547 | * that are necessary for a software soft reset. | |
2548 | * --------------------------------------------------------------------------- | |
2549 | */ | |
2550 | static CsrResult unifi_reset_hardware(card_t *card) | |
2551 | { | |
2552 | CsrResult r; | |
8c87f69a | 2553 | u16 new_block_size = UNIFI_IO_BLOCK_SIZE; |
635d2b00 GKH |
2554 | CsrResult csrResult; |
2555 | ||
635d2b00 GKH |
2556 | /* Errors returned by unifi_prepare_hw() are not critical at this point */ |
2557 | r = unifi_prepare_hw(card); | |
2558 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2559 | { | |
2560 | return r; | |
2561 | } | |
2562 | ||
2563 | /* First try SDIO controller reset, which may power cycle the UniFi, assert | |
2564 | * its reset line, or not be implemented depending on the platform. | |
2565 | */ | |
2566 | unifi_info(card->ospriv, "Calling CsrSdioHardReset\n"); | |
2567 | csrResult = CsrSdioHardReset(card->sdio_if); | |
2568 | if (csrResult == CSR_RESULT_SUCCESS) | |
2569 | { | |
58af42a4 | 2570 | unifi_info(card->ospriv, "CsrSdioHardReset succeeded on resetting UniFi\n"); |
635d2b00 GKH |
2571 | r = unifi_prepare_hw(card); |
2572 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2573 | { | |
2574 | return r; | |
2575 | } | |
2576 | if (r != CSR_RESULT_SUCCESS) | |
2577 | { | |
2578 | unifi_error(card->ospriv, "unifi_prepare_hw failed after hard reset\n"); | |
635d2b00 GKH |
2579 | return r; |
2580 | } | |
2581 | } | |
2582 | else if (csrResult == CSR_SDIO_RESULT_NO_DEVICE) | |
2583 | { | |
2584 | return CSR_WIFI_HIP_RESULT_NO_DEVICE; | |
2585 | } | |
2586 | else | |
2587 | { | |
2588 | /* Falling back to software hard reset methods */ | |
2589 | unifi_info(card->ospriv, "Falling back to software hard reset\n"); | |
2590 | r = unifi_card_hard_reset(card); | |
2591 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2592 | { | |
2593 | return r; | |
2594 | } | |
2595 | if (r != CSR_RESULT_SUCCESS) | |
2596 | { | |
2597 | unifi_error(card->ospriv, "software hard reset failed\n"); | |
635d2b00 GKH |
2598 | return r; |
2599 | } | |
2600 | ||
2601 | /* If we fell back to unifi_card_hard_reset() methods, chip version may | |
2602 | * not have been read. (Note in the unlikely event that it is zero, | |
2603 | * it will be harmlessly read again) | |
2604 | */ | |
2605 | if (card->chip_version == 0) | |
2606 | { | |
2607 | r = unifi_read_chip_version(card); | |
2608 | if (r != CSR_RESULT_SUCCESS) | |
2609 | { | |
635d2b00 GKH |
2610 | return r; |
2611 | } | |
2612 | } | |
2613 | } | |
2614 | ||
2615 | #ifdef CSR_WIFI_HIP_SDIO_BLOCK_SIZE | |
2616 | new_block_size = CSR_WIFI_HIP_SDIO_BLOCK_SIZE; | |
2617 | #endif | |
2618 | ||
2619 | /* After hard reset, we need to restore the SDIO block size */ | |
2620 | csrResult = CsrSdioBlockSizeSet(card->sdio_if, new_block_size); | |
2621 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
2622 | ||
2623 | /* Warn if a different block size was achieved by the transport */ | |
2624 | if (card->sdio_if->blockSize != new_block_size) | |
2625 | { | |
2626 | unifi_info(card->ospriv, | |
2627 | "Actually got block size %d\n", card->sdio_if->blockSize); | |
2628 | } | |
2629 | ||
2630 | /* sdio_io_block_size always needs be updated from the achieved block size, | |
2631 | * as it is used by the OS layer to allocate memory in unifi_net_malloc(). | |
2632 | * Controllers which don't support block mode (e.g. CSPI) will report a | |
2633 | * block size of zero. | |
2634 | */ | |
2635 | if (card->sdio_if->blockSize == 0) | |
2636 | { | |
2637 | unifi_info(card->ospriv, "Block size 0, block mode not available\n"); | |
2638 | ||
2639 | /* Set sdio_io_block_size to 1 so that unifi_net_data_malloc() has a | |
2640 | * sensible rounding value. Elsewhere padding will already be | |
2641 | * disabled because the controller supports byte mode. | |
2642 | */ | |
2643 | card->sdio_io_block_size = 1; | |
2644 | ||
2645 | /* Controller features must declare support for byte mode */ | |
2646 | if (!(card->sdio_if->features & CSR_SDIO_FEATURE_BYTE_MODE)) | |
2647 | { | |
2648 | unifi_error(card->ospriv, "Requires byte mode\n"); | |
2649 | r = CSR_WIFI_HIP_RESULT_INVALID_VALUE; | |
2650 | } | |
2651 | } | |
2652 | else | |
2653 | { | |
2654 | /* Padding will be enabled if CSR_SDIO_FEATURE_BYTE_MODE isn't set */ | |
2655 | card->sdio_io_block_size = card->sdio_if->blockSize; | |
2656 | } | |
2657 | ||
2658 | ||
635d2b00 GKH |
2659 | return r; |
2660 | } /* unifi_reset_hardware() */ | |
2661 | ||
2662 | ||
2663 | /* | |
2664 | * --------------------------------------------------------------------------- | |
2665 | * card_reset_method_io_enable | |
2666 | * | |
2667 | * Issue a hard reset to the hw writing the IO_ENABLE. | |
2668 | * | |
2669 | * Arguments: | |
2670 | * card Pointer to Card object | |
2671 | * | |
2672 | * Returns: | |
2673 | * 0 on success, | |
2674 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
2675 | * CSR_RESULT_FAILURE if an SDIO error occurred or if a response | |
2676 | * was not seen in the expected time | |
2677 | * --------------------------------------------------------------------------- | |
2678 | */ | |
2679 | static CsrResult card_reset_method_io_enable(card_t *card) | |
2680 | { | |
2681 | CsrResult r; | |
2682 | CsrResult csrResult; | |
2683 | ||
635d2b00 GKH |
2684 | /* |
2685 | * This resets only function 1, so should be used in | |
2686 | * preference to the method below (CSR_FUNC_EN) | |
2687 | */ | |
2688 | unifi_trace(card->ospriv, UDBG1, "Hard reset (IO_ENABLE)\n"); | |
2689 | ||
2690 | csrResult = CsrSdioFunctionDisable(card->sdio_if); | |
2691 | if (csrResult == CSR_SDIO_RESULT_NO_DEVICE) | |
2692 | { | |
2693 | return CSR_WIFI_HIP_RESULT_NO_DEVICE; | |
2694 | } | |
2695 | if (csrResult != CSR_RESULT_SUCCESS) | |
2696 | { | |
2697 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
2698 | unifi_warning(card->ospriv, "SDIO error writing IO_ENABLE: %d\n", r); | |
2699 | } | |
2700 | else | |
2701 | { | |
2702 | /* Delay here to let the reset take affect. */ | |
2703 | CsrThreadSleep(RESET_SETTLE_DELAY); | |
2704 | ||
2705 | r = card_wait_for_unifi_to_disable(card); | |
2706 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2707 | { | |
2708 | return r; | |
2709 | } | |
2710 | ||
2711 | if (r == CSR_RESULT_SUCCESS) | |
2712 | { | |
2713 | r = card_wait_for_unifi_to_reset(card); | |
2714 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2715 | { | |
2716 | return r; | |
2717 | } | |
2718 | } | |
2719 | } | |
2720 | ||
2721 | if (r != CSR_RESULT_SUCCESS) | |
2722 | { | |
2723 | unifi_trace(card->ospriv, UDBG1, "Hard reset (CSR_FUNC_EN)\n"); | |
2724 | ||
2725 | r = sdio_write_f0(card, SDIO_CSR_FUNC_EN, 0); | |
2726 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2727 | { | |
2728 | return r; | |
2729 | } | |
2730 | if (r != CSR_RESULT_SUCCESS) | |
2731 | { | |
2732 | unifi_warning(card->ospriv, "SDIO error writing SDIO_CSR_FUNC_EN: %d\n", r); | |
635d2b00 GKH |
2733 | return r; |
2734 | } | |
2735 | else | |
2736 | { | |
2737 | /* Delay here to let the reset take affect. */ | |
2738 | CsrThreadSleep(RESET_SETTLE_DELAY); | |
2739 | ||
2740 | r = card_wait_for_unifi_to_reset(card); | |
2741 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2742 | { | |
2743 | return r; | |
2744 | } | |
2745 | } | |
2746 | } | |
2747 | ||
2748 | if (r != CSR_RESULT_SUCCESS) | |
2749 | { | |
2750 | unifi_warning(card->ospriv, "card_reset_method_io_enable failed to reset UniFi\n"); | |
2751 | } | |
2752 | ||
635d2b00 GKH |
2753 | return r; |
2754 | } /* card_reset_method_io_enable() */ | |
2755 | ||
2756 | ||
2757 | /* | |
2758 | * --------------------------------------------------------------------------- | |
2759 | * card_reset_method_dbg_reset | |
2760 | * | |
2761 | * Issue a hard reset to the hw writing the DBG_RESET. | |
2762 | * | |
2763 | * Arguments: | |
2764 | * card Pointer to Card object | |
2765 | * | |
2766 | * Returns: | |
2767 | * CSR_RESULT_SUCCESS on success, | |
2768 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
2769 | * CSR_RESULT_FAILURE if an SDIO error occurred or if a response | |
2770 | * was not seen in the expected time | |
2771 | * --------------------------------------------------------------------------- | |
2772 | */ | |
2773 | static CsrResult card_reset_method_dbg_reset(card_t *card) | |
2774 | { | |
2775 | CsrResult r; | |
2776 | ||
635d2b00 GKH |
2777 | /* |
2778 | * Prepare UniFi for h/w reset | |
2779 | */ | |
2780 | if (card->host_state == UNIFI_HOST_STATE_TORPID) | |
2781 | { | |
2782 | r = unifi_set_host_state(card, UNIFI_HOST_STATE_DROWSY); | |
2783 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2784 | { | |
2785 | return r; | |
2786 | } | |
2787 | if (r != CSR_RESULT_SUCCESS) | |
2788 | { | |
2789 | unifi_error(card->ospriv, "Failed to set UNIFI_HOST_STATE_DROWSY\n"); | |
635d2b00 GKH |
2790 | return r; |
2791 | } | |
2792 | CsrThreadSleep(5); | |
2793 | } | |
2794 | ||
2795 | r = unifi_card_stop_processor(card, UNIFI_PROC_BOTH); | |
2796 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2797 | { | |
2798 | return r; | |
2799 | } | |
2800 | if (r != CSR_RESULT_SUCCESS) | |
2801 | { | |
2802 | unifi_error(card->ospriv, "Can't stop processors\n"); | |
635d2b00 GKH |
2803 | return r; |
2804 | } | |
2805 | ||
2806 | unifi_trace(card->ospriv, UDBG1, "Hard reset (DBG_RESET)\n"); | |
2807 | ||
2808 | /* | |
2809 | * This register write may fail. The debug reset resets | |
2810 | * parts of the Function 0 sections of the chip, and | |
2811 | * therefore the response cannot be sent back to the host. | |
2812 | */ | |
2813 | r = unifi_write_direct_8_or_16(card, ChipHelper_DBG_RESET(card->helper) * 2, 1); | |
2814 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2815 | { | |
2816 | return r; | |
2817 | } | |
2818 | if (r != CSR_RESULT_SUCCESS) | |
2819 | { | |
2820 | unifi_warning(card->ospriv, "SDIO error writing DBG_RESET: %d\n", r); | |
635d2b00 GKH |
2821 | return r; |
2822 | } | |
2823 | ||
2824 | /* Delay here to let the reset take affect. */ | |
2825 | CsrThreadSleep(RESET_SETTLE_DELAY); | |
2826 | ||
2827 | r = card_wait_for_unifi_to_reset(card); | |
2828 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2829 | { | |
2830 | return r; | |
2831 | } | |
2832 | if (r != CSR_RESULT_SUCCESS) | |
2833 | { | |
2834 | unifi_warning(card->ospriv, "card_reset_method_dbg_reset failed to reset UniFi\n"); | |
2835 | } | |
2836 | ||
635d2b00 GKH |
2837 | return r; |
2838 | } /* card_reset_method_dbg_reset() */ | |
2839 | ||
2840 | ||
2841 | /* | |
2842 | * --------------------------------------------------------------------------- | |
2843 | * unifi_card_hard_reset | |
2844 | * | |
2845 | * Issue reset to hardware, by writing to registers on the card. | |
2846 | * Power to the card is preserved. | |
2847 | * | |
2848 | * Arguments: | |
2849 | * card Pointer to Card object | |
2850 | * | |
2851 | * Returns: | |
2852 | * CSR_RESULT_SUCCESS on success, | |
2853 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
2854 | * CSR_RESULT_FAILURE if an SDIO error occurred or if a response | |
2855 | * was not seen in the expected time | |
2856 | * --------------------------------------------------------------------------- | |
2857 | */ | |
2858 | CsrResult unifi_card_hard_reset(card_t *card) | |
2859 | { | |
2860 | CsrResult r; | |
2861 | const struct chip_helper_reset_values *init_data; | |
26a6b2e1 | 2862 | u32 chunks; |
635d2b00 | 2863 | |
635d2b00 | 2864 | /* Clear cache of page registers */ |
26a6b2e1 GKH |
2865 | card->proc_select = (u32)(-1); |
2866 | card->dmem_page = (u32)(-1); | |
2867 | card->pmem_page = (u32)(-1); | |
635d2b00 GKH |
2868 | |
2869 | /* | |
2870 | * We need to have a valid card->helper before we use software hard reset. | |
2871 | * If unifi_identify_hw() fails to get the card ID, it probably means | |
2872 | * that there is no way to talk to the h/w. | |
2873 | */ | |
2874 | r = unifi_identify_hw(card); | |
2875 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2876 | { | |
2877 | return r; | |
2878 | } | |
2879 | if (r != CSR_RESULT_SUCCESS) | |
2880 | { | |
2881 | unifi_error(card->ospriv, "unifi_card_hard_reset failed to identify h/w\n"); | |
635d2b00 GKH |
2882 | return r; |
2883 | } | |
2884 | ||
2885 | /* Search for some reset code. */ | |
2886 | chunks = ChipHelper_HostResetSequence(card->helper, &init_data); | |
2887 | if (chunks != 0) | |
2888 | { | |
2889 | unifi_error(card->ospriv, | |
2890 | "Hard reset (Code download) is unsupported\n"); | |
2891 | ||
635d2b00 GKH |
2892 | return CSR_RESULT_FAILURE; |
2893 | } | |
2894 | ||
2895 | if (card->chip_id > SDIO_CARD_ID_UNIFI_2) | |
2896 | { | |
2897 | /* The HIP spec considers this a bus-specific reset. | |
2898 | * This resets only function 1, so should be used in | |
2899 | * preference to the method below (CSR_FUNC_EN) | |
2900 | * If this method fails, it means that the f/w is probably | |
2901 | * not running. In this case, try the DBG_RESET method. | |
2902 | */ | |
2903 | r = card_reset_method_io_enable(card); | |
2904 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2905 | { | |
2906 | return r; | |
2907 | } | |
2908 | if (r == CSR_RESULT_SUCCESS) | |
2909 | { | |
635d2b00 GKH |
2910 | return r; |
2911 | } | |
2912 | } | |
2913 | ||
2914 | /* Software hard reset */ | |
2915 | r = card_reset_method_dbg_reset(card); | |
2916 | ||
635d2b00 GKH |
2917 | return r; |
2918 | } /* unifi_card_hard_reset() */ | |
2919 | ||
2920 | ||
2921 | /* | |
2922 | * --------------------------------------------------------------------------- | |
2923 | * | |
2924 | * CardGenInt | |
2925 | * | |
2926 | * Prod the card. | |
2927 | * This function causes an internal interrupt to be raised in the | |
2928 | * UniFi chip. It is used to signal the firmware that some action has | |
2929 | * been completed. | |
2930 | * The UniFi Host Interface asks that the value used increments for | |
2931 | * debugging purposes. | |
2932 | * | |
2933 | * Arguments: | |
2934 | * card Pointer to Card object | |
2935 | * | |
2936 | * Returns: | |
2937 | * CSR_RESULT_SUCCESS on success, | |
2938 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
2939 | * CSR_RESULT_FAILURE if an SDIO error occurred or if a response | |
2940 | * was not seen in the expected time | |
2941 | * --------------------------------------------------------------------------- | |
2942 | */ | |
2943 | CsrResult CardGenInt(card_t *card) | |
2944 | { | |
2945 | CsrResult r; | |
2946 | ||
635d2b00 GKH |
2947 | if (card->chip_id > SDIO_CARD_ID_UNIFI_2) |
2948 | { | |
2949 | r = sdio_write_f0(card, SDIO_CSR_FROM_HOST_SCRATCH0, | |
7e6f5794 | 2950 | (u8)card->unifi_interrupt_seq); |
635d2b00 GKH |
2951 | } |
2952 | else | |
2953 | { | |
2954 | r = unifi_write_direct_8_or_16(card, | |
2955 | ChipHelper_SHARED_IO_INTERRUPT(card->helper) * 2, | |
7e6f5794 | 2956 | (u8)card->unifi_interrupt_seq); |
635d2b00 GKH |
2957 | } |
2958 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2959 | { | |
2960 | return r; | |
2961 | } | |
2962 | if (r != CSR_RESULT_SUCCESS) | |
2963 | { | |
2964 | unifi_error(card->ospriv, "SDIO error writing UNIFI_SHARED_IO_INTERRUPT: %d\n", r); | |
635d2b00 GKH |
2965 | return r; |
2966 | } | |
2967 | ||
2968 | card->unifi_interrupt_seq++; | |
2969 | ||
635d2b00 GKH |
2970 | return CSR_RESULT_SUCCESS; |
2971 | } /* CardGenInt() */ | |
2972 | ||
2973 | ||
2974 | /* | |
2975 | * --------------------------------------------------------------------------- | |
2976 | * CardEnableInt | |
2977 | * | |
2978 | * Enable the outgoing SDIO interrupt from UniFi to the host. | |
2979 | * | |
2980 | * Arguments: | |
2981 | * card Pointer to Card object | |
2982 | * | |
2983 | * Returns: | |
2984 | * CSR_RESULT_SUCCESS on success, | |
2985 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
2986 | * CSR_RESULT_FAILURE if an SDIO error occurred, | |
2987 | * --------------------------------------------------------------------------- | |
2988 | */ | |
2989 | CsrResult CardEnableInt(card_t *card) | |
2990 | { | |
2991 | CsrResult r; | |
7e6f5794 | 2992 | u8 int_enable; |
635d2b00 GKH |
2993 | |
2994 | r = sdio_read_f0(card, SDIO_INT_ENABLE, &int_enable); | |
2995 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
2996 | { | |
2997 | return r; | |
2998 | } | |
2999 | if (r != CSR_RESULT_SUCCESS) | |
3000 | { | |
3001 | unifi_error(card->ospriv, "SDIO error reading SDIO_INT_ENABLE\n"); | |
3002 | return r; | |
3003 | } | |
3004 | ||
3005 | int_enable |= (1 << card->function) | UNIFI_SD_INT_ENABLE_IENM; | |
3006 | ||
3007 | r = sdio_write_f0(card, SDIO_INT_ENABLE, int_enable); | |
3008 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3009 | { | |
3010 | return r; | |
3011 | } | |
3012 | if (r != CSR_RESULT_SUCCESS) | |
3013 | { | |
3014 | unifi_error(card->ospriv, "SDIO error writing SDIO_INT_ENABLE\n"); | |
3015 | return r; | |
3016 | } | |
3017 | ||
3018 | return CSR_RESULT_SUCCESS; | |
3019 | } /* CardEnableInt() */ | |
3020 | ||
3021 | ||
3022 | /* | |
3023 | * --------------------------------------------------------------------------- | |
3024 | * CardDisableInt | |
3025 | * | |
3026 | * Disable the outgoing SDIO interrupt from UniFi to the host. | |
3027 | * | |
3028 | * Arguments: | |
3029 | * card Pointer to Card object | |
3030 | * | |
3031 | * Returns: | |
3032 | * CSR_RESULT_SUCCESS on success, | |
3033 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
3034 | * CSR_RESULT_FAILURE if an SDIO error occurred, | |
3035 | * --------------------------------------------------------------------------- | |
3036 | */ | |
3037 | CsrResult CardDisableInt(card_t *card) | |
3038 | { | |
3039 | CsrResult r; | |
7e6f5794 | 3040 | u8 int_enable; |
635d2b00 GKH |
3041 | |
3042 | r = sdio_read_f0(card, SDIO_INT_ENABLE, &int_enable); | |
3043 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3044 | { | |
3045 | return r; | |
3046 | } | |
3047 | if (r != CSR_RESULT_SUCCESS) | |
3048 | { | |
3049 | unifi_error(card->ospriv, "SDIO error reading SDIO_INT_ENABLE\n"); | |
3050 | return r; | |
3051 | } | |
3052 | ||
3053 | int_enable &= ~(1 << card->function); | |
3054 | ||
3055 | r = sdio_write_f0(card, SDIO_INT_ENABLE, int_enable); | |
3056 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3057 | { | |
3058 | return r; | |
3059 | } | |
3060 | if (r != CSR_RESULT_SUCCESS) | |
3061 | { | |
3062 | unifi_error(card->ospriv, "SDIO error writing SDIO_INT_ENABLE\n"); | |
3063 | return r; | |
3064 | } | |
3065 | ||
3066 | return CSR_RESULT_SUCCESS; | |
3067 | } /* CardDisableInt() */ | |
3068 | ||
3069 | ||
3070 | /* | |
3071 | * --------------------------------------------------------------------------- | |
3072 | * CardPendingInt | |
3073 | * | |
3074 | * Determine whether UniFi is currently asserting the SDIO interrupt | |
3075 | * request. | |
3076 | * | |
3077 | * Arguments: | |
3078 | * card Pointer to Card object | |
3079 | * pintr Pointer to location to write interrupt status, | |
3080 | * TRUE if interrupt pending, | |
3081 | * FALSE if no interrupt pending. | |
3082 | * Returns: | |
3083 | * CSR_RESULT_SUCCESS interrupt status read successfully | |
3084 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
3085 | * CSR_RESULT_FAILURE if an SDIO error occurred, | |
3086 | * --------------------------------------------------------------------------- | |
3087 | */ | |
5379b13d | 3088 | CsrResult CardPendingInt(card_t *card, u8 *pintr) |
635d2b00 GKH |
3089 | { |
3090 | CsrResult r; | |
7e6f5794 | 3091 | u8 pending; |
635d2b00 GKH |
3092 | |
3093 | *pintr = FALSE; | |
3094 | ||
3095 | r = sdio_read_f0(card, SDIO_INT_PENDING, &pending); | |
3096 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3097 | { | |
3098 | return r; | |
3099 | } | |
3100 | if (r != CSR_RESULT_SUCCESS) | |
3101 | { | |
3102 | unifi_error(card->ospriv, "SDIO error reading SDIO_INT_PENDING\n"); | |
3103 | return r; | |
3104 | } | |
3105 | ||
3106 | *pintr = (pending & (1 << card->function))?TRUE : FALSE; | |
3107 | ||
3108 | return CSR_RESULT_SUCCESS; | |
3109 | } /* CardPendingInt() */ | |
3110 | ||
3111 | ||
3112 | /* | |
3113 | * --------------------------------------------------------------------------- | |
3114 | * CardClearInt | |
3115 | * | |
3116 | * Clear the UniFi SDIO interrupt request. | |
3117 | * | |
3118 | * Arguments: | |
3119 | * card Pointer to Card object | |
3120 | * | |
3121 | * Returns: | |
3122 | * CSR_RESULT_SUCCESS if pending interrupt was cleared, or no pending interrupt. | |
3123 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
3124 | * CSR_RESULT_FAILURE if an SDIO error occurred, | |
3125 | * --------------------------------------------------------------------------- | |
3126 | */ | |
3127 | CsrResult CardClearInt(card_t *card) | |
3128 | { | |
3129 | CsrResult r; | |
5379b13d | 3130 | u8 intr; |
635d2b00 GKH |
3131 | |
3132 | if (card->chip_id > SDIO_CARD_ID_UNIFI_2) | |
3133 | { | |
3134 | /* CardPendingInt() sets intr, if there is a pending interrupt */ | |
3135 | r = CardPendingInt(card, &intr); | |
3136 | if (intr == FALSE) | |
3137 | { | |
3138 | return r; | |
3139 | } | |
3140 | ||
3141 | r = sdio_write_f0(card, SDIO_CSR_HOST_INT_CLEAR, 1); | |
3142 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3143 | { | |
3144 | return r; | |
3145 | } | |
3146 | if (r != CSR_RESULT_SUCCESS) | |
3147 | { | |
3148 | unifi_error(card->ospriv, "SDIO error writing SDIO_CSR_HOST_INT_CLEAR\n"); | |
3149 | } | |
3150 | } | |
3151 | else | |
3152 | { | |
3153 | r = unifi_write_direct_8_or_16(card, | |
3154 | ChipHelper_SDIO_HOST_INT(card->helper) * 2, | |
3155 | 0); | |
3156 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3157 | { | |
3158 | return r; | |
3159 | } | |
3160 | if (r != CSR_RESULT_SUCCESS) | |
3161 | { | |
3162 | unifi_error(card->ospriv, "SDIO error writing UNIFI_SDIO_HOST_INT\n"); | |
3163 | } | |
3164 | } | |
3165 | ||
3166 | return r; | |
3167 | } /* CardClearInt() */ | |
3168 | ||
3169 | ||
3170 | /* | |
3171 | * --------------------------------------------------------------------------- | |
3172 | * CardIntEnabled | |
3173 | * | |
3174 | * Determine whether UniFi is currently asserting the SDIO interrupt | |
3175 | * request. | |
3176 | * | |
3177 | * Arguments: | |
3178 | * card Pointer to Card object | |
3179 | * enabled Pointer to location to write interrupt enable status, | |
3180 | * TRUE if interrupts enabled, | |
3181 | * FALSE if interupts disabled. | |
3182 | * | |
3183 | * Returns: | |
3184 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
3185 | * CSR_RESULT_FAILURE if an SDIO error occurred, | |
3186 | * --------------------------------------------------------------------------- | |
3187 | */ | |
5379b13d | 3188 | CsrResult CardIntEnabled(card_t *card, u8 *enabled) |
635d2b00 GKH |
3189 | { |
3190 | CsrResult r; | |
7e6f5794 | 3191 | u8 int_enable; |
635d2b00 GKH |
3192 | |
3193 | r = sdio_read_f0(card, SDIO_INT_ENABLE, &int_enable); | |
3194 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3195 | { | |
3196 | return r; | |
3197 | } | |
3198 | if (r != CSR_RESULT_SUCCESS) | |
3199 | { | |
3200 | unifi_error(card->ospriv, "SDIO error reading SDIO_INT_ENABLE\n"); | |
3201 | return r; | |
3202 | } | |
3203 | ||
3204 | *enabled = (int_enable & (1 << card->function))?TRUE : FALSE; | |
3205 | ||
3206 | return CSR_RESULT_SUCCESS; | |
3207 | } /* CardIntEnabled() */ | |
3208 | ||
3209 | ||
3210 | /* | |
3211 | * --------------------------------------------------------------------------- | |
3212 | * CardWriteBulkData | |
3213 | * Allocate slot in the pending bulkdata arrays and assign it to a signal's | |
3214 | * bulkdata reference. The slot is then ready for UniFi's bulkdata commands | |
3215 | * to transfer the data to/from the host. | |
3216 | * | |
3217 | * Arguments: | |
3218 | * card Pointer to Card object | |
3219 | * csptr Pending signal pointer, including bulkdata ref | |
3220 | * queue Traffic queue that this signal is using | |
3221 | * | |
3222 | * Returns: | |
3223 | * CSR_RESULT_SUCCESS if a free slot was assigned | |
3224 | * CSR_RESULT_FAILURE if no slot was available | |
3225 | * --------------------------------------------------------------------------- | |
3226 | */ | |
3227 | CsrResult CardWriteBulkData(card_t *card, card_signal_t *csptr, unifi_TrafficQueue queue) | |
3228 | { | |
8c87f69a | 3229 | u16 i, slots[UNIFI_MAX_DATA_REFERENCES], j = 0; |
7e6f5794 | 3230 | u8 *packed_sigptr, num_slots_required = 0; |
635d2b00 | 3231 | bulk_data_desc_t *bulkdata = csptr->bulkdata; |
ab2b8c73 | 3232 | s16 h, nslots; |
635d2b00 | 3233 | |
635d2b00 GKH |
3234 | /* Count the number of slots required */ |
3235 | for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) | |
3236 | { | |
3237 | if (bulkdata[i].data_length != 0) | |
3238 | { | |
3239 | num_slots_required++; | |
3240 | } | |
3241 | } | |
3242 | ||
3243 | /* Get the slot numbers */ | |
3244 | if (num_slots_required != 0) | |
3245 | { | |
3246 | /* Last 2 slots for MLME */ | |
3247 | if (queue == UNIFI_TRAFFIC_Q_MLME) | |
3248 | { | |
3249 | h = card->config_data.num_fromhost_data_slots - UNIFI_RESERVED_COMMAND_SLOTS; | |
3250 | for (i = 0; i < card->config_data.num_fromhost_data_slots; i++) | |
3251 | { | |
3252 | if (card->from_host_data[h].bd.data_length == 0) | |
3253 | { | |
3254 | /* Free data slot, claim it */ | |
3255 | slots[j++] = h; | |
3256 | if (j == num_slots_required) | |
3257 | { | |
3258 | break; | |
3259 | } | |
3260 | } | |
3261 | ||
3262 | if (++h >= card->config_data.num_fromhost_data_slots) | |
3263 | { | |
3264 | h = 0; | |
3265 | } | |
3266 | } | |
3267 | } | |
3268 | else | |
3269 | { | |
3270 | if (card->dynamic_slot_data.from_host_used_slots[queue] | |
3271 | < card->dynamic_slot_data.from_host_max_slots[queue]) | |
3272 | { | |
3273 | /* Data commands get a free slot only after a few checks */ | |
3274 | nslots = card->config_data.num_fromhost_data_slots - UNIFI_RESERVED_COMMAND_SLOTS; | |
3275 | ||
3276 | h = card->from_host_data_head; | |
3277 | ||
3278 | for (i = 0; i < nslots; i++) | |
3279 | { | |
3280 | if (card->from_host_data[h].bd.data_length == 0) | |
3281 | { | |
3282 | /* Free data slot, claim it */ | |
3283 | slots[j++] = h; | |
3284 | if (j == num_slots_required) | |
3285 | { | |
3286 | break; | |
3287 | } | |
3288 | } | |
3289 | ||
3290 | if (++h >= nslots) | |
3291 | { | |
3292 | h = 0; | |
3293 | } | |
3294 | } | |
3295 | card->from_host_data_head = h; | |
3296 | } | |
3297 | } | |
3298 | ||
3299 | /* Required number of slots are not available, bail out */ | |
3300 | if (j != num_slots_required) | |
3301 | { | |
3302 | unifi_trace(card->ospriv, UDBG5, "CardWriteBulkData: didn't find free slot/s\n"); | |
3303 | ||
3304 | /* If we haven't already reached the stable state we can ask for reservation */ | |
3305 | if ((queue != UNIFI_TRAFFIC_Q_MLME) && (card->dynamic_slot_data.queue_stable[queue] == FALSE)) | |
3306 | { | |
3307 | CardCheckDynamicReservation(card, queue); | |
3308 | } | |
3309 | ||
3310 | for (i = 0; i < card->config_data.num_fromhost_data_slots; i++) | |
3311 | { | |
3312 | unifi_trace(card->ospriv, UDBG5, "fh data slot %d: %d\n", i, card->from_host_data[i].bd.data_length); | |
3313 | } | |
635d2b00 GKH |
3314 | return CSR_RESULT_FAILURE; |
3315 | } | |
3316 | } | |
3317 | ||
3318 | packed_sigptr = csptr->sigbuf; | |
3319 | ||
3320 | /* Fill in the slots with data */ | |
3321 | j = 0; | |
3322 | for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) | |
3323 | { | |
3324 | if (bulkdata[i].data_length == 0) | |
3325 | { | |
3326 | /* Zero-out the DATAREF in the signal */ | |
3327 | SET_PACKED_DATAREF_SLOT(packed_sigptr, i, 0); | |
3328 | SET_PACKED_DATAREF_LEN(packed_sigptr, i, 0); | |
3329 | } | |
3330 | else | |
3331 | { | |
3332 | /* | |
3333 | * Fill in the slot number in the SIGNAL structure but | |
3334 | * preserve the offset already in there | |
3335 | */ | |
8c87f69a | 3336 | SET_PACKED_DATAREF_SLOT(packed_sigptr, i, slots[j] | (((u16)packed_sigptr[SIZEOF_SIGNAL_HEADER + (i * SIZEOF_DATAREF) + 1]) << 8)); |
635d2b00 GKH |
3337 | SET_PACKED_DATAREF_LEN(packed_sigptr, i, bulkdata[i].data_length); |
3338 | ||
3339 | /* Do not copy the data, just store the information to them */ | |
3340 | card->from_host_data[slots[j]].bd.os_data_ptr = bulkdata[i].os_data_ptr; | |
3341 | card->from_host_data[slots[j]].bd.os_net_buf_ptr = bulkdata[i].os_net_buf_ptr; | |
3342 | card->from_host_data[slots[j]].bd.data_length = bulkdata[i].data_length; | |
3343 | card->from_host_data[slots[j]].bd.net_buf_length = bulkdata[i].net_buf_length; | |
3344 | card->from_host_data[slots[j]].queue = queue; | |
3345 | ||
3346 | unifi_trace(card->ospriv, UDBG4, "CardWriteBulkData sig=0x%x, fh slot %d = %p\n", | |
3347 | GET_SIGNAL_ID(packed_sigptr), i, bulkdata[i].os_data_ptr); | |
3348 | ||
3349 | /* Sanity-check that the bulk data desc being assigned to the slot | |
3350 | * actually has a payload. | |
3351 | */ | |
3352 | if (!bulkdata[i].os_data_ptr) | |
3353 | { | |
3354 | unifi_error(card->ospriv, "Assign null os_data_ptr (len=%d) fh slot %d, i=%d, q=%d, sig=0x%x", | |
3355 | bulkdata[i].data_length, slots[j], i, queue, GET_SIGNAL_ID(packed_sigptr)); | |
3356 | } | |
3357 | ||
3358 | j++; | |
3359 | if (queue < UNIFI_NO_OF_TX_QS) | |
3360 | { | |
3361 | card->dynamic_slot_data.from_host_used_slots[queue]++; | |
3362 | } | |
3363 | } | |
3364 | } | |
3365 | ||
635d2b00 GKH |
3366 | return CSR_RESULT_SUCCESS; |
3367 | } /* CardWriteBulkData() */ | |
3368 | ||
3369 | ||
3370 | /* | |
3371 | * --------------------------------------------------------------------------- | |
3372 | * card_find_data_slot | |
3373 | * | |
3374 | * Dereference references to bulk data slots into pointers to real data. | |
3375 | * | |
3376 | * Arguments: | |
3377 | * card Pointer to the card struct. | |
3378 | * slot Slot number from a signal structure | |
3379 | * | |
3380 | * Returns: | |
3381 | * Pointer to entry in bulk_data_slot array. | |
3382 | * --------------------------------------------------------------------------- | |
3383 | */ | |
ab2b8c73 | 3384 | bulk_data_desc_t* card_find_data_slot(card_t *card, s16 slot) |
635d2b00 | 3385 | { |
ab2b8c73 | 3386 | s16 sn; |
635d2b00 GKH |
3387 | bulk_data_desc_t *bd; |
3388 | ||
3389 | sn = slot & 0x7FFF; | |
3390 | ||
3391 | /* ?? check sanity of slot number ?? */ | |
3392 | ||
3393 | if (slot & SLOT_DIR_TO_HOST) | |
3394 | { | |
3395 | bd = &card->to_host_data[sn]; | |
3396 | } | |
3397 | else | |
3398 | { | |
3399 | bd = &card->from_host_data[sn].bd; | |
3400 | } | |
3401 | ||
3402 | return bd; | |
3403 | } /* card_find_data_slot() */ | |
3404 | ||
3405 | ||
3406 | /* | |
3407 | * --------------------------------------------------------------------------- | |
3408 | * firmware_present_in_flash | |
3409 | * | |
3410 | * Probe for external Flash that looks like it might contain firmware. | |
3411 | * | |
3412 | * If Flash is not present, reads always return 0x0008. | |
3413 | * If Flash is present, but empty, reads return 0xFFFF. | |
3414 | * Anything else is considered to be firmware. | |
3415 | * | |
3416 | * Arguments: | |
3417 | * card Pointer to card struct | |
3418 | * | |
3419 | * Returns: | |
3420 | * CSR_RESULT_SUCCESS firmware is present in ROM or flash | |
3421 | * CSR_WIFI_HIP_RESULT_NOT_FOUND firmware is not present in ROM or flash | |
3422 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
3423 | * CSR_RESULT_FAILURE if an SDIO error occurred | |
3424 | * --------------------------------------------------------------------------- | |
3425 | */ | |
3426 | static CsrResult firmware_present_in_flash(card_t *card) | |
3427 | { | |
3428 | CsrResult r; | |
8c87f69a | 3429 | u16 m1, m5; |
635d2b00 GKH |
3430 | |
3431 | if (ChipHelper_HasRom(card->helper)) | |
3432 | { | |
3433 | return CSR_RESULT_SUCCESS; | |
3434 | } | |
3435 | if (!ChipHelper_HasFlash(card->helper)) | |
3436 | { | |
3437 | return CSR_WIFI_HIP_RESULT_NOT_FOUND; | |
3438 | } | |
3439 | ||
3440 | /* | |
3441 | * Examine the Flash locations that are the power-on default reset | |
3442 | * vectors of the XAP processors. | |
3443 | * These are words 1 and 5 in Flash. | |
3444 | */ | |
3445 | r = unifi_card_read16(card, UNIFI_MAKE_GP(EXT_FLASH, 2), &m1); | |
3446 | if (r != CSR_RESULT_SUCCESS) | |
3447 | { | |
3448 | return r; | |
3449 | } | |
3450 | ||
3451 | r = unifi_card_read16(card, UNIFI_MAKE_GP(EXT_FLASH, 10), &m5); | |
3452 | if (r != CSR_RESULT_SUCCESS) | |
3453 | { | |
3454 | return r; | |
3455 | } | |
3456 | ||
3457 | /* Check for uninitialised/missing flash */ | |
3458 | if ((m1 == 0x0008) || (m1 == 0xFFFF) || | |
3459 | (m1 == 0x0004) || (m5 == 0x0004) || | |
3460 | (m5 == 0x0008) || (m5 == 0xFFFF)) | |
3461 | { | |
3462 | return CSR_WIFI_HIP_RESULT_NOT_FOUND; | |
3463 | } | |
3464 | ||
3465 | return CSR_RESULT_SUCCESS; | |
3466 | } /* firmware_present_in_flash() */ | |
3467 | ||
3468 | ||
3469 | /* | |
3470 | * --------------------------------------------------------------------------- | |
3471 | * bootstrap_chip_hw | |
3472 | * | |
3473 | * Perform chip specific magic to "Get It Working" TM. This will | |
3474 | * increase speed of PLLs in analogue and maybe enable some | |
3475 | * on-chip regulators. | |
3476 | * | |
3477 | * Arguments: | |
3478 | * card Pointer to card struct | |
3479 | * | |
3480 | * Returns: | |
3481 | * None. | |
3482 | * --------------------------------------------------------------------------- | |
3483 | */ | |
3484 | static void bootstrap_chip_hw(card_t *card) | |
3485 | { | |
3486 | const struct chip_helper_init_values *vals; | |
26a6b2e1 | 3487 | u32 i, len; |
635d2b00 GKH |
3488 | void *sdio = card->sdio_if; |
3489 | CsrResult csrResult; | |
3490 | ||
3491 | len = ChipHelper_ClockStartupSequence(card->helper, &vals); | |
3492 | if (len != 0) | |
3493 | { | |
3494 | for (i = 0; i < len; i++) | |
3495 | { | |
3496 | csrResult = CsrSdioWrite16(sdio, vals[i].addr * 2, vals[i].value); | |
3497 | if (csrResult != CSR_RESULT_SUCCESS) | |
3498 | { | |
3499 | unifi_warning(card->ospriv, "Failed to write bootstrap value %d\n", i); | |
3500 | /* Might not be fatal */ | |
3501 | } | |
3502 | ||
3503 | CsrThreadSleep(1); | |
3504 | } | |
3505 | } | |
3506 | } /* bootstrap_chip_hw() */ | |
3507 | ||
3508 | ||
3509 | /* | |
3510 | * --------------------------------------------------------------------------- | |
3511 | * unifi_card_stop_processor | |
3512 | * | |
3513 | * Stop the UniFi XAP processors. | |
3514 | * | |
3515 | * Arguments: | |
3516 | * card Pointer to card struct | |
3517 | * which One of UNIFI_PROC_MAC, UNIFI_PROC_PHY, UNIFI_PROC_BOTH | |
3518 | * | |
3519 | * Returns: | |
3520 | * CSR_RESULT_SUCCESS if successful, or CSR error code | |
3521 | * --------------------------------------------------------------------------- | |
3522 | */ | |
3523 | CsrResult unifi_card_stop_processor(card_t *card, enum unifi_dbg_processors_select which) | |
3524 | { | |
3525 | CsrResult r = CSR_RESULT_SUCCESS; | |
7e6f5794 | 3526 | u8 status; |
ab2b8c73 | 3527 | s16 retry = 100; |
635d2b00 GKH |
3528 | |
3529 | while (retry--) | |
3530 | { | |
3531 | /* Select both XAPs */ | |
3532 | r = unifi_set_proc_select(card, which); | |
3533 | if (r != CSR_RESULT_SUCCESS) | |
3534 | { | |
3535 | break; | |
3536 | } | |
3537 | ||
3538 | /* Stop processors */ | |
3539 | r = unifi_write_direct16(card, ChipHelper_DBG_EMU_CMD(card->helper) * 2, 2); | |
3540 | if (r != CSR_RESULT_SUCCESS) | |
3541 | { | |
3542 | break; | |
3543 | } | |
3544 | ||
3545 | /* Read status */ | |
3546 | r = unifi_read_direct_8_or_16(card, | |
3547 | ChipHelper_DBG_HOST_STOP_STATUS(card->helper) * 2, | |
3548 | &status); | |
3549 | if (r != CSR_RESULT_SUCCESS) | |
3550 | { | |
3551 | break; | |
3552 | } | |
3553 | ||
3554 | if ((status & 1) == 1) | |
3555 | { | |
3556 | /* Success! */ | |
3557 | return CSR_RESULT_SUCCESS; | |
3558 | } | |
3559 | ||
3560 | /* Processors didn't stop, try again */ | |
3561 | } | |
3562 | ||
3563 | if (r != CSR_RESULT_SUCCESS) | |
3564 | { | |
3565 | /* An SDIO error occurred */ | |
3566 | unifi_error(card->ospriv, "Failed to stop processors: SDIO error\n"); | |
3567 | } | |
3568 | else | |
3569 | { | |
3570 | /* If we reach here, we didn't the status in time. */ | |
3571 | unifi_error(card->ospriv, "Failed to stop processors: timeout waiting for stopped status\n"); | |
3572 | r = CSR_RESULT_FAILURE; | |
3573 | } | |
3574 | ||
3575 | return r; | |
3576 | } /* unifi_card_stop_processor() */ | |
3577 | ||
3578 | ||
3579 | /* | |
3580 | * --------------------------------------------------------------------------- | |
3581 | * card_start_processor | |
3582 | * | |
3583 | * Start the UniFi XAP processors. | |
3584 | * | |
3585 | * Arguments: | |
3586 | * card Pointer to card struct | |
3587 | * which One of UNIFI_PROC_MAC, UNIFI_PROC_PHY, UNIFI_PROC_BOTH | |
3588 | * | |
3589 | * Returns: | |
3590 | * CSR_RESULT_SUCCESS or CSR error code | |
3591 | * --------------------------------------------------------------------------- | |
3592 | */ | |
3593 | CsrResult card_start_processor(card_t *card, enum unifi_dbg_processors_select which) | |
3594 | { | |
3595 | CsrResult r; | |
3596 | ||
3597 | /* Select both XAPs */ | |
3598 | r = unifi_set_proc_select(card, which); | |
3599 | if (r != CSR_RESULT_SUCCESS) | |
3600 | { | |
3601 | unifi_error(card->ospriv, "unifi_set_proc_select failed: %d.\n", r); | |
3602 | return r; | |
3603 | } | |
3604 | ||
3605 | ||
3606 | r = unifi_write_direct_8_or_16(card, | |
3607 | ChipHelper_DBG_EMU_CMD(card->helper) * 2, 8); | |
3608 | if (r != CSR_RESULT_SUCCESS) | |
3609 | { | |
3610 | return r; | |
3611 | } | |
3612 | ||
3613 | r = unifi_write_direct_8_or_16(card, | |
3614 | ChipHelper_DBG_EMU_CMD(card->helper) * 2, 0); | |
3615 | if (r != CSR_RESULT_SUCCESS) | |
3616 | { | |
3617 | return r; | |
3618 | } | |
3619 | ||
3620 | return CSR_RESULT_SUCCESS; | |
3621 | } /* card_start_processor() */ | |
3622 | ||
3623 | ||
3624 | /* | |
3625 | * --------------------------------------------------------------------------- | |
3626 | * unifi_set_interrupt_mode | |
3627 | * | |
3628 | * Configure the interrupt processing mode used by the HIP | |
3629 | * | |
3630 | * Arguments: | |
3631 | * card Pointer to card struct | |
3632 | * mode Interrupt mode to apply | |
3633 | * | |
3634 | * Returns: | |
3635 | * None | |
3636 | * --------------------------------------------------------------------------- | |
3637 | */ | |
26a6b2e1 | 3638 | void unifi_set_interrupt_mode(card_t *card, u32 mode) |
635d2b00 GKH |
3639 | { |
3640 | if (mode == CSR_WIFI_INTMODE_RUN_BH_ONCE) | |
3641 | { | |
3642 | unifi_info(card->ospriv, "Scheduled interrupt mode"); | |
3643 | } | |
3644 | card->intmode = mode; | |
3645 | } /* unifi_set_interrupt_mode() */ | |
3646 | ||
3647 | ||
3648 | /* | |
3649 | * --------------------------------------------------------------------------- | |
3650 | * unifi_start_processors | |
3651 | * | |
3652 | * Start all UniFi XAP processors. | |
3653 | * | |
3654 | * Arguments: | |
3655 | * card Pointer to card struct | |
3656 | * | |
3657 | * Returns: | |
3658 | * CSR_RESULT_SUCCESS on success, CSR error code on error | |
3659 | * --------------------------------------------------------------------------- | |
3660 | */ | |
3661 | CsrResult unifi_start_processors(card_t *card) | |
3662 | { | |
3663 | return card_start_processor(card, UNIFI_PROC_BOTH); | |
3664 | } /* unifi_start_processors() */ | |
3665 | ||
3666 | ||
3667 | /* | |
3668 | * --------------------------------------------------------------------------- | |
3669 | * unifi_request_max_sdio_clock | |
3670 | * | |
3671 | * Requests that the maximum SDIO clock rate is set at the next suitable | |
3672 | * opportunity (e.g. when the BH next runs, so as not to interfere with | |
3673 | * any current operation). | |
3674 | * | |
3675 | * Arguments: | |
3676 | * card Pointer to card struct | |
3677 | * | |
3678 | * Returns: | |
3679 | * None | |
3680 | * --------------------------------------------------------------------------- | |
3681 | */ | |
3682 | void unifi_request_max_sdio_clock(card_t *card) | |
3683 | { | |
3684 | card->request_max_clock = 1; | |
3685 | } /* unifi_request_max_sdio_clock() */ | |
3686 | ||
3687 | ||
3688 | /* | |
3689 | * --------------------------------------------------------------------------- | |
3690 | * unifi_set_host_state | |
3691 | * | |
3692 | * Set the host deep-sleep state. | |
3693 | * | |
3694 | * If transitioning to TORPID, the SDIO driver will be notified | |
3695 | * that the SD bus will be unused (idle) and conversely, when | |
3696 | * transitioning from TORPID that the bus will be used (active). | |
3697 | * | |
3698 | * Arguments: | |
3699 | * card Pointer to card struct | |
3700 | * state New deep-sleep state. | |
3701 | * | |
3702 | * Returns: | |
3703 | * CSR_RESULT_SUCCESS on success | |
3704 | * CSR_WIFI_HIP_RESULT_NO_DEVICE if the card was ejected | |
3705 | * CSR_RESULT_FAILURE if an SDIO error occurred | |
3706 | * | |
3707 | * Notes: | |
3708 | * We need to reduce the SDIO clock speed before trying to wake up the | |
3709 | * chip. Actually, in the implementation below we reduce the clock speed | |
3710 | * not just before we try to wake up the chip, but when we put the chip to | |
3711 | * deep sleep. This means that if the f/w wakes up on its' own, we waste | |
3712 | * a reduce/increace cycle. However, trying to eliminate this overhead is | |
3713 | * proved difficult, as the current state machine in the HIP lib does at | |
3714 | * least a CMD52 to disable the interrupts before we configure the host | |
3715 | * state. | |
3716 | * --------------------------------------------------------------------------- | |
3717 | */ | |
3718 | CsrResult unifi_set_host_state(card_t *card, enum unifi_host_state state) | |
3719 | { | |
3720 | CsrResult r = CSR_RESULT_SUCCESS; | |
3721 | CsrResult csrResult; | |
c781b96b | 3722 | static const char *const states[] = { |
635d2b00 GKH |
3723 | "AWAKE", "DROWSY", "TORPID" |
3724 | }; | |
7e6f5794 | 3725 | static const u8 state_csr_host_wakeup[] = { |
635d2b00 GKH |
3726 | 1, 3, 0 |
3727 | }; | |
7e6f5794 | 3728 | static const u8 state_io_abort[] = { |
635d2b00 GKH |
3729 | 0, 2, 3 |
3730 | }; | |
3731 | ||
3732 | unifi_trace(card->ospriv, UDBG4, "State %s to %s\n", | |
3733 | states[card->host_state], states[state]); | |
3734 | ||
3735 | if (card->host_state == UNIFI_HOST_STATE_TORPID) | |
3736 | { | |
3737 | CsrSdioFunctionActive(card->sdio_if); | |
3738 | } | |
3739 | ||
3740 | /* Write the new state to UniFi. */ | |
3741 | if (card->chip_id > SDIO_CARD_ID_UNIFI_2) | |
3742 | { | |
3743 | r = sdio_write_f0(card, SDIO_CSR_HOST_WAKEUP, | |
7e6f5794 | 3744 | (u8)((card->function << 4) | state_csr_host_wakeup[state])); |
635d2b00 GKH |
3745 | } |
3746 | else | |
3747 | { | |
3748 | r = sdio_write_f0(card, SDIO_IO_ABORT, state_io_abort[state]); | |
3749 | } | |
3750 | ||
3751 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3752 | { | |
3753 | return r; | |
3754 | } | |
3755 | if (r != CSR_RESULT_SUCCESS) | |
3756 | { | |
3757 | unifi_error(card->ospriv, "Failed to write UniFi deep sleep state\n"); | |
3758 | } | |
3759 | else | |
3760 | { | |
3761 | /* | |
3762 | * If the chip was in state TORPID then we can now increase | |
3763 | * the maximum bus clock speed. | |
3764 | */ | |
3765 | if (card->host_state == UNIFI_HOST_STATE_TORPID) | |
3766 | { | |
3767 | csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, | |
3768 | UNIFI_SDIO_CLOCK_MAX_HZ); | |
3769 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
3770 | /* Non-fatal error */ | |
3771 | if (r != CSR_RESULT_SUCCESS && r != CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3772 | { | |
3773 | unifi_warning(card->ospriv, | |
3774 | "Failed to increase the SDIO clock speed\n"); | |
3775 | } | |
3776 | else | |
3777 | { | |
3778 | card->sdio_clock_speed = UNIFI_SDIO_CLOCK_MAX_HZ; | |
3779 | } | |
3780 | } | |
3781 | ||
3782 | /* | |
3783 | * Cache the current state in the card structure to avoid | |
3784 | * unnecessary SDIO reads. | |
3785 | */ | |
3786 | card->host_state = state; | |
3787 | ||
3788 | if (state == UNIFI_HOST_STATE_TORPID) | |
3789 | { | |
3790 | /* | |
3791 | * If the chip is now in state TORPID then we must now decrease | |
3792 | * the maximum bus clock speed. | |
3793 | */ | |
3794 | csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, | |
3795 | UNIFI_SDIO_CLOCK_SAFE_HZ); | |
3796 | r = ConvertCsrSdioToCsrHipResult(card, csrResult); | |
3797 | if (r != CSR_RESULT_SUCCESS && r != CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3798 | { | |
3799 | unifi_warning(card->ospriv, | |
3800 | "Failed to decrease the SDIO clock speed\n"); | |
3801 | } | |
3802 | else | |
3803 | { | |
3804 | card->sdio_clock_speed = UNIFI_SDIO_CLOCK_SAFE_HZ; | |
3805 | } | |
3806 | CsrSdioFunctionIdle(card->sdio_if); | |
3807 | } | |
3808 | } | |
3809 | ||
3810 | return r; | |
3811 | } /* unifi_set_host_state() */ | |
3812 | ||
3813 | ||
3814 | /* | |
3815 | * --------------------------------------------------------------------------- | |
3816 | * unifi_card_info | |
3817 | * | |
3818 | * Update the card information data structure | |
3819 | * | |
3820 | * Arguments: | |
3821 | * card Pointer to card struct | |
3822 | * card_info Pointer to info structure to update | |
3823 | * | |
3824 | * Returns: | |
3825 | * None | |
3826 | * --------------------------------------------------------------------------- | |
3827 | */ | |
3828 | void unifi_card_info(card_t *card, card_info_t *card_info) | |
3829 | { | |
3830 | card_info->chip_id = card->chip_id; | |
3831 | card_info->chip_version = card->chip_version; | |
3832 | card_info->fw_build = card->build_id; | |
3833 | card_info->fw_hip_version = card->config_data.version; | |
3834 | card_info->sdio_block_size = card->sdio_io_block_size; | |
3835 | } /* unifi_card_info() */ | |
3836 | ||
3837 | ||
3838 | /* | |
3839 | * --------------------------------------------------------------------------- | |
3840 | * unifi_check_io_status | |
3841 | * | |
3842 | * Check UniFi for spontaneous reset and pending interrupt. | |
3843 | * | |
3844 | * Arguments: | |
3845 | * card Pointer to card struct | |
3846 | * status Pointer to location to write chip status: | |
3847 | * 0 if UniFi is running, and no interrupt pending | |
3848 | * 1 if UniFi has spontaneously reset | |
3849 | * 2 if there is a pending interrupt | |
3850 | * Returns: | |
3851 | * CSR_RESULT_SUCCESS if OK, or CSR error | |
3852 | * --------------------------------------------------------------------------- | |
3853 | */ | |
95e326c2 | 3854 | CsrResult unifi_check_io_status(card_t *card, s32 *status) |
635d2b00 | 3855 | { |
7e6f5794 | 3856 | u8 io_en; |
635d2b00 | 3857 | CsrResult r; |
5379b13d | 3858 | u8 pending; |
635d2b00 GKH |
3859 | |
3860 | *status = 0; | |
3861 | ||
3862 | r = sdio_read_f0(card, SDIO_IO_ENABLE, &io_en); | |
3863 | if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE) | |
3864 | { | |
3865 | return r; | |
3866 | } | |
3867 | if (r != CSR_RESULT_SUCCESS) | |
3868 | { | |
3869 | unifi_error(card->ospriv, "Failed to read SDIO_IO_ENABLE to check for spontaneous reset\n"); | |
3870 | return r; | |
3871 | } | |
3872 | ||
3873 | if ((io_en & (1 << card->function)) == 0) | |
3874 | { | |
95e326c2 | 3875 | s32 fw_count; |
635d2b00 GKH |
3876 | *status = 1; |
3877 | unifi_error(card->ospriv, "UniFi has spontaneously reset.\n"); | |
3878 | ||
3879 | /* | |
3880 | * These reads are very likely to fail. We want to know if the function is really | |
3881 | * disabled or the SDIO driver just returns rubbish. | |
3882 | */ | |
3883 | fw_count = unifi_read_shared_count(card, card->sdio_ctrl_addr + 4); | |
3884 | if (fw_count < 0) | |
3885 | { | |
3886 | unifi_error(card->ospriv, "Failed to read to-host sig written count\n"); | |
3887 | } | |
3888 | else | |
3889 | { | |
3890 | unifi_error(card->ospriv, "thsw: %u (driver thinks is %u)\n", | |
3891 | fw_count, card->to_host_signals_w); | |
3892 | } | |
3893 | fw_count = unifi_read_shared_count(card, card->sdio_ctrl_addr + 2); | |
3894 | if (fw_count < 0) | |
3895 | { | |
3896 | unifi_error(card->ospriv, "Failed to read from-host sig read count\n"); | |
3897 | } | |
3898 | else | |
3899 | { | |
3900 | unifi_error(card->ospriv, "fhsr: %u (driver thinks is %u)\n", | |
3901 | fw_count, card->from_host_signals_r); | |
3902 | } | |
3903 | ||
3904 | return r; | |
3905 | } | |
3906 | ||
3907 | unifi_info(card->ospriv, "UniFi function %d is enabled.\n", card->function); | |
3908 | ||
3909 | /* See if we missed an SDIO interrupt */ | |
3910 | r = CardPendingInt(card, &pending); | |
3911 | if (pending) | |
3912 | { | |
3913 | unifi_error(card->ospriv, "There is an unhandled pending interrupt.\n"); | |
3914 | *status = 2; | |
3915 | return r; | |
3916 | } | |
3917 | ||
3918 | return r; | |
3919 | } /* unifi_check_io_status() */ | |
3920 | ||
3921 | ||
3922 | void unifi_get_hip_qos_info(card_t *card, unifi_HipQosInfo *hipqosinfo) | |
3923 | { | |
95e326c2 | 3924 | s32 count_fhr; |
ab2b8c73 | 3925 | s16 t; |
26a6b2e1 | 3926 | u32 occupied_fh; |
635d2b00 GKH |
3927 | |
3928 | q_t *sigq; | |
8c87f69a | 3929 | u16 nslots, i; |
635d2b00 | 3930 | |
b7244a31 | 3931 | memset(hipqosinfo, 0, sizeof(unifi_HipQosInfo)); |
635d2b00 GKH |
3932 | |
3933 | nslots = card->config_data.num_fromhost_data_slots; | |
3934 | ||
3935 | for (i = 0; i < nslots; i++) | |
3936 | { | |
3937 | if (card->from_host_data[i].bd.data_length == 0) | |
3938 | { | |
3939 | hipqosinfo->free_fh_bulkdata_slots++; | |
3940 | } | |
3941 | } | |
3942 | ||
3943 | for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) | |
3944 | { | |
3945 | sigq = &card->fh_traffic_queue[i]; | |
3946 | t = sigq->q_wr_ptr - sigq->q_rd_ptr; | |
3947 | if (t < 0) | |
3948 | { | |
3949 | t += sigq->q_length; | |
3950 | } | |
3951 | hipqosinfo->free_fh_sig_queue_slots[i] = (sigq->q_length - t) - 1; | |
3952 | } | |
3953 | ||
3954 | count_fhr = unifi_read_shared_count(card, card->sdio_ctrl_addr + 2); | |
3955 | if (count_fhr < 0) | |
3956 | { | |
3957 | unifi_error(card->ospriv, "Failed to read from-host sig read count - %d\n", count_fhr); | |
3958 | hipqosinfo->free_fh_fw_slots = 0xfa; | |
3959 | return; | |
3960 | } | |
3961 | ||
3962 | occupied_fh = (card->from_host_signals_w - count_fhr) % 128; | |
3963 | ||
8c87f69a | 3964 | hipqosinfo->free_fh_fw_slots = (u16)(card->config_data.num_fromhost_sig_frags - occupied_fh); |
635d2b00 GKH |
3965 | } |
3966 | ||
3967 | ||
3968 | ||
3969 | CsrResult ConvertCsrSdioToCsrHipResult(card_t *card, CsrResult csrResult) | |
3970 | { | |
3971 | CsrResult r = CSR_RESULT_FAILURE; | |
3972 | ||
3973 | switch (csrResult) | |
3974 | { | |
3975 | case CSR_RESULT_SUCCESS: | |
3976 | r = CSR_RESULT_SUCCESS; | |
3977 | break; | |
3978 | /* Timeout errors */ | |
3979 | case CSR_SDIO_RESULT_TIMEOUT: | |
3980 | /* Integrity errors */ | |
3981 | case CSR_SDIO_RESULT_CRC_ERROR: | |
3982 | r = CSR_RESULT_FAILURE; | |
3983 | break; | |
3984 | case CSR_SDIO_RESULT_NO_DEVICE: | |
3985 | r = CSR_WIFI_HIP_RESULT_NO_DEVICE; | |
3986 | break; | |
3987 | case CSR_SDIO_RESULT_INVALID_VALUE: | |
3988 | r = CSR_WIFI_HIP_RESULT_INVALID_VALUE; | |
3989 | break; | |
3990 | case CSR_RESULT_FAILURE: | |
3991 | r = CSR_RESULT_FAILURE; | |
3992 | break; | |
3993 | default: | |
3994 | unifi_warning(card->ospriv, "Unrecognised csrResult error code: %d\n", csrResult); | |
3995 | break; | |
3996 | } | |
3997 | ||
3998 | return r; | |
3999 | } /* ConvertCsrSdioToCsrHipResult() */ | |
4000 | ||
4001 |