1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * DHD Bus Module for SDIO
4 *
5 * Copyright (C) 1999-2019, Broadcom.
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 *
26 * <<Broadcom-WL-IPTag/Open:>>
27 *
28 * $Id: dhd_sdio.c 825481 2019-06-14 10:06:03Z $
29 */
30
31 #include <typedefs.h>
32 #include <osl.h>
33 #include <bcmsdh.h>
34
35 #include <bcmdefs.h>
36 #include <bcmutils.h>
37 #include <bcmendian.h>
38 #include <bcmdevs.h>
39
40 #include <siutils.h>
41 #include <hndpmu.h>
42 #include <hndsoc.h>
43 #include <hnd_armtrap.h>
44 #include <sbchipc.h>
45 #include <sbhnddma.h>
46
47 #include <sdio.h>
48 #ifdef BCMSPI
49 #include <spid.h>
50 #endif /* BCMSPI */
51 #include <sbsdio.h>
52 #include <bcmsdpcm.h>
53 #include <bcmsdbus.h>
54
55 #include <ethernet.h>
56 #include <802.1d.h>
57 #include <802.11.h>
58
59 #include <dngl_stats.h>
60 #include <dhd.h>
61 #include <dhd_bus.h>
62 #include <dhd_proto.h>
63 #include <dhd_dbg.h>
64 #include <dhdioctl.h>
65 #include <sdiovar.h>
66 #include <dhd_config.h>
67
68 #ifdef PROP_TXSTATUS
69 #include <dhd_wlfc.h>
70 #endif // endif
71 #ifdef DHDTCPACK_SUPPRESS
72 #include <dhd_ip.h>
73 #endif /* DHDTCPACK_SUPPRESS */
74
75 #ifdef BT_OVER_SDIO
76 #include <dhd_bt_interface.h>
77 #endif /* BT_OVER_SDIO */
78
79 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
80 #include <debugger.h>
81 #endif /* DEBUGGER || DHD_DSCOPE */
82
83 bool dhd_mp_halting(dhd_pub_t *dhdp);
84 extern void bcmsdh_waitfor_iodrain(void *sdh);
85 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
86 extern bool bcmsdh_fatal_error(void *sdh);
87 static int dhdsdio_suspend(void *context);
88 static int dhdsdio_resume(void *context);
89
90 #ifndef DHDSDIO_MEM_DUMP_FNAME
91 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
92 #endif // endif
93
94 #define QLEN (1024) /* bulk rx and tx queue lengths */
95 #define FCHI (QLEN - 10)
96 #define FCLOW (FCHI / 2)
97 #define PRIOMASK 7
98
99 #define F0_BLOCK_SIZE 32
100 #define TXRETRIES 2 /* # of retries for tx frames */
101 #define READ_FRM_CNT_RETRIES 3
102 #ifndef DHD_RXBOUND
103 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
104 #endif // endif
105
106 #ifndef DHD_TXBOUND
107 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
108 #endif // endif
109
110 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
111
112 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
113 #define MAX_MEMBLOCK (32 * 1024) /* Block size used for downloading of dongle image */
114
115 #define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
116 #define MAX_MEM_BUF 4096
117
118 #ifndef DHD_FIRSTREAD
119 #define DHD_FIRSTREAD 32
120 #endif // endif
121 #if !ISPOWEROF2(DHD_FIRSTREAD)
122 #error DHD_FIRSTREAD is not a power of 2!
123 #endif // endif
124
125 /* Total length of frame header for dongle protocol */
126 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
127 #define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN)
128 #define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE
129
130 #ifdef SDTEST
131 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
132 #else
133 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
134 #endif // endif
135
136 /* Space for header read, limit for data packets */
137 #if !ISPOWEROF2(MAX_HDR_READ)
138 #error MAX_HDR_READ is not a power of 2!
139 #endif // endif
140
141 #define MAX_RX_DATASZ 2048
142
143 /* Maximum milliseconds to wait for F2 to come up */
144 #define DHD_WAIT_F2RDY 3000
145
146 /* Maximum usec to wait for HTAVAIL to come up */
147 #define DHD_WAIT_HTAVAIL 10000
148
149 /* Bump up limit on waiting for HT to account for first startup;
150 * if the image is doing a CRC calculation before programming the PMU
151 * for HT availability, it could take a couple hundred ms more, so
152 * max out at a 1 second (1000000us).
153 */
154 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
155 #undef PMU_MAX_TRANSITION_DLY
156 #ifdef NO_EXT32K
157 #define PMU_MAX_TRANSITION_DLY (1000000*5)
158 #else
159 #define PMU_MAX_TRANSITION_DLY 1000000
160 #endif
161 #endif // endif
162
163 /* hooks for limiting threshold custom tx num in rx processing */
164 #define DEFAULT_TXINRX_THRES 0
165 #ifndef CUSTOM_TXINRX_THRES
166 #define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES
167 #endif // endif
168
169 /* Value for ChipClockCSR during initial setup */
170 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
171 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
172
173 /* Flags for SDH calls */
174 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
175
176 /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
177 * bufpool was present for gspi bus.
178 */
179 #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
180 PKTFREE(bus->dhd->osh, pkt, FALSE);
181 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
182
183 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
184 extern unsigned int system_hw_rev;
185 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
186
187 /* Device console log buffer state */
188 #define CONSOLE_LINE_MAX 192
189 #define CONSOLE_BUFFER_MAX 8192
190
191 #define REMAP_ENAB(bus) ((bus)->remap)
192 #define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
193 #define KSO_ENAB(bus) ((bus)->kso)
194 #define SR_ENAB(bus) ((bus)->_srenab)
195 #define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto))
196
197 #define MIN_RSRC_SR 0x3
198 #define CORE_CAPEXT_ADDR_OFFSET (0x64c)
199 #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
200 #define RCTL_MACPHY_DISABLE_MASK (1 << 26)
201 #define RCTL_LOGIC_DISABLE_MASK (1 << 27)
202
203 #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
204 #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
205 #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
206 #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
207 #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
208 #define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
209 #define OVERFLOW_BLKSZ512_WM 96
210 #define OVERFLOW_BLKSZ512_MES 80
211
212 #define CC_PMUCC3 (0x3)
213
214 #ifdef DHD_UCODE_DOWNLOAD
215 /* Ucode host download related macros */
216 #define UCODE_DOWNLOAD_REQUEST 0xCAFECAFE
217 #define UCODE_DOWNLOAD_COMPLETE 0xABCDABCD
218 #endif /* DHD_UCODE_DOWNLOAD */
219
220 #if defined(BT_OVER_SDIO)
221 #define BTMEM_OFFSET 0x19000000
222 /* BIT0 => WLAN Power UP and BIT1=> WLAN Wake */
223 #define BT2WLAN_PWRUP_WAKE 0x03
224 #define BT2WLAN_PWRUP_ADDR 0x640894 /* This address is specific to 43012B0 */
225
226 #define BTFW_MAX_STR_LEN 600
227 #define BTFW_DOWNLOAD_BLK_SIZE (BTFW_MAX_STR_LEN/2 + 8)
228
229 #define BTFW_ADDR_MODE_UNKNOWN 0
230 #define BTFW_ADDR_MODE_EXTENDED 1
231 #define BTFW_ADDR_MODE_SEGMENT 2
232 #define BTFW_ADDR_MODE_LINEAR32 3
233
234 #define BTFW_HEX_LINE_TYPE_DATA 0
235 #define BTFW_HEX_LINE_TYPE_END_OF_DATA 1
236 #define BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS 2
237 #define BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS 4
238 #define BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS 5
239
240 #endif /* defined (BT_OVER_SDIO) */
241
242 /*
243 * Whenever DHD_IDLE_IMMEDIATE condition is handled, we have to now check if
244 * BT is active too. Instead of adding #ifdef code in all the places, we thought
245 * of adding one macro check as part of the if condition that checks for DHD_IDLE_IMMEDIATE
246 * In case of non BT over SDIO builds, this macro will always return TRUE. In case
247 * of the builds where BT_OVER_SDIO is enabled, it will expand to a condition check
248 * that checks if bt_use_count is zero. So this macro will return equate to 1 if
249 * bt_use_count is 0, indicating that there are no active users and if bt_use_count
250 * is non zero it would return 0 there by preventing the caller from executing the
251 * sleep calls.
252 */
253 #ifdef BT_OVER_SDIO
254 #define NO_OTHER_ACTIVE_BUS_USER(bus) (bus->bt_use_count == 0)
255 #else
256 #define NO_OTHER_ACTIVE_BUS_USER(bus) (1)
257 #endif /* BT_OVER_SDIO */
258
259 /* clkstate */
260 #define CLK_NONE 0
261 #define CLK_SDONLY 1
262 #define CLK_PENDING 2 /* Not used yet */
263 #define CLK_AVAIL 3
264
265 #define DHD_NOPMU(dhd) (FALSE)
266
267 #if defined(BCMSDIOH_STD)
268 #define BLK_64_MAXTXGLOM 20
269 #endif /* BCMSDIOH_STD */
270
271 #ifdef DHD_DEBUG
272 static int qcount[NUMPRIO];
273 static int tx_packets[NUMPRIO];
274 #endif /* DHD_DEBUG */
275
276 /* Deferred transmit */
277 const uint dhd_deferred_tx = 1;
278
279 extern uint dhd_watchdog_ms;
280 extern uint sd_f1_blocksize;
281
282 #ifdef BCMSPI_ANDROID
283 extern uint *dhd_spi_lockcount;
284 #endif /* BCMSPI_ANDROID */
285
286 extern void dhd_os_wd_timer(void *bus, uint wdtick);
287 int dhd_enableOOB(dhd_pub_t *dhd, bool sleep);
288
289 #ifdef DHD_PM_CONTROL_FROM_FILE
290 extern bool g_pm_control;
291 #endif /* DHD_PM_CONTROL_FROM_FILE */
292
293 /* Tx/Rx bounds */
294 uint dhd_txbound;
295 uint dhd_rxbound;
296 uint dhd_txminmax = DHD_TXMINMAX;
297
298 /* override the RAM size if possible */
299 #define DONGLE_MIN_RAMSIZE (128 *1024)
300 int dhd_dongle_ramsize;
301
302 uint dhd_doflow = TRUE;
303 uint dhd_dpcpoll = FALSE;
304
305 module_param(dhd_doflow, uint, 0644);
306 module_param(dhd_dpcpoll, uint, 0644);
307
308 static bool dhd_alignctl;
309
310 static bool sd1idle;
311
312 static bool retrydata;
313 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
314
315 #ifdef BCMSPI
316 /* At a watermark around 8 the spid hits underflow error. */
317 static uint watermark = 32;
318 static uint mesbusyctrl = 0;
319 #else
320 static uint watermark = 8;
321 static uint mesbusyctrl = 0;
322 #endif /* BCMSPI */
323 #ifdef DYNAMIC_MAX_HDR_READ
324 uint firstread = DHD_FIRSTREAD;
325 #else
326 static const uint firstread = DHD_FIRSTREAD;
327 #endif
328
329 /* Retry count for register access failures */
330 static const uint retry_limit = 2;
331
332 /* Force even SD lengths (some host controllers mess up on odd bytes) */
333 static bool forcealign;
334
335 #if defined(DEBUGGER)
336 static uint32 dhd_sdio_reg_read(struct dhd_bus *bus, ulong addr);
337 static void dhd_sdio_reg_write(struct dhd_bus *bus, ulong addr, uint32 val);
338
339 /** the debugger layer will call back into this (bus) layer to read/write dongle memory */
340 static struct dhd_dbg_bus_ops_s bus_ops = {
341 .read_u16 = NULL,
342 .read_u32 = dhd_sdio_reg_read,
343 .write_u32 = dhd_sdio_reg_write,
344 };
345 #endif /* DEBUGGER */
346
347 #define ALIGNMENT 4
348
349 #if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN)
350 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
351 #endif // endif
352
353 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
354 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
355 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
356 #define PKTALIGN(osh, p, len, align) \
357 do { \
358 uintptr datalign; \
359 datalign = (uintptr)PKTDATA((osh), (p)); \
360 datalign = ROUNDUP(datalign, (align)) - datalign; \
361 ASSERT(datalign < (align)); \
362 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
363 if (datalign) \
364 PKTPULL((osh), (p), (uint)datalign); \
365 PKTSETLEN((osh), (p), (len)); \
366 } while (0)
367
368 /* Limit on rounding up frames */
369 static const uint max_roundup = 512;
370
371 /* Try doing readahead */
372 static bool dhd_readahead;
373
374 #if defined(BCMSDIOH_TXGLOM_EXT)
375 bool
dhdsdio_is_dataok(dhd_bus_t * bus)376 dhdsdio_is_dataok(dhd_bus_t *bus) {
377 return (((uint8)(bus->tx_max - bus->tx_seq) - bus->dhd->conf->tx_max_offset > 1) && \
378 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0));
379 }
380
381 uint8
dhdsdio_get_databufcnt(dhd_bus_t * bus)382 dhdsdio_get_databufcnt(dhd_bus_t *bus) {
383 return ((uint8)(bus->tx_max - bus->tx_seq) - 1 - bus->dhd->conf->tx_max_offset);
384 }
385 #endif
386
387 /* To check if there's window offered */
388 #if defined(BCMSDIOH_TXGLOM_EXT)
389 #define DATAOK(bus) dhdsdio_is_dataok(bus)
390 #else
391 #define DATAOK(bus) \
392 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
393 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
394 #endif
395
396 /* To check if there's window offered for ctrl frame */
397 #define TXCTLOK(bus) \
398 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
399 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
400
401 /* Number of pkts available in dongle for data RX */
402 #if defined(BCMSDIOH_TXGLOM_EXT)
403 #define DATABUFCNT(bus) dhdsdio_get_databufcnt(bus)
404 #else
405 #define DATABUFCNT(bus) \
406 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
407 #endif
408
409 /* Macros to get register read/write status */
410 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
411 #define R_SDREG(regvar, regaddr, retryvar) \
412 do { \
413 retryvar = 0; \
414 do { \
415 regvar = R_REG(bus->dhd->osh, regaddr); \
416 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
417 if (retryvar) { \
418 bus->regfails += (retryvar-1); \
419 if (retryvar > retry_limit) { \
420 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
421 __FUNCTION__, __LINE__)); \
422 regvar = 0; \
423 } \
424 } \
425 } while (0)
426
427 #define W_SDREG(regval, regaddr, retryvar) \
428 do { \
429 retryvar = 0; \
430 do { \
431 W_REG(bus->dhd->osh, regaddr, regval); \
432 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
433 if (retryvar) { \
434 bus->regfails += (retryvar-1); \
435 if (retryvar > retry_limit) \
436 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
437 __FUNCTION__, __LINE__)); \
438 } \
439 } while (0)
440
441 #define BUS_WAKE(bus) \
442 do { \
443 bus->idlecount = 0; \
444 if ((bus)->sleeping) \
445 dhdsdio_bussleep((bus), FALSE); \
446 } while (0);
447
448 /*
449 * pktavail interrupts from dongle to host can be managed in 3 different ways
450 * whenever there is a packet available in dongle to transmit to host.
451 *
452 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
453 * Mode 1: (sdiod core rev >= 4)
454 * Device sets a new bit in the intstatus whenever there is a packet
455 * available in fifo. Host can't clear this specific status bit until all the
456 * packets are read from the FIFO. No need to ack dongle intstatus.
457 * Mode 2: (sdiod core rev >= 4)
458 * Device sets a bit in the intstatus, and host acks this by writing
459 * one to this bit. Dongle won't generate anymore packet interrupts
460 * until host reads all the packets from the dongle and reads a zero to
461 * figure that there are no more packets. No need to disable host ints.
462 * Need to ack the intstatus.
463 */
464
465 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
466 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
467 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
468
469 #ifdef BCMSPI
470
471 #define FRAME_AVAIL_MASK(bus) I_HMB_FRAME_IND
472
473 #define DHD_BUS SPI_BUS
474
475 /* check packet-available-interrupt in piggybacked dstatus */
476 #define PKT_AVAILABLE(bus, intstatus) (bcmsdh_get_dstatus(bus->sdh) & STATUS_F2_PKT_AVAILABLE)
477
478 #define HOSTINTMASK (I_HMB_FC_CHANGE | I_HMB_HOST_INT)
479
480 #define GSPI_PR55150_BAILOUT \
481 do { \
482 uint32 dstatussw = bcmsdh_get_dstatus((void *)bus->sdh); \
483 uint32 dstatushw = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL); \
484 uint32 intstatuserr = 0; \
485 uint retries = 0; \
486 \
487 R_SDREG(intstatuserr, &bus->regs->intstatus, retries); \
488 printf("dstatussw = 0x%x, dstatushw = 0x%x, intstatus = 0x%x\n", \
489 dstatussw, dstatushw, intstatuserr); \
490 \
491 bus->nextlen = 0; \
492 *finished = TRUE; \
493 } while (0)
494
495 #else /* BCMSDIO */
496
497 #define FRAME_AVAIL_MASK(bus) \
498 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
499
500 #define DHD_BUS SDIO_BUS
501
502 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
503
504 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
505
506 #define GSPI_PR55150_BAILOUT
507
508 #endif /* BCMSPI */
509
510 #ifdef SDTEST
511 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
512 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
513 #endif // endif
514
515 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
516 #ifdef DHD_DEBUG
517 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
518 #endif /* DHD_DEBUG */
519
520 #if defined(DHD_FW_COREDUMP)
521 static int dhdsdio_mem_dump(dhd_bus_t *bus);
522 static int dhdsdio_get_mem_dump(dhd_bus_t *bus);
523 #endif /* DHD_FW_COREDUMP */
524 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
525 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
526
527 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
528 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
529 static void dhdsdio_disconnect(void *ptr);
530 static bool dhdsdio_chipmatch(uint16 chipid);
531 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
532 void * regsva, uint16 devid);
533 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
534 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
535 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
536 bool reset_flag);
537
538 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
539 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
540 uint8 *buf, uint nbytes,
541 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
542 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
543 uint8 *buf, uint nbytes,
544 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry);
545 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt);
546 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
547 int prev_chain_total_len, bool last_chained_pkt,
548 int *pad_pkt_len, void **new_pkt
549 #if defined(BCMSDIOH_TXGLOM_EXT)
550 , int first_frame
551 #endif
552 );
553 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
554
555 static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
556 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
557
558 #ifdef DHD_UCODE_DOWNLOAD
559 static int dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path);
560 #endif /* DHD_UCODE_DOWNLOAD */
561 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
562 static int dhdsdio_download_nvram(dhd_bus_t *bus);
563 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
564 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
565 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
566 static bool dhdsdio_dpc(dhd_bus_t *bus);
567 static int dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len);
568 static int dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode);
569 static int dhdsdio_sdclk(dhd_bus_t *bus, bool on);
570 static void dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp);
571 static void dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp);
572
573 #if defined(BT_OVER_SDIO)
574 static int extract_hex_field(char * line, uint16 start_pos, uint16 num_chars, uint16 * value);
575 static int read_more_btbytes(struct dhd_bus *bus, void * file, char *line, int * addr_mode,
576 uint16 * hi_addr, uint32 * dest_addr, uint8 *data_bytes, uint32 * num_bytes);
577 static int dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh);
578 static int _dhdsdio_download_btfw(struct dhd_bus *bus);
579 #endif /* defined (BT_OVER_SDIO) */
580
581 #ifdef DHD_ULP
582 #include <dhd_ulp.h>
583 static int dhd_bus_ulp_reinit_fw(dhd_bus_t *bus);
584 #endif /* DHD_ULP */
585
586 #ifdef DHD_WAKE_STATUS
587 int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh);
588 int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag);
589 #endif /* DHD_WAKE_STATUS */
590
591 static void
dhdsdio_tune_fifoparam(struct dhd_bus * bus)592 dhdsdio_tune_fifoparam(struct dhd_bus *bus)
593 {
594 int err;
595 uint8 devctl, wm, mes;
596
597 if (bus->sih->buscorerev >= 15) {
598 /* See .ppt in PR for these recommended values */
599 if (bus->blocksize == 512) {
600 wm = OVERFLOW_BLKSZ512_WM;
601 mes = OVERFLOW_BLKSZ512_MES;
602 } else {
603 mes = bus->blocksize/4;
604 wm = bus->blocksize/4;
605 }
606
607 watermark = wm;
608 mesbusyctrl = mes;
609 } else {
610 DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n",
611 bus->sih->buscorerev));
612 return;
613 }
614
615 /* Update watermark */
616 if (wm > 0) {
617 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
618
619 devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
620 devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
621 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
622 }
623
624 /* Update MES */
625 if (mes > 0) {
626 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
627 (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
628 }
629
630 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
631 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
632 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
633 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
634 }
635
636 static void
dhd_dongle_setramsize(struct dhd_bus * bus,int mem_size)637 dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
638 {
639 int32 min_size = DONGLE_MIN_RAMSIZE;
640 /* Restrict the ramsize to user specified limit */
641 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
642 dhd_dongle_ramsize, min_size));
643 if ((dhd_dongle_ramsize > min_size) &&
644 (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
645 bus->ramsize = dhd_dongle_ramsize;
646 }
647
648 static int
dhdsdio_set_siaddr_window(dhd_bus_t * bus,uint32 address)649 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
650 {
651 int err = 0;
652 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
653 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
654 if (!err)
655 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
656 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
657 if (!err)
658 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
659 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
660 return err;
661 }
662
663 #ifdef BCMSPI
664 static void
dhdsdio_wkwlan(dhd_bus_t * bus,bool on)665 dhdsdio_wkwlan(dhd_bus_t *bus, bool on)
666 {
667 int err;
668 uint32 regdata;
669 bcmsdh_info_t *sdh = bus->sdh;
670
671 if (bus->sih->buscoretype == SDIOD_CORE_ID) {
672 /* wake up wlan function :WAKE_UP goes as ht_avail_request and alp_avail_request */
673 regdata = bcmsdh_cfg_read_word(sdh, SDIO_FUNC_0, SPID_CONFIG, NULL);
674 DHD_INFO(("F0 REG0 rd = 0x%x\n", regdata));
675
676 if (on == TRUE)
677 regdata |= WAKE_UP;
678 else
679 regdata &= ~WAKE_UP;
680
681 bcmsdh_cfg_write_word(sdh, SDIO_FUNC_0, SPID_CONFIG, regdata, &err);
682 }
683 }
684 #endif /* BCMSPI */
685
686 #ifdef USE_OOB_GPIO1
687 static int
dhdsdio_oobwakeup_init(dhd_bus_t * bus)688 dhdsdio_oobwakeup_init(dhd_bus_t *bus)
689 {
690 uint32 val, addr, data;
691
692 bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
693
694 addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
695 data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
696
697 /* Set device for gpio1 wakeup */
698 bcmsdh_reg_write(bus->sdh, addr, 4, 2);
699 val = bcmsdh_reg_read(bus->sdh, data, 4);
700 val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
701 bcmsdh_reg_write(bus->sdh, data, 4, val);
702
703 bus->_oobwakeup = TRUE;
704
705 return 0;
706 }
707 #endif /* USE_OOB_GPIO1 */
708
709 #ifndef BCMSPI
710 /*
711 * Query if FW is in SR mode
712 */
713 static bool
dhdsdio_sr_cap(dhd_bus_t * bus)714 dhdsdio_sr_cap(dhd_bus_t *bus)
715 {
716 bool cap = FALSE;
717 uint32 core_capext, addr, data;
718
719 if (bus->sih->chip == BCM43430_CHIP_ID ||
720 bus->sih->chip == BCM43018_CHIP_ID) {
721 /* check if fw initialized sr engine */
722 addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, sr_control1);
723 if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0)
724 cap = TRUE;
725
726 return cap;
727 }
728 if (
729 0) {
730 core_capext = FALSE;
731 } else if ((bus->sih->chip == BCM4330_CHIP_ID) ||
732 (bus->sih->chip == BCM43362_CHIP_ID) ||
733 (BCM4347_CHIP(bus->sih->chip))) {
734 core_capext = FALSE;
735 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
736 (bus->sih->chip == BCM4339_CHIP_ID) ||
737 BCM4345_CHIP(bus->sih->chip) ||
738 (bus->sih->chip == BCM4354_CHIP_ID) ||
739 (bus->sih->chip == BCM4358_CHIP_ID) ||
740 (bus->sih->chip == BCM43569_CHIP_ID) ||
741 (bus->sih->chip == BCM4371_CHIP_ID) ||
742 (BCM4349_CHIP(bus->sih->chip)) ||
743 (bus->sih->chip == BCM4350_CHIP_ID) ||
744 (bus->sih->chip == BCM4362_CHIP_ID) ||
745 (bus->sih->chip == BCM43012_CHIP_ID) ||
746 (bus->sih->chip == BCM43014_CHIP_ID) ||
747 (bus->sih->chip == BCM43751_CHIP_ID) ||
748 (bus->sih->chip == BCM43752_CHIP_ID)) {
749 core_capext = TRUE;
750 } else {
751 core_capext = bcmsdh_reg_read(bus->sdh,
752 si_get_pmu_reg_addr(bus->sih, OFFSETOF(chipcregs_t, core_cap_ext)),
753 4);
754 core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
755 }
756 if (!(core_capext))
757 return FALSE;
758
759 if ((bus->sih->chip == BCM4335_CHIP_ID) ||
760 (bus->sih->chip == BCM4339_CHIP_ID) ||
761 BCM4345_CHIP(bus->sih->chip) ||
762 (bus->sih->chip == BCM4354_CHIP_ID) ||
763 (bus->sih->chip == BCM4358_CHIP_ID) ||
764 (bus->sih->chip == BCM43569_CHIP_ID) ||
765 (bus->sih->chip == BCM4371_CHIP_ID) ||
766 (bus->sih->chip == BCM4350_CHIP_ID)) {
767 uint32 enabval = 0;
768 addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
769 data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
770 bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
771 enabval = bcmsdh_reg_read(bus->sdh, data, 4);
772
773 if ((bus->sih->chip == BCM4350_CHIP_ID) ||
774 BCM4345_CHIP(bus->sih->chip) ||
775 (bus->sih->chip == BCM4354_CHIP_ID) ||
776 (bus->sih->chip == BCM4358_CHIP_ID) ||
777 (bus->sih->chip == BCM43569_CHIP_ID) ||
778 (bus->sih->chip == BCM4371_CHIP_ID))
779 enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
780
781 if (enabval)
782 cap = TRUE;
783 } else {
784 data = bcmsdh_reg_read(bus->sdh,
785 si_get_pmu_reg_addr(bus->sih, OFFSETOF(chipcregs_t, retention_ctl)),
786 4);
787 if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
788 cap = TRUE;
789 }
790
791 return cap;
792 }
793
794 static int
dhdsdio_sr_init(dhd_bus_t * bus)795 dhdsdio_sr_init(dhd_bus_t *bus)
796 {
797 uint8 val;
798 int err = 0;
799
800 if (bus->sih->chip == BCM43012_CHIP_ID) {
801 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
802 val |= 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT;
803 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
804 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT, &err);
805 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
806 } else {
807 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
808 val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
809 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
810 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
811 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
812 }
813
814 #ifdef USE_CMD14
815 /* Add CMD14 Support */
816 dhdsdio_devcap_set(bus,
817 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
818 #endif /* USE_CMD14 */
819
820 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
821 CHIPID(bus->sih->chip) == BCM43018_CHIP_ID ||
822 CHIPID(bus->sih->chip) == BCM4339_CHIP_ID ||
823 CHIPID(bus->sih->chip) == BCM43012_CHIP_ID ||
824 CHIPID(bus->sih->chip) == BCM4362_CHIP_ID ||
825 CHIPID(bus->sih->chip) == BCM43014_CHIP_ID ||
826 CHIPID(bus->sih->chip) == BCM43751_CHIP_ID ||
827 CHIPID(bus->sih->chip) == BCM43752_CHIP_ID)
828 dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
829
830 if (bus->sih->chip == BCM43012_CHIP_ID) {
831 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
832 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_HT_AVAIL_REQ, &err);
833 } else {
834 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
835 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
836 }
837 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
838
839 bus->_srenab = TRUE;
840
841 return 0;
842 }
843 #endif /* BCMSPI */
844
845 /*
846 * FIX: Be sure KSO bit is enabled
847 * Currently, it's defaulting to 0 which should be 1.
848 */
849 static int
dhdsdio_clk_kso_init(dhd_bus_t * bus)850 dhdsdio_clk_kso_init(dhd_bus_t *bus)
851 {
852 uint8 val;
853 int err = 0;
854
855 /* set flag */
856 bus->kso = TRUE;
857
858 /*
859 * Enable KeepSdioOn (KSO) bit for normal operation
860 * Default is 0 (4334A0) so set it. Fixed in B0.
861 */
862 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
863 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
864 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
865 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
866 if (err)
867 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
868 }
869
870 return 0;
871 }
872
873 #define KSO_DBG(x)
874 #define KSO_WAIT_US 50
875 #define KSO_WAIT_MS 1
876 #define KSO_SLEEP_RETRY_COUNT 20
877 #define KSO_WAKE_RETRY_COUNT 100
878 #define ERROR_BCME_NODEVICE_MAX 1
879
880 #define DEFAULT_MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
881 #ifndef CUSTOM_MAX_KSO_ATTEMPTS
882 #define CUSTOM_MAX_KSO_ATTEMPTS DEFAULT_MAX_KSO_ATTEMPTS
883 #endif // endif
884
885 static int
dhdsdio_clk_kso_enab(dhd_bus_t * bus,bool on)886 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
887 {
888 uint8 wr_val = 0, rd_val, cmp_val, bmask;
889 int err = 0;
890 int try_cnt = 0;
891
892 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
893
894 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
895
896 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
897
898 /* In case of 43012 chip, the chip could go down immediately after KSO bit is cleared.
899 * So the further reads of KSO register could fail. Thereby just bailing out immediately
900 * after clearing KSO bit, to avoid polling of KSO bit.
901 */
902 if ((!on) && (bus->sih->chip == BCM43012_CHIP_ID)) {
903 return err;
904 }
905
906 if (on) {
907 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
908 bmask = cmp_val;
909
910 OSL_SLEEP(3);
911
912 } else {
913 /* Put device to sleep, turn off KSO */
914 cmp_val = 0;
915 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
916 }
917
918 do {
919 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
920 if (((rd_val & bmask) == cmp_val) && !err)
921 break;
922
923 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
924
925 if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) {
926 OSL_SLEEP(KSO_WAIT_MS);
927 } else
928 OSL_DELAY(KSO_WAIT_US);
929
930 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
931 } while (try_cnt++ < CUSTOM_MAX_KSO_ATTEMPTS);
932
933 if (try_cnt > 2)
934 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
935 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
936
937 if (try_cnt > CUSTOM_MAX_KSO_ATTEMPTS) {
938 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
939 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
940 }
941
942 return err;
943 }
944
945 static int
dhdsdio_clk_kso_iovar(dhd_bus_t * bus,bool on)946 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
947 {
948 int err = 0;
949
950 if (on == FALSE) {
951
952 BUS_WAKE(bus);
953 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
954
955 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
956 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
957 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
958 dhdsdio_clk_kso_enab(bus, FALSE);
959 } else {
960 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
961
962 /* Make sure we have SD bus access */
963 if (bus->clkstate == CLK_NONE) {
964 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
965 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
966 }
967
968 dhdsdio_clk_kso_enab(bus, TRUE);
969
970 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
971 dhdsdio_sleepcsr_get(bus)));
972 }
973
974 bus->kso = on;
975 BCM_REFERENCE(err);
976
977 return 0;
978 }
979
980 static uint8
dhdsdio_sleepcsr_get(dhd_bus_t * bus)981 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
982 {
983 int err = 0;
984 uint8 val = 0;
985
986 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
987 if (err)
988 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
989
990 return val;
991 }
992
993 uint8
dhdsdio_devcap_get(dhd_bus_t * bus)994 dhdsdio_devcap_get(dhd_bus_t *bus)
995 {
996 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
997 }
998
999 static int
dhdsdio_devcap_set(dhd_bus_t * bus,uint8 cap)1000 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
1001 {
1002 int err = 0;
1003
1004 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
1005 if (err)
1006 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
1007
1008 return 0;
1009 }
1010
1011 static int
dhdsdio_clk_devsleep_iovar(dhd_bus_t * bus,bool on)1012 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
1013 {
1014 int err = 0, retry;
1015 uint8 val;
1016
1017 retry = 0;
1018 if (on == TRUE) {
1019 /* Enter Sleep */
1020
1021 /* Be sure we request clk before going to sleep
1022 * so we can wake-up with clk request already set
1023 * else device can go back to sleep immediately
1024 */
1025 if (!SLPAUTO_ENAB(bus))
1026 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1027 else {
1028 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1029 if ((val & SBSDIO_CSR_MASK) == 0) {
1030 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
1031 __FUNCTION__, val));
1032
1033 /* Reset clock request */
1034 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1035 SBSDIO_ALP_AVAIL_REQ, &err);
1036 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
1037 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1038 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1039 }
1040 }
1041
1042 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
1043 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1044 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1045 #ifdef USE_CMD14
1046 err = bcmsdh_sleep(bus->sdh, TRUE);
1047 #else
1048 if ((SLPAUTO_ENAB(bus)) && (bus->idleclock == DHD_IDLE_STOP)) {
1049 if (sd1idle) {
1050 /* Change to SD1 mode */
1051 dhdsdio_set_sdmode(bus, 1);
1052 }
1053 }
1054
1055 err = dhdsdio_clk_kso_enab(bus, FALSE);
1056 if (OOB_WAKEUP_ENAB(bus))
1057 {
1058 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
1059 }
1060 #endif /* USE_CMD14 */
1061
1062 if ((SLPAUTO_ENAB(bus)) && (bus->idleclock != DHD_IDLE_ACTIVE)) {
1063 DHD_TRACE(("%s: Turnoff SD clk\n", __FUNCTION__));
1064 /* Now remove the SD clock */
1065 err = dhdsdio_sdclk(bus, FALSE);
1066 }
1067 } else {
1068 /* Exit Sleep */
1069 /* Make sure we have SD bus access */
1070 if (bus->clkstate == CLK_NONE) {
1071 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
1072 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1073 }
1074 #ifdef USE_CMD14
1075 err = bcmsdh_sleep(bus->sdh, FALSE);
1076 if (SLPAUTO_ENAB(bus) && (err != 0)) {
1077 OSL_DELAY(10000);
1078 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
1079
1080 /* Toggle sleep to resync with host and device */
1081 err = bcmsdh_sleep(bus->sdh, TRUE);
1082 OSL_DELAY(10000);
1083 err = bcmsdh_sleep(bus->sdh, FALSE);
1084
1085 if (err) {
1086 OSL_DELAY(10000);
1087 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
1088
1089 /* Toggle sleep to resync with host and device */
1090 err = bcmsdh_sleep(bus->sdh, TRUE);
1091 OSL_DELAY(10000);
1092 err = bcmsdh_sleep(bus->sdh, FALSE);
1093 if (err) {
1094 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1095 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1096 __FUNCTION__));
1097 err = 0;
1098 }
1099 }
1100 }
1101 #else
1102 if (OOB_WAKEUP_ENAB(bus))
1103 {
1104 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
1105 }
1106 do {
1107 err = dhdsdio_clk_kso_enab(bus, TRUE);
1108 if (err)
1109 OSL_SLEEP(10);
1110 } while ((err != 0) && (++retry < 3));
1111
1112 if (err != 0) {
1113 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1114 #ifndef BT_OVER_SDIO
1115 err = 0; /* continue anyway */
1116 #endif /* BT_OVER_SDIO */
1117 }
1118
1119 if ((SLPAUTO_ENAB(bus)) && (bus->idleclock == DHD_IDLE_STOP)) {
1120 dhdsdio_set_sdmode(bus, bus->sd_mode);
1121 }
1122 #endif /* !USE_CMD14 */
1123
1124 if (err == 0) {
1125 uint8 csr;
1126
1127 /* Wait for device ready during transition to wake-up */
1128 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1129 (((csr = dhdsdio_sleepcsr_get(bus)) &
1130 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1131 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1132
1133 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1134
1135 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1136 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1137 __FUNCTION__, csr));
1138 err = BCME_NODEVICE;
1139 }
1140
1141 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1142 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1143 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1144 (SBSDIO_HT_AVAIL)), (DHD_WAIT_HTAVAIL));
1145
1146 DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr));
1147 if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) {
1148 DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n",
1149 __FUNCTION__, csr));
1150 err = BCME_NODEVICE;
1151 }
1152 }
1153 }
1154
1155 /* Update if successful */
1156 if (err == 0)
1157 bus->kso = on ? FALSE : TRUE;
1158 else {
1159 DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
1160 __FUNCTION__, bus->kso, on, err));
1161 if (!on && retry > 2)
1162 bus->kso = FALSE;
1163 }
1164
1165 return err;
1166 }
1167
1168 /* Turn backplane clock on or off */
1169 static int
dhdsdio_htclk(dhd_bus_t * bus,bool on,bool pendok)1170 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1171 {
1172 #define HT_AVAIL_ERROR_MAX 10
1173 static int ht_avail_error = 0;
1174 int err;
1175 uint8 clkctl, clkreq, devctl;
1176 bcmsdh_info_t *sdh;
1177
1178 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1179
1180 clkctl = 0;
1181 sdh = bus->sdh;
1182
1183 if (!KSO_ENAB(bus))
1184 return BCME_OK;
1185
1186 if (SLPAUTO_ENAB(bus)) {
1187 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1188 return BCME_OK;
1189 }
1190
1191 if (on) {
1192 /* Request HT Avail */
1193 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1194
1195 #ifdef BCMSPI
1196 dhdsdio_wkwlan(bus, TRUE);
1197 #endif /* BCMSPI */
1198
1199 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1200 if (err) {
1201 ht_avail_error++;
1202 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1203 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1204 }
1205
1206 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1207 bus->dhd->hang_reason = HANG_REASON_HT_AVAIL_ERROR;
1208 dhd_os_send_hang_message(bus->dhd);
1209 }
1210 return BCME_ERROR;
1211 } else {
1212 ht_avail_error = 0;
1213 }
1214
1215 /* Check current status */
1216 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1217 if (err) {
1218 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1219 return BCME_ERROR;
1220 }
1221
1222 #if !defined(OOB_INTR_ONLY)
1223 /* Go to pending and await interrupt if appropriate */
1224 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1225 /* Allow only clock-available interrupt */
1226 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1227 if (err) {
1228 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1229 __FUNCTION__, err));
1230 return BCME_ERROR;
1231 }
1232
1233 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1234 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1235 DHD_INFO(("CLKCTL: set PENDING\n"));
1236 bus->clkstate = CLK_PENDING;
1237 return BCME_OK;
1238 } else
1239 #endif /* !defined (OOB_INTR_ONLY) */
1240 {
1241 if (bus->clkstate == CLK_PENDING) {
1242 /* Cancel CA-only interrupt filter */
1243 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1244 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1245 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1246 }
1247 }
1248 #ifndef BCMSDIOLITE
1249 /* Otherwise, wait here (polling) for HT Avail */
1250 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1251 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1252 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1253 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1254 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1255 }
1256 if (err) {
1257 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1258 return BCME_ERROR;
1259 }
1260 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1261 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1262 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1263 return BCME_ERROR;
1264 }
1265 #endif /* BCMSDIOLITE */
1266 /* Mark clock available */
1267 bus->clkstate = CLK_AVAIL;
1268 DHD_INFO(("CLKCTL: turned ON\n"));
1269
1270 #if defined(DHD_DEBUG)
1271 if (bus->alp_only == TRUE) {
1272 #if !defined(BCMLXSDMMC)
1273 if (!SBSDIO_ALPONLY(clkctl)) {
1274 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1275 }
1276 #endif /* !defined(BCMLXSDMMC) */
1277 } else {
1278 if (SBSDIO_ALPONLY(clkctl)) {
1279 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1280 }
1281 }
1282 #endif /* defined (DHD_DEBUG) */
1283
1284 bus->activity = TRUE;
1285 #ifdef DHD_USE_IDLECOUNT
1286 bus->idlecount = 0;
1287 #endif /* DHD_USE_IDLECOUNT */
1288 } else {
1289 clkreq = 0;
1290
1291 if (bus->clkstate == CLK_PENDING) {
1292 /* Cancel CA-only interrupt filter */
1293 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1294 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1295 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1296 }
1297
1298 bus->clkstate = CLK_SDONLY;
1299 if (!SR_ENAB(bus)) {
1300 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1301 DHD_INFO(("CLKCTL: turned OFF\n"));
1302 if (err) {
1303 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1304 __FUNCTION__, err));
1305 return BCME_ERROR;
1306 }
1307 }
1308 #ifdef BCMSPI
1309 dhdsdio_wkwlan(bus, FALSE);
1310 #endif /* BCMSPI */
1311 }
1312 return BCME_OK;
1313 }
1314
1315 /* Change SD1/SD4 bus mode */
1316 static int
dhdsdio_set_sdmode(dhd_bus_t * bus,int32 sd_mode)1317 dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode)
1318 {
1319 int err;
1320
1321 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1322 &sd_mode, sizeof(sd_mode), TRUE);
1323 if (err) {
1324 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1325 __FUNCTION__, err));
1326 return BCME_ERROR;
1327 }
1328 return BCME_OK;
1329 }
1330
1331 /* Change idle/active SD state */
1332 static int
dhdsdio_sdclk(dhd_bus_t * bus,bool on)1333 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1334 {
1335 #ifndef BCMSPI
1336 int err;
1337 int32 iovalue;
1338
1339 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1340
1341 if (on) {
1342 if (bus->idleclock == DHD_IDLE_STOP) {
1343 /* Turn on clock and restore mode */
1344 iovalue = 1;
1345 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1346 &iovalue, sizeof(iovalue), TRUE);
1347 if (err) {
1348 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1349 __FUNCTION__, err));
1350 return BCME_ERROR;
1351 }
1352
1353 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1354 /* Restore clock speed */
1355 iovalue = bus->sd_divisor;
1356 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1357 &iovalue, sizeof(iovalue), TRUE);
1358 if (err) {
1359 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1360 __FUNCTION__, err));
1361 return BCME_ERROR;
1362 }
1363 }
1364 bus->clkstate = CLK_SDONLY;
1365 } else {
1366 /* Stop or slow the SD clock itself */
1367 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1368 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1369 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1370 return BCME_ERROR;
1371 }
1372 if (bus->idleclock == DHD_IDLE_STOP) {
1373 iovalue = 0;
1374 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1375 &iovalue, sizeof(iovalue), TRUE);
1376 if (err) {
1377 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1378 __FUNCTION__, err));
1379 return BCME_ERROR;
1380 }
1381 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1382 /* Set divisor to idle value */
1383 iovalue = bus->idleclock;
1384 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1385 &iovalue, sizeof(iovalue), TRUE);
1386 if (err) {
1387 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1388 __FUNCTION__, err));
1389 return BCME_ERROR;
1390 }
1391 }
1392 bus->clkstate = CLK_NONE;
1393 }
1394 #endif /* BCMSPI */
1395
1396 return BCME_OK;
1397 }
1398
1399 /* Transition SD and backplane clock readiness */
1400 static int
dhdsdio_clkctl(dhd_bus_t * bus,uint target,bool pendok)1401 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1402 {
1403 int ret = BCME_OK;
1404 #ifdef DHD_DEBUG
1405 uint oldstate = bus->clkstate;
1406 #endif /* DHD_DEBUG */
1407
1408 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1409
1410 /* Early exit if we're already there */
1411 if (bus->clkstate == target) {
1412 if (target == CLK_AVAIL) {
1413 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1414 bus->activity = TRUE;
1415 #ifdef DHD_USE_IDLECOUNT
1416 bus->idlecount = 0;
1417 #endif /* DHD_USE_IDLECOUNT */
1418 }
1419 return ret;
1420 }
1421
1422 switch (target) {
1423 case CLK_AVAIL:
1424 /* Make sure SD clock is available */
1425 if (bus->clkstate == CLK_NONE)
1426 dhdsdio_sdclk(bus, TRUE);
1427 /* Now request HT Avail on the backplane */
1428 ret = dhdsdio_htclk(bus, TRUE, pendok);
1429 if (ret == BCME_OK) {
1430 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1431 bus->activity = TRUE;
1432 #ifdef DHD_USE_IDLECOUNT
1433 bus->idlecount = 0;
1434 #endif /* DHD_USE_IDLECOUNT */
1435 }
1436 break;
1437
1438 case CLK_SDONLY:
1439
1440 #ifdef BT_OVER_SDIO
1441 /*
1442 * If the request is to switch off Back plane clock,
1443 * confirm that BT is inactive before doing so.
1444 * If this call had come from Non Watchdog context any way
1445 * the Watchdog would switch off the clock again when
1446 * nothing is to be done & Bt has finished using the bus.
1447 */
1448 if (bus->bt_use_count != 0) {
1449 DHD_INFO(("%s(): Req CLK_SDONLY, BT is active %d not switching off \r\n",
1450 __FUNCTION__, bus->bt_use_count));
1451 ret = BCME_OK;
1452 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1453 break;
1454 }
1455
1456 DHD_INFO(("%s(): Request CLK_NONE BT is NOT active switching off \r\n",
1457 __FUNCTION__));
1458 #endif /* BT_OVER_SDIO */
1459
1460 /* Remove HT request, or bring up SD clock */
1461 if (bus->clkstate == CLK_NONE)
1462 ret = dhdsdio_sdclk(bus, TRUE);
1463 else if (bus->clkstate == CLK_AVAIL)
1464 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1465 else
1466 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1467 bus->clkstate, target));
1468 if (ret == BCME_OK) {
1469 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1470 }
1471 break;
1472
1473 case CLK_NONE:
1474
1475 #ifdef BT_OVER_SDIO
1476 /*
1477 * If the request is to switch off Back plane clock,
1478 * confirm that BT is inactive before doing so.
1479 * If this call had come from Non Watchdog context any way
1480 * the Watchdog would switch off the clock again when
1481 * nothing is to be done & Bt has finished using the bus.
1482 */
1483 if (bus->bt_use_count != 0) {
1484 DHD_INFO(("%s(): Request CLK_NONE BT is active %d not switching off \r\n",
1485 __FUNCTION__, bus->bt_use_count));
1486 ret = BCME_OK;
1487 break;
1488 }
1489
1490 DHD_INFO(("%s(): Request CLK_NONE BT is NOT active switching off \r\n",
1491 __FUNCTION__));
1492 #endif /* BT_OVER_SDIO */
1493
1494 /* Make sure to remove HT request */
1495 if (bus->clkstate == CLK_AVAIL)
1496 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1497 /* Now remove the SD clock */
1498 ret = dhdsdio_sdclk(bus, FALSE);
1499 #ifdef DHD_DEBUG
1500 if (bus->dhd->dhd_console_ms == 0)
1501 #endif /* DHD_DEBUG */
1502 if (bus->poll == 0)
1503 dhd_os_wd_timer(bus->dhd, 0);
1504 break;
1505 }
1506 #ifdef DHD_DEBUG
1507 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1508 #endif /* DHD_DEBUG */
1509
1510 return ret;
1511 }
1512
1513 static int
dhdsdio_bussleep(dhd_bus_t * bus,bool sleep)1514 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1515 {
1516 int err = 0;
1517 bcmsdh_info_t *sdh = bus->sdh;
1518 sdpcmd_regs_t *regs = bus->regs;
1519 uint retries = 0;
1520 #if defined(BCMSDIOH_STD)
1521 uint32 sd3_tuning_disable = FALSE;
1522 #endif /* BCMSDIOH_STD */
1523
1524 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1525 (sleep ? "SLEEP" : "WAKE"),
1526 (bus->sleeping ? "SLEEP" : "WAKE")));
1527
1528 if (bus->dhd->hang_was_sent)
1529 return BCME_ERROR;
1530
1531 /* Done if we're already in the requested state */
1532 if (sleep == bus->sleeping)
1533 return BCME_OK;
1534
1535 /* Going to sleep: set the alarm and turn off the lights... */
1536 if (sleep) {
1537 /* Don't sleep if something is pending */
1538 #ifdef DHD_USE_IDLECOUNT
1539 if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq) ||
1540 bus->readframes || bus->ctrl_frame_stat)
1541 #else
1542 if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq))
1543 #endif /* DHD_USE_IDLECOUNT */
1544 return BCME_BUSY;
1545
1546 #ifdef BT_OVER_SDIO
1547 /*
1548 * The following is the assumption based on which the hook is placed.
1549 * From WLAN driver, either from the active contexts OR from the Watchdog contexts
1550 * we will be attempting to Go to Sleep. AT that moment if we see that BT is still
1551 * actively using the bus, we will return BCME_BUSY from here, but the bus->sleeping
1552 * state would not have changed. So the caller can then schedule the Watchdog again
1553 * which will come and attempt to sleep at a later point.
1554 *
1555 * In case if BT is the only one and is the last user, we don't switch off the clock
1556 * immediately, we allow the WLAN to decide when to sleep i.e from the watchdog.
1557 * Now if the watchdog becomes active and attempts to switch off the clock and if
1558 * another WLAN context is active they are any way serialized with sdlock.
1559 */
1560 if (bus->bt_use_count != 0) {
1561 DHD_INFO(("%s(): Cannot sleep BT is active \r\n", __FUNCTION__));
1562 return BCME_BUSY;
1563 }
1564 #endif /* !BT_OVER_SDIO */
1565
1566 if (!SLPAUTO_ENAB(bus)) {
1567 /* Disable SDIO interrupts (no longer interested) */
1568 bcmsdh_intr_disable(bus->sdh);
1569
1570 /* Make sure the controller has the bus up */
1571 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1572
1573 /* Tell device to start using OOB wakeup */
1574 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1575 if (retries > retry_limit)
1576 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1577
1578 /* Turn off our contribution to the HT clock request */
1579 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1580
1581 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1582 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1583
1584 /* Isolate the bus */
1585 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1586 SBSDIO_DEVCTL_PADS_ISO, NULL);
1587 } else {
1588 #ifdef FORCE_SWOOB_ENABLE
1589 /* Tell device to start using OOB wakeup */
1590 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1591 if (retries > retry_limit)
1592 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1593 #endif
1594 /* Leave interrupts enabled since device can exit sleep and
1595 * interrupt host
1596 */
1597 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1598 }
1599
1600 /* Change state */
1601 bus->sleeping = TRUE;
1602 #if defined(BCMSDIOH_STD)
1603 sd3_tuning_disable = TRUE;
1604 err = bcmsdh_iovar_op(bus->sdh, "sd3_tuning_disable", NULL, 0,
1605 &sd3_tuning_disable, sizeof(sd3_tuning_disable), TRUE);
1606 #endif /* BCMSDIOH_STD */
1607 #if defined(SUPPORT_P2P_GO_PS)
1608 wake_up(&bus->bus_sleep);
1609 #endif /* LINUX && SUPPORT_P2P_GO_PS */
1610 } else {
1611 /* Waking up: bus power up is ok, set local state */
1612
1613 if (!SLPAUTO_ENAB(bus)) {
1614 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1615
1616 /* Force pad isolation off if possible (in case power never toggled) */
1617 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1618
1619 /* Make sure the controller has the bus up */
1620 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1621
1622 /* Send misc interrupt to indicate OOB not needed */
1623 W_SDREG(0, ®s->tosbmailboxdata, retries);
1624 if (retries <= retry_limit)
1625 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1626
1627 if (retries > retry_limit)
1628 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1629
1630 /* Make sure we have SD bus access */
1631 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1632
1633 /* Enable interrupts again */
1634 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1635 bus->intdis = FALSE;
1636 bcmsdh_intr_enable(bus->sdh);
1637 }
1638 } else {
1639 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1640 #ifdef FORCE_SWOOB_ENABLE
1641 /* Send misc interrupt to indicate OOB not needed */
1642 W_SDREG(0, ®s->tosbmailboxdata, retries);
1643 if (retries <= retry_limit)
1644 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1645 #endif
1646 #ifdef BT_OVER_SDIO
1647 if (err < 0) {
1648 struct net_device *net = NULL;
1649 dhd_pub_t *dhd = bus->dhd;
1650 net = dhd_idx2net(dhd, 0);
1651 if (net != NULL) {
1652 DHD_ERROR(("<< WIFI HANG by KSO Enabled failure\n"));
1653 dhd_os_sdunlock(dhd);
1654 net_os_send_hang_message(net);
1655 dhd_os_sdlock(dhd);
1656 } else {
1657 DHD_ERROR(("<< WIFI HANG Fail because net is NULL\n"));
1658 }
1659 }
1660 #endif /* BT_OVER_SDIO */
1661 }
1662
1663 if (err == 0) {
1664 /* Change state */
1665 bus->sleeping = FALSE;
1666 #if defined(BCMSDIOH_STD)
1667 sd3_tuning_disable = FALSE;
1668 err = bcmsdh_iovar_op(bus->sdh, "sd3_tuning_disable", NULL, 0,
1669 &sd3_tuning_disable, sizeof(sd3_tuning_disable), TRUE);
1670 #endif /* BCMSDIOH_STD */
1671 }
1672 }
1673
1674 return err;
1675 }
1676
1677 #ifdef BT_OVER_SDIO
1678 /*
1679 * Call this function to Get the Clock running.
1680 * Assumes that the caller holds the sdlock.
1681 * bus - Pointer to the dhd_bus handle
1682 * can_wait - TRUE if the caller can wait until the clock becomes ready
1683 * FALSE if the caller cannot wait
1684 */
__dhdsdio_clk_enable(struct dhd_bus * bus,bus_owner_t owner,int can_wait)1685 int __dhdsdio_clk_enable(struct dhd_bus *bus, bus_owner_t owner, int can_wait)
1686 {
1687 int ret = BCME_ERROR;
1688
1689 BCM_REFERENCE(owner);
1690
1691 bus->bt_use_count++;
1692
1693 /*
1694 * We can call BUS_WAKE, clkctl multiple times, both of the items
1695 * have states and if its already ON, no new configuration is done
1696 */
1697
1698 /* Wake up the Dongle FW from SR */
1699 BUS_WAKE(bus);
1700
1701 /*
1702 * Make sure back plane ht clk is on
1703 * CLK_AVAIL - Turn On both SD & HT clock
1704 */
1705 ret = dhdsdio_clkctl(bus, CLK_AVAIL, can_wait);
1706
1707 DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__,
1708 bus->bt_use_count));
1709 return ret;
1710 }
1711
1712 /*
1713 * Call this function to relinquish the Clock.
1714 * Assumes that the caller holds the sdlock.
1715 * bus - Pointer to the dhd_bus handle
1716 * can_wait - TRUE if the caller can wait until the clock becomes ready
1717 * FALSE if the caller cannot wait
1718 */
__dhdsdio_clk_disable(struct dhd_bus * bus,bus_owner_t owner,int can_wait)1719 int __dhdsdio_clk_disable(struct dhd_bus *bus, bus_owner_t owner, int can_wait)
1720 {
1721 int ret = BCME_ERROR;
1722
1723 BCM_REFERENCE(owner);
1724 BCM_REFERENCE(can_wait);
1725
1726 if (bus->bt_use_count == 0) {
1727 DHD_ERROR(("%s(): Clocks are already turned off \r\n",
1728 __FUNCTION__));
1729 return ret;
1730 }
1731
1732 bus->bt_use_count--;
1733
1734 /*
1735 * When the SDIO Bus is shared between BT & WLAN, we turn Off the clock
1736 * once the last user has relinqushed the same. But there are two schemes
1737 * in that too. We consider WLAN as the bus master (even if its not
1738 * active). Even when the WLAN is OFF the DHD Watchdog is active.
1739 * So this Bus Watchdog is the context whill put the Bus to sleep.
1740 * Refer dhd_bus_watchdog function
1741 */
1742
1743 ret = BCME_OK;
1744 DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__,
1745 bus->bt_use_count));
1746 return ret;
1747 }
1748
dhdsdio_reset_bt_use_count(struct dhd_bus * bus)1749 void dhdsdio_reset_bt_use_count(struct dhd_bus *bus)
1750 {
1751 /* reset bt use count */
1752 bus->bt_use_count = 0;
1753 }
1754 #endif /* BT_OVER_SDIO */
1755
1756 #ifdef USE_DYNAMIC_F2_BLKSIZE
dhdsdio_func_blocksize(dhd_pub_t * dhd,int function_num,int block_size)1757 int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
1758 {
1759 int func_blk_size = function_num;
1760 int bcmerr = 0;
1761 int result;
1762
1763 bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size,
1764 sizeof(int), &result, sizeof(int), IOV_GET);
1765
1766 if (bcmerr != BCME_OK) {
1767 DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num));
1768 return BCME_ERROR;
1769 }
1770
1771 if (result != block_size) {
1772 DHD_ERROR(("%s: F%d Block size set from %d to %d\n",
1773 __FUNCTION__, function_num, result, block_size));
1774 func_blk_size = function_num << 16 | block_size;
1775 bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", NULL,
1776 0, &func_blk_size, sizeof(int32), IOV_SET);
1777 if (bcmerr != BCME_OK) {
1778 DHD_ERROR(("%s: Set F%d Block size error\n", __FUNCTION__, function_num));
1779 return BCME_ERROR;
1780 }
1781 }
1782
1783 return BCME_OK;
1784 }
1785 #endif /* USE_DYNAMIC_F2_BLKSIZE */
1786
1787 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) || defined(FORCE_WOWLAN)
1788 void
dhd_enable_oob_intr(struct dhd_bus * bus,bool enable)1789 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1790 {
1791 #if defined(BCMSPI_ANDROID)
1792 bcmsdh_intr_enable(bus->sdh);
1793 #elif defined(HW_OOB) || defined(FORCE_WOWLAN)
1794 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1795 #else
1796 sdpcmd_regs_t *regs = bus->regs;
1797 uint retries = 0;
1798
1799 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1800 if (enable == TRUE) {
1801
1802 /* Tell device to start using OOB wakeup */
1803 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1804 if (retries > retry_limit)
1805 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1806
1807 } else {
1808 /* Send misc interrupt to indicate OOB not needed */
1809 W_SDREG(0, ®s->tosbmailboxdata, retries);
1810 if (retries <= retry_limit)
1811 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1812 }
1813
1814 /* Turn off our contribution to the HT clock request */
1815 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1816 #endif /* !defined(HW_OOB) */
1817 }
1818 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
1819
1820 int
dhd_bus_txdata(struct dhd_bus * bus,void * pkt)1821 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1822 {
1823 int ret = BCME_ERROR;
1824 osl_t *osh;
1825 uint datalen, prec;
1826
1827 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1828
1829 osh = bus->dhd->osh;
1830 datalen = PKTLEN(osh, pkt);
1831
1832 #ifdef SDTEST
1833 /* Push the test header if doing loopback */
1834 if (bus->ext_loop) {
1835 uint8* data;
1836 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1837 data = PKTDATA(osh, pkt);
1838 *data++ = SDPCM_TEST_ECHOREQ;
1839 *data++ = (uint8)bus->loopid++;
1840 *data++ = (datalen >> 0);
1841 *data++ = (datalen >> 8);
1842 datalen += SDPCM_TEST_HDRLEN;
1843 }
1844 #else /* SDTEST */
1845 BCM_REFERENCE(datalen);
1846 #endif /* SDTEST */
1847
1848 #ifdef DHD_ULP
1849 dhd_ulp_set_path(bus->dhd, DHD_ULP_TX_DATA);
1850 #endif /* DHD_ULP */
1851
1852 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1853
1854 /* move from dhdsdio_sendfromq(), try to orphan skb early */
1855 if (bus->dhd->conf->orphan_move == 1)
1856 PKTORPHAN(pkt, bus->dhd->conf->tsq);
1857
1858 /* Check for existing queue, current flow-control, pending event, or pending clock */
1859 if (dhd_deferred_tx || bus->fcstate || pktq_n_pkts_tot(&bus->txq) || bus->dpc_sched ||
1860 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1861 (bus->clkstate != CLK_AVAIL)) {
1862 bool deq_ret;
1863 int pkq_len = 0;
1864
1865 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
1866 pktq_n_pkts_tot(&bus->txq)));
1867 bus->fcqueued++;
1868
1869 /* Priority based enq */
1870 dhd_os_sdlock_txq(bus->dhd);
1871 deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec);
1872 dhd_os_sdunlock_txq(bus->dhd);
1873
1874 if (!deq_ret) {
1875 #ifdef PROP_TXSTATUS
1876 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0)
1877 #endif /* PROP_TXSTATUS */
1878 {
1879 #ifdef DHDTCPACK_SUPPRESS
1880 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1881 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
1882 __FUNCTION__, __LINE__));
1883 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1884 }
1885 #endif /* DHDTCPACK_SUPPRESS */
1886 dhd_txcomplete(bus->dhd, pkt, FALSE);
1887 PKTFREE(osh, pkt, TRUE);
1888 }
1889 ret = BCME_NORESOURCE;
1890 } else
1891 ret = BCME_OK;
1892
1893 if (dhd_doflow) {
1894 dhd_os_sdlock_txq(bus->dhd);
1895 pkq_len = pktq_n_pkts_tot(&bus->txq);
1896 dhd_os_sdunlock_txq(bus->dhd);
1897 }
1898 if (dhd_doflow && pkq_len >= FCHI) {
1899 bool wlfc_enabled = FALSE;
1900 #ifdef PROP_TXSTATUS
1901 wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) !=
1902 WLFC_UNSUPPORTED);
1903 #endif // endif
1904 if (!wlfc_enabled && dhd_doflow) {
1905 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1906 }
1907 }
1908
1909 #ifdef DHD_DEBUG
1910 dhd_os_sdlock_txq(bus->dhd);
1911 if (pktqprec_n_pkts(&bus->txq, prec) > qcount[prec])
1912 qcount[prec] = pktqprec_n_pkts(&bus->txq, prec);
1913 dhd_os_sdunlock_txq(bus->dhd);
1914 #endif // endif
1915
1916 /* Schedule DPC if needed to send queued packet(s) */
1917 if (dhd_deferred_tx && !bus->dpc_sched) {
1918 if (bus->dhd->conf->deferred_tx_len) {
1919 if(dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
1920 bus->dpc_sched = TRUE;
1921 dhd_sched_dpc(bus->dhd);
1922 }
1923 if(pktq_n_pkts_tot(&bus->txq) >= bus->dhd->conf->deferred_tx_len &&
1924 dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
1925 bus->dpc_sched = TRUE;
1926 dhd_sched_dpc(bus->dhd);
1927 }
1928 } else {
1929 bus->dpc_sched = TRUE;
1930 dhd_sched_dpc(bus->dhd);
1931 }
1932 }
1933 } else {
1934 int chan = SDPCM_DATA_CHANNEL;
1935
1936 #ifdef SDTEST
1937 chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL);
1938 #endif // endif
1939 /* Lock: we're about to use shared data/code (and SDIO) */
1940 dhd_os_sdlock(bus->dhd);
1941
1942 /* Otherwise, send it now */
1943 BUS_WAKE(bus);
1944 /* Make sure back plane ht clk is on, no pending allowed */
1945 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1946
1947 ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
1948
1949 if (ret != BCME_OK)
1950 bus->dhd->tx_errors++;
1951 else
1952 bus->dhd->dstats.tx_bytes += datalen;
1953
1954 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
1955 NO_OTHER_ACTIVE_BUS_USER(bus)) {
1956 bus->activity = FALSE;
1957 dhdsdio_bussleep(bus, TRUE);
1958 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
1959 }
1960
1961 dhd_os_sdunlock(bus->dhd);
1962 }
1963
1964 return ret;
1965 }
1966
1967 /* align packet data pointer and packet length to n-byte boundary, process packet headers,
1968 * a new packet may be allocated if there is not enough head and/or tail from for padding.
1969 * the caller is responsible for updating the glom size in the head packet (when glom is
1970 * used)
1971 *
1972 * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter
1973 * is taken in tx glom mode only
1974 *
1975 * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment
1976 * padding, NULL if not needed, the caller is responsible for freeing the new packet
1977 *
1978 * return: positive value - length of the packet, including head and tail padding
1979 * negative value - errors
1980 */
dhdsdio_txpkt_preprocess(dhd_bus_t * bus,void * pkt,int chan,int txseq,int prev_chain_total_len,bool last_chained_pkt,int * pad_pkt_len,void ** new_pkt,int first_frame)1981 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
1982 int prev_chain_total_len, bool last_chained_pkt,
1983 int *pad_pkt_len, void **new_pkt
1984 #if defined(BCMSDIOH_TXGLOM_EXT)
1985 , int first_frame
1986 #endif
1987 )
1988 {
1989 osl_t *osh;
1990 uint8 *frame;
1991 int pkt_len;
1992 int modulo;
1993 int head_padding;
1994 int tail_padding = 0;
1995 uint32 swheader;
1996 uint32 swhdr_offset;
1997 bool alloc_new_pkt = FALSE;
1998 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
1999 #ifdef PKT_STATICS
2000 uint16 len;
2001 #endif
2002
2003 *new_pkt = NULL;
2004 osh = bus->dhd->osh;
2005
2006 #ifdef DHDTCPACK_SUPPRESS
2007 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
2008 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
2009 __FUNCTION__, __LINE__));
2010 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
2011 }
2012 #endif /* DHDTCPACK_SUPPRESS */
2013
2014 /* Add space for the SDPCM hardware/software headers */
2015 PKTPUSH(osh, pkt, sdpcm_hdrlen);
2016 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
2017
2018 frame = (uint8*)PKTDATA(osh, pkt);
2019 pkt_len = (uint16)PKTLEN(osh, pkt);
2020
2021 #ifdef PKT_STATICS
2022 len = (uint16)PKTLEN(osh, pkt);
2023 switch(chan) {
2024 case SDPCM_CONTROL_CHANNEL:
2025 bus->tx_statics.ctrl_count++;
2026 bus->tx_statics.ctrl_size += len;
2027 break;
2028 case SDPCM_DATA_CHANNEL:
2029 bus->tx_statics.data_count++;
2030 bus->tx_statics.data_size += len;
2031 break;
2032 case SDPCM_GLOM_CHANNEL:
2033 bus->tx_statics.glom_count++;
2034 bus->tx_statics.glom_size += len;
2035 break;
2036 case SDPCM_EVENT_CHANNEL:
2037 bus->tx_statics.event_count++;
2038 bus->tx_statics.event_size += len;
2039 break;
2040 case SDPCM_TEST_CHANNEL:
2041 bus->tx_statics.test_count++;
2042 bus->tx_statics.test_size += len;
2043 break;
2044
2045 default:
2046 break;
2047 }
2048 #endif /* PKT_STATICS */
2049 #ifdef DHD_DEBUG
2050 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
2051 tx_packets[PKTPRIO(pkt)]++;
2052 #endif /* DHD_DEBUG */
2053
2054 /* align the data pointer, allocate a new packet if there is not enough space (new
2055 * packet data pointer will be aligned thus no padding will be needed)
2056 */
2057 head_padding = (uintptr)frame % DHD_SDALIGN;
2058 if (PKTHEADROOM(osh, pkt) < head_padding) {
2059 head_padding = 0;
2060 alloc_new_pkt = TRUE;
2061 } else {
2062 uint cur_chain_total_len;
2063 int chain_tail_padding = 0;
2064
2065 /* All packets need to be aligned by DHD_SDALIGN */
2066 modulo = (pkt_len + head_padding) % DHD_SDALIGN;
2067 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
2068
2069 /* Total pkt chain length needs to be aligned by block size,
2070 * unless it is a single pkt chain with total length less than one block size,
2071 * which we prefer sending by byte mode.
2072 *
2073 * Do the chain alignment here if
2074 * 1. This is the last pkt of the chain of multiple pkts or a single pkt.
2075 * 2-1. This chain is of multiple pkts, or
2076 * 2-2. This is a single pkt whose size is longer than one block size.
2077 */
2078 cur_chain_total_len = prev_chain_total_len +
2079 (head_padding + pkt_len + tail_padding);
2080 if (last_chained_pkt && bus->blocksize != 0 &&
2081 (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
2082 modulo = cur_chain_total_len % bus->blocksize;
2083 chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
2084 }
2085
2086 #ifdef DHDENABLE_TAILPAD
2087 if (PKTTAILROOM(osh, pkt) < tail_padding) {
2088 /* We don't have tail room to align by DHD_SDALIGN */
2089 alloc_new_pkt = TRUE;
2090 bus->tx_tailpad_pktget++;
2091 } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) {
2092 /* We have tail room for tail_padding of this pkt itself, but not for
2093 * total pkt chain alignment by block size.
2094 * Use the padding packet to avoid memory copy if applicable,
2095 * otherwise, just allocate a new pkt.
2096 */
2097 if (bus->pad_pkt) {
2098 *pad_pkt_len = chain_tail_padding;
2099 bus->tx_tailpad_chain++;
2100 } else {
2101 alloc_new_pkt = TRUE;
2102 bus->tx_tailpad_pktget++;
2103 }
2104 } else
2105 /* This last pkt's tailroom is sufficient to hold both tail_padding
2106 * of the pkt itself and chain_tail_padding of total pkt chain
2107 */
2108 #endif /* DHDENABLE_TAILPAD */
2109 tail_padding += chain_tail_padding;
2110 }
2111
2112 DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
2113 __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len));
2114
2115 if (alloc_new_pkt) {
2116 void *tmp_pkt;
2117 int newpkt_size;
2118 int cur_total_len;
2119
2120 ASSERT(*pad_pkt_len == 0);
2121
2122 DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__));
2123
2124 /* head pointer is aligned now, no padding needed */
2125 head_padding = 0;
2126
2127 /* update the tail padding as it depends on the head padding, since a new packet is
2128 * allocated, the head padding is non longer needed and packet length is chagned
2129 */
2130
2131 cur_total_len = prev_chain_total_len + pkt_len;
2132 if (last_chained_pkt && bus->blocksize != 0 &&
2133 (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
2134 modulo = cur_total_len % bus->blocksize;
2135 tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
2136 } else {
2137 modulo = pkt_len % DHD_SDALIGN;
2138 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
2139 }
2140
2141 newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN;
2142 bus->dhd->tx_realloc++;
2143 tmp_pkt = PKTGET(osh, newpkt_size, TRUE);
2144 if (tmp_pkt == NULL) {
2145 DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size));
2146 return BCME_NOMEM;
2147 }
2148 PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
2149 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
2150 *new_pkt = tmp_pkt;
2151 pkt = tmp_pkt;
2152 }
2153
2154 if (head_padding)
2155 PKTPUSH(osh, pkt, head_padding);
2156
2157 frame = (uint8*)PKTDATA(osh, pkt);
2158 bzero(frame, head_padding + sdpcm_hdrlen);
2159 pkt_len = (uint16)PKTLEN(osh, pkt);
2160
2161 /* the header has the followming format
2162 * 4-byte HW frame tag: length, ~length (for glom this is the total length)
2163 *
2164 * 8-byte HW extesion flags (glom mode only) as the following:
2165 * 2-byte packet length, excluding HW tag and padding
2166 * 2-byte frame channel and frame flags (e.g. next frame following)
2167 * 2-byte header length
2168 * 2-byte tail padding size
2169 *
2170 * 8-byte SW frame tags as the following
2171 * 4-byte flags: host tx seq, channel, data offset
2172 * 4-byte flags: TBD
2173 */
2174
2175 swhdr_offset = SDPCM_FRAMETAG_LEN;
2176
2177 /* hardware frame tag:
2178 *
2179 * in tx-glom mode, dongle only checks the hardware frame tag in the first
2180 * packet and sees it as the total lenght of the glom (including tail padding),
2181 * for each packet in the glom, the packet length needs to be updated, (see
2182 * below PKTSETLEN)
2183 *
2184 * in non tx-glom mode, PKTLEN still need to include tail padding as to be
2185 * referred to in sdioh_request_buffer(). The tail length will be excluded in
2186 * dhdsdio_txpkt_postprocess().
2187 */
2188 #if defined(BCMSDIOH_TXGLOM_EXT)
2189 if (bus->dhd->conf->txglom_bucket_size)
2190 tail_padding = 0;
2191 #endif
2192 *(uint16*)frame = (uint16)htol16(pkt_len);
2193 *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
2194 pkt_len += tail_padding;
2195
2196 /* hardware extesion flags */
2197 if (bus->txglom_enable) {
2198 uint32 hwheader1;
2199 uint32 hwheader2;
2200 #ifdef BCMSDIOH_TXGLOM_EXT
2201 uint32 act_len = pkt_len - tail_padding;
2202 uint32 real_pad = 0;
2203 if(bus->dhd->conf->txglom_ext && !last_chained_pkt) {
2204 tail_padding = 0;
2205 if(first_frame == 0) {
2206 // first pkt, add pad to bucket size - recv offset
2207 pkt_len = bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET;
2208 } else {
2209 // add pad to bucket size
2210 pkt_len = bus->dhd->conf->txglom_bucket_size;
2211 }
2212 swhdr_offset += SDPCM_HWEXT_LEN;
2213 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (last_chained_pkt << 24);
2214 hwheader2 = (pkt_len - act_len) << 16;
2215 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2216 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2217 real_pad = pkt_len - act_len;
2218
2219 if (PKTTAILROOM(osh, pkt) < real_pad) {
2220 DHD_INFO(("%s : insufficient tailroom %d for %d real_pad\n",
2221 __func__, (int)PKTTAILROOM(osh, pkt), real_pad));
2222 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
2223 DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
2224 } else
2225 frame = (uint8 *)PKTDATA(osh, pkt);
2226 }
2227 } else
2228 #endif
2229 {
2230 swhdr_offset += SDPCM_HWEXT_LEN;
2231 hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
2232 (last_chained_pkt << 24);
2233 hwheader2 = (tail_padding) << 16;
2234 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2235 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2236 }
2237 }
2238 PKTSETLEN((osh), (pkt), (pkt_len));
2239
2240 /* software frame tags */
2241 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2242 | (txseq % SDPCM_SEQUENCE_WRAP) |
2243 (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2244 htol32_ua_store(swheader, frame + swhdr_offset);
2245 htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader));
2246
2247 return pkt_len;
2248 }
2249
dhdsdio_txpkt_postprocess(dhd_bus_t * bus,void * pkt)2250 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
2251 {
2252 osl_t *osh;
2253 uint8 *frame;
2254 int data_offset;
2255 int tail_padding;
2256 int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0);
2257
2258 (void)osh;
2259 osh = bus->dhd->osh;
2260
2261 /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
2262 frame = (uint8*)PKTDATA(osh, pkt);
2263
2264 DHD_INFO(("%s PKTLEN before postprocess %d",
2265 __FUNCTION__, PKTLEN(osh, pkt)));
2266
2267 /* PKTLEN still includes tail_padding, so exclude it.
2268 * We shall have head_padding + original pkt_len for PKTLEN afterwards.
2269 */
2270 if (bus->txglom_enable) {
2271 /* txglom pkts have tail_padding length in HW ext header */
2272 tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
2273 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
2274 DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
2275 tail_padding, PKTLEN(osh, pkt)));
2276 } else {
2277 /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
2278 * We cannot refer to this field for txglom pkts as the first pkt of the chain will
2279 * have the field for the total length of the chain.
2280 */
2281 PKTSETLEN(osh, pkt, *(uint16*)frame);
2282 DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
2283 *(uint16*)frame, PKTLEN(osh, pkt)));
2284 }
2285
2286 data_offset = ltoh32_ua(frame + swhdr_offset);
2287 data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2288 /* Get rid of sdpcm header + head_padding */
2289 PKTPULL(osh, pkt, data_offset);
2290
2291 DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
2292 __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
2293
2294 return BCME_OK;
2295 }
2296
dhdsdio_txpkt(dhd_bus_t * bus,uint chan,void ** pkts,int num_pkt,bool free_pkt)2297 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
2298 {
2299 int i;
2300 int ret = 0;
2301 osl_t *osh;
2302 bcmsdh_info_t *sdh;
2303 void *pkt = NULL;
2304 void *pkt_chain;
2305 int total_len = 0;
2306 void *head_pkt = NULL;
2307 void *prev_pkt = NULL;
2308 int pad_pkt_len = 0;
2309 int new_pkt_num = 0;
2310 void *new_pkts[MAX_TX_PKTCHAIN_CNT];
2311 bool wlfc_enabled = FALSE;
2312
2313 if (bus->dhd->dongle_reset)
2314 return BCME_NOTREADY;
2315
2316 if (num_pkt <= 0)
2317 return BCME_BADARG;
2318
2319 sdh = bus->sdh;
2320 osh = bus->dhd->osh;
2321 /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */
2322 new_pkts[0] = NULL;
2323
2324 for (i = 0; i < num_pkt; i++) {
2325 int pkt_len;
2326 bool last_pkt;
2327 void *new_pkt = NULL;
2328
2329 pkt = pkts[i];
2330 ASSERT(pkt);
2331 last_pkt = (i == num_pkt - 1);
2332 pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i,
2333 total_len, last_pkt, &pad_pkt_len, &new_pkt
2334 #if defined(BCMSDIOH_TXGLOM_EXT)
2335 , i
2336 #endif
2337 );
2338 if (pkt_len <= 0)
2339 goto done;
2340 if (new_pkt) {
2341 pkt = new_pkt;
2342 new_pkts[new_pkt_num++] = new_pkt;
2343 }
2344 total_len += pkt_len;
2345
2346 PKTSETNEXT(osh, pkt, NULL);
2347 /* insert the packet into the list */
2348 head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt);
2349 prev_pkt = pkt;
2350
2351 }
2352
2353 /* Update the HW frame tag (total length) in the first pkt of the glom */
2354 if (bus->txglom_enable) {
2355 uint8 *frame;
2356
2357 total_len += pad_pkt_len;
2358 frame = (uint8*)PKTDATA(osh, head_pkt);
2359 *(uint16*)frame = (uint16)htol16(total_len);
2360 *(((uint16*)frame) + 1) = (uint16)htol16(~total_len);
2361
2362 }
2363
2364 #ifdef DHDENABLE_TAILPAD
2365 /* if a padding packet if needed, insert it to the end of the link list */
2366 if (pad_pkt_len) {
2367 PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len);
2368 PKTSETNEXT(osh, pkt, bus->pad_pkt);
2369 }
2370 #endif /* DHDENABLE_TAILPAD */
2371
2372 /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
2373 * parameter is not NULL, for non packet chian we pass NULL pkt pointer
2374 * so it will take the aligned length and buffer pointer.
2375 */
2376 pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
2377 #ifdef HOST_TPUT_TEST
2378 if ((bus->dhd->conf->data_drop_mode == TXPKT_DROP) && (total_len > 500)) {
2379 ret = BCME_OK;
2380 } else {
2381 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2382 PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
2383 if (ret == BCME_OK)
2384 bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
2385 }
2386 #else
2387 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2388 PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
2389 if (ret == BCME_OK)
2390 bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
2391 #endif
2392
2393 /* if a padding packet was needed, remove it from the link list as it not a data pkt */
2394 if (pad_pkt_len && pkt)
2395 PKTSETNEXT(osh, pkt, NULL);
2396
2397 done:
2398 pkt = head_pkt;
2399 while (pkt) {
2400 void *pkt_next = PKTNEXT(osh, pkt);
2401 PKTSETNEXT(osh, pkt, NULL);
2402 dhdsdio_txpkt_postprocess(bus, pkt);
2403 pkt = pkt_next;
2404 }
2405
2406 /* new packets might be allocated due to insufficient room for padding, but we
2407 * still have to indicate the original packets to upper layer
2408 */
2409 for (i = 0; i < num_pkt; i++) {
2410 pkt = pkts[i];
2411 wlfc_enabled = FALSE;
2412 #ifdef PROP_TXSTATUS
2413 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) {
2414 wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) !=
2415 WLFC_UNSUPPORTED);
2416 }
2417 #endif /* PROP_TXSTATUS */
2418 if (!wlfc_enabled) {
2419 PKTSETNEXT(osh, pkt, NULL);
2420 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2421 if (free_pkt)
2422 PKTFREE(osh, pkt, TRUE);
2423 }
2424 }
2425
2426 for (i = 0; i < new_pkt_num; i++)
2427 PKTFREE(osh, new_pkts[i], TRUE);
2428
2429 return ret;
2430 }
2431
2432 static uint
dhdsdio_sendfromq(dhd_bus_t * bus,uint maxframes)2433 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2434 {
2435 uint cnt = 0;
2436 uint8 tx_prec_map;
2437 uint16 txpktqlen = 0;
2438 uint32 intstatus = 0;
2439 uint retries = 0;
2440 osl_t *osh;
2441 dhd_pub_t *dhd = bus->dhd;
2442 sdpcmd_regs_t *regs = bus->regs;
2443 #ifdef DHD_LOSSLESS_ROAMING
2444 uint8 *pktdata;
2445 struct ether_header *eh;
2446 #ifdef BDC
2447 struct bdc_header *bdc_header;
2448 uint8 data_offset;
2449 #endif // endif
2450 #endif /* DHD_LOSSLESS_ROAMING */
2451
2452 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2453
2454 if (!KSO_ENAB(bus)) {
2455 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2456 return BCME_NODEVICE;
2457 }
2458
2459 osh = dhd->osh;
2460 tx_prec_map = ~bus->flowcontrol;
2461 #ifdef DHD_LOSSLESS_ROAMING
2462 tx_prec_map &= dhd->dequeue_prec_map;
2463 #endif /* DHD_LOSSLESS_ROAMING */
2464 for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
2465 int i;
2466 int num_pkt = 1;
2467 void *pkts[MAX_TX_PKTCHAIN_CNT];
2468 int prec_out;
2469 uint datalen = 0;
2470
2471 dhd_os_sdlock_txq(bus->dhd);
2472 if (bus->txglom_enable) {
2473 uint32 glomlimit = (uint32)bus->txglomsize;
2474 #if defined(BCMSDIOH_STD)
2475 if (bus->blocksize == 64) {
2476 glomlimit = MIN((uint32)bus->txglomsize, BLK_64_MAXTXGLOM);
2477 }
2478 #endif /* BCMSDIOH_STD */
2479 num_pkt = MIN((uint32)DATABUFCNT(bus), glomlimit);
2480 num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
2481 }
2482 num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
2483 for (i = 0; i < num_pkt; i++) {
2484 pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2485 if (!pkts[i]) {
2486 DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
2487 __FUNCTION__));
2488 ASSERT(0);
2489 break;
2490 }
2491 #ifdef DHD_LOSSLESS_ROAMING
2492 pktdata = (uint8 *)PKTDATA(osh, pkts[i]);
2493 #ifdef BDC
2494 /* Skip BDC header */
2495 bdc_header = (struct bdc_header *)pktdata;
2496 data_offset = bdc_header->dataOffset;
2497 pktdata += BDC_HEADER_LEN + (data_offset << 2);
2498 #endif // endif
2499 eh = (struct ether_header *)pktdata;
2500 if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
2501 uint8 prio = (uint8)PKTPRIO(pkts[i]);
2502
2503 /* Restore to original priority for 802.1X packet */
2504 if (prio == PRIO_8021D_NC) {
2505 PKTSETPRIO(pkts[i], dhd->prio_8021x);
2506 #ifdef BDC
2507 /* Restore to original priority in BDC header */
2508 bdc_header->priority =
2509 (dhd->prio_8021x & BDC_PRIORITY_MASK);
2510 #endif // endif
2511 }
2512 }
2513 #endif /* DHD_LOSSLESS_ROAMING */
2514 if (!bus->dhd->conf->orphan_move)
2515 PKTORPHAN(pkts[i], bus->dhd->conf->tsq);
2516 datalen += PKTLEN(osh, pkts[i]);
2517 }
2518 dhd_os_sdunlock_txq(bus->dhd);
2519
2520 if (i == 0)
2521 break;
2522 if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK)
2523 dhd->tx_errors++;
2524 else {
2525 dhd->dstats.tx_bytes += datalen;
2526 bus->txglomframes++;
2527 bus->txglompkts += num_pkt;
2528 #ifdef PKT_STATICS
2529 bus->tx_statics.glom_cnt_us[num_pkt-1] =
2530 (bus->tx_statics.glom_cnt[num_pkt-1]*bus->tx_statics.glom_cnt_us[num_pkt-1]
2531 + bcmsdh_get_spend_time(bus->sdh))/(bus->tx_statics.glom_cnt[num_pkt-1] + 1);
2532 #endif
2533 }
2534 cnt += i;
2535 #ifdef PKT_STATICS
2536 if (num_pkt) {
2537 bus->tx_statics.glom_cnt[num_pkt-1]++;
2538 if (num_pkt > bus->tx_statics.glom_max)
2539 bus->tx_statics.glom_max = num_pkt;
2540 }
2541 #endif
2542
2543 /* In poll mode, need to check for other events */
2544 if (!bus->intr && cnt)
2545 {
2546 /* Check device status, signal pending interrupt */
2547 R_SDREG(intstatus, ®s->intstatus, retries);
2548 bus->f2txdata++;
2549 if (bcmsdh_regfail(bus->sdh))
2550 break;
2551 if (intstatus & bus->hostintmask)
2552 bus->ipend = TRUE;
2553 }
2554
2555 }
2556
2557 if (dhd_doflow) {
2558 dhd_os_sdlock_txq(bus->dhd);
2559 txpktqlen = pktq_n_pkts_tot(&bus->txq);
2560 dhd_os_sdunlock_txq(bus->dhd);
2561 }
2562
2563 /* Do flow-control if needed */
2564 if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
2565 bool wlfc_enabled = FALSE;
2566 #ifdef PROP_TXSTATUS
2567 wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED);
2568 #endif // endif
2569 if (!wlfc_enabled && dhd_doflow && dhd->txoff) {
2570 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2571 }
2572 }
2573
2574 return cnt;
2575 }
2576
2577 static void
dhdsdio_sendpendctl(dhd_bus_t * bus)2578 dhdsdio_sendpendctl(dhd_bus_t *bus)
2579 {
2580 bcmsdh_info_t *sdh = bus->sdh;
2581 int ret;
2582 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2583
2584 if (bus->txglom_enable)
2585 frame_seq += SDPCM_HWEXT_LEN;
2586
2587 if (*frame_seq != bus->tx_seq) {
2588 DHD_INFO(("%s IOCTL frame seq lag detected!"
2589 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2590 __FUNCTION__, *frame_seq, bus->tx_seq));
2591 *frame_seq = bus->tx_seq;
2592 }
2593
2594 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2595 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2596 NULL, NULL, NULL, 1);
2597 if (ret == BCME_OK)
2598 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2599
2600 bus->ctrl_frame_stat = FALSE;
2601 dhd_wait_event_wakeup(bus->dhd);
2602 }
2603
2604 int
dhd_bus_txctl(struct dhd_bus * bus,uchar * msg,uint msglen)2605 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2606 {
2607 static int err_nodevice = 0;
2608 uint8 *frame;
2609 uint16 len;
2610 uint32 swheader;
2611 uint8 doff = 0;
2612 int ret = -1;
2613 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
2614
2615 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2616
2617 if (bus->dhd->dongle_reset)
2618 return -EIO;
2619
2620 /* Back the pointer to make a room for bus header */
2621 frame = msg - sdpcm_hdrlen;
2622 len = (msglen += sdpcm_hdrlen);
2623
2624 /* Add alignment padding (optional for ctl frames) */
2625 if (dhd_alignctl) {
2626 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2627 frame -= doff;
2628 len += doff;
2629 msglen += doff;
2630 bzero(frame, doff + sdpcm_hdrlen);
2631 }
2632 ASSERT(doff < DHD_SDALIGN);
2633 }
2634 doff += sdpcm_hdrlen;
2635
2636 #ifndef BCMSPI
2637 /* Round send length to next SDIO block */
2638 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2639 uint16 pad = bus->blocksize - (len % bus->blocksize);
2640 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2641 len += pad;
2642 } else if (len % DHD_SDALIGN) {
2643 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2644 }
2645 #endif /* BCMSPI */
2646
2647 /* Satisfy length-alignment requirements */
2648 if (forcealign && (len & (ALIGNMENT - 1)))
2649 len = ROUNDUP(len, ALIGNMENT);
2650
2651 ASSERT(ISALIGNED((uintptr)frame, 2));
2652
2653 /* Need to lock here to protect txseq and SDIO tx calls */
2654 dhd_os_sdlock(bus->dhd);
2655 if (bus->dhd->conf->txctl_tmo_fix > 0 && !TXCTLOK(bus)) {
2656 bus->ctrl_wait = TRUE;
2657 dhd_os_sdunlock(bus->dhd);
2658 wait_event_interruptible_timeout(bus->ctrl_tx_wait, TXCTLOK(bus),
2659 msecs_to_jiffies(bus->dhd->conf->txctl_tmo_fix));
2660 dhd_os_sdlock(bus->dhd);
2661 bus->ctrl_wait = FALSE;
2662 }
2663
2664 BUS_WAKE(bus);
2665
2666 /* Make sure backplane clock is on */
2667 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2668
2669 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2670 *(uint16*)frame = htol16((uint16)msglen);
2671 *(((uint16*)frame) + 1) = htol16(~msglen);
2672
2673 if (bus->txglom_enable) {
2674 uint32 hwheader1, hwheader2;
2675 /* Software tag: channel, sequence number, data offset */
2676 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2677 | bus->tx_seq
2678 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2679 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2680 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2681 + SDPCM_HWEXT_LEN + sizeof(swheader));
2682
2683 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2684 hwheader2 = (len - (msglen)) << 16;
2685 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2686 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2687
2688 *(uint16*)frame = htol16(len);
2689 *(((uint16*)frame) + 1) = htol16(~(len));
2690 } else {
2691 /* Software tag: channel, sequence number, data offset */
2692 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2693 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2694 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2695 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2696 }
2697
2698 #ifdef DHD_ULP
2699 dhd_ulp_set_path(bus->dhd, DHD_ULP_TX_CTRL);
2700
2701 if (!TXCTLOK(bus) || !dhd_ulp_f2_ready(bus->dhd, bus->sdh))
2702 #else
2703 if (!TXCTLOK(bus))
2704 #endif // endif
2705 {
2706 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2707 __FUNCTION__, bus->tx_max, bus->tx_seq));
2708 bus->ctrl_frame_stat = TRUE;
2709 /* Send from dpc */
2710 bus->ctrl_frame_buf = frame;
2711 bus->ctrl_frame_len = len;
2712
2713 if (!bus->dpc_sched) {
2714 bus->dpc_sched = TRUE;
2715 dhd_sched_dpc(bus->dhd);
2716 }
2717 if (bus->ctrl_frame_stat) {
2718 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2719 }
2720
2721 if (bus->ctrl_frame_stat == FALSE) {
2722 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2723 ret = 0;
2724 } else {
2725 bus->dhd->txcnt_timeout++;
2726 if (!bus->dhd->hang_was_sent) {
2727 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2728 __FUNCTION__, bus->dhd->txcnt_timeout));
2729 #ifdef BCMSDIO_RXLIM_POST
2730 DHD_ERROR(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n",
2731 __FUNCTION__,
2732 bus->dhd->conf->rxlim_en, bus->rxlim_en, bus->rxlim_addr));
2733 #endif /* BCMSDIO_RXLIM_POST */
2734 }
2735 #ifdef DHD_FW_COREDUMP
2736 /* Collect socram dump */
2737 if ((bus->dhd->memdump_enabled) &&
2738 (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)) {
2739 /* collect core dump */
2740 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT_TX;
2741 dhd_os_sdunlock(bus->dhd);
2742 dhd_bus_mem_dump(bus->dhd);
2743 dhd_os_sdlock(bus->dhd);
2744 }
2745 #endif /* DHD_FW_COREDUMP */
2746 ret = -1;
2747 bus->ctrl_frame_stat = FALSE;
2748 goto done;
2749 }
2750 }
2751
2752 bus->dhd->txcnt_timeout = 0;
2753 bus->ctrl_frame_stat = TRUE;
2754
2755 if (ret == -1) {
2756 #ifdef DHD_DEBUG
2757 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2758 prhex("Tx Frame", frame, len);
2759 } else if (DHD_HDRS_ON()) {
2760 prhex("TxHdr", frame, MIN(len, 16));
2761 }
2762 #endif // endif
2763 #ifdef PKT_STATICS
2764 bus->tx_statics.ctrl_count++;
2765 bus->tx_statics.ctrl_size += len;
2766 #endif
2767 ret = dhd_bcmsdh_send_buffer(bus, frame, len);
2768 }
2769 bus->ctrl_frame_stat = FALSE;
2770 #ifdef DHD_ULP
2771 dhd_ulp_enable_cached_sbwad(bus->dhd, bus->sdh);
2772 #endif /* DHD_ULP */
2773
2774 done:
2775 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
2776 NO_OTHER_ACTIVE_BUS_USER(bus)) {
2777 bus->activity = FALSE;
2778 dhdsdio_bussleep(bus, TRUE);
2779 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
2780 }
2781
2782 dhd_os_sdunlock(bus->dhd);
2783
2784 if (ret)
2785 bus->dhd->tx_ctlerrs++;
2786 else
2787 bus->dhd->tx_ctlpkts++;
2788
2789 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) {
2790 #ifdef DHD_PM_CONTROL_FROM_FILE
2791 if (g_pm_control == TRUE) {
2792 return -BCME_ERROR;
2793 } else {
2794 return -ETIMEDOUT;
2795 }
2796 #else
2797 return -ETIMEDOUT;
2798 #endif /* DHD_PM_CONTROL_FROM_FILE */
2799 }
2800 if (ret == BCME_NODEVICE)
2801 err_nodevice++;
2802 else
2803 err_nodevice = 0;
2804
2805 return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0;
2806 }
2807
2808 int
dhd_bus_rxctl(struct dhd_bus * bus,uchar * msg,uint msglen)2809 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2810 {
2811 int timeleft;
2812 uint rxlen = 0;
2813 static uint cnt = 0;
2814
2815 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2816
2817 if (bus->dhd->dongle_reset)
2818 return -EIO;
2819
2820 /* Wait until control frame is available */
2821 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
2822
2823 dhd_os_sdlock(bus->dhd);
2824 rxlen = bus->rxlen;
2825 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2826 bus->rxlen = 0;
2827 dhd_os_sdunlock(bus->dhd);
2828
2829 if (bus->dhd->conf->ctrl_resched > 0 && !rxlen && timeleft == 0) {
2830 cnt++;
2831 if (cnt <= bus->dhd->conf->ctrl_resched) {
2832 uint32 status, retry = 0;
2833 R_SDREG(status, &bus->regs->intstatus, retry);
2834 if ((status & I_HMB_HOST_INT) || PKT_AVAILABLE(bus, status)) {
2835 DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, status=0x%x\n",
2836 __FUNCTION__, cnt, status));
2837 bus->ipend = TRUE;
2838 bus->dpc_sched = TRUE;
2839 dhd_sched_dpc(bus->dhd);
2840
2841 /* Wait until control frame is available */
2842 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
2843
2844 dhd_os_sdlock(bus->dhd);
2845 rxlen = bus->rxlen;
2846 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2847 bus->rxlen = 0;
2848 dhd_os_sdunlock(bus->dhd);
2849 }
2850 }
2851 } else {
2852 cnt = 0;
2853 }
2854
2855 if (rxlen) {
2856 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2857 __FUNCTION__, rxlen, msglen));
2858 } else {
2859 if (timeleft == 0) {
2860 #ifdef DHD_DEBUG
2861 uint32 status, retry = 0;
2862 R_SDREG(status, &bus->regs->intstatus, retry);
2863 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2864 __FUNCTION__, status));
2865 #else
2866 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2867 #endif /* DHD_DEBUG */
2868 if (!bus->dhd->dongle_trap_occured) {
2869 #ifdef DHD_FW_COREDUMP
2870 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT;
2871 #endif /* DHD_FW_COREDUMP */
2872 dhd_os_sdlock(bus->dhd);
2873 dhdsdio_checkdied(bus, NULL, 0);
2874 dhd_os_sdunlock(bus->dhd);
2875 }
2876 } else {
2877 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2878 if (!bus->dhd->dongle_trap_occured) {
2879 #ifdef DHD_FW_COREDUMP
2880 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_UNKNOWN;
2881 #endif /* DHD_FW_COREDUMP */
2882 dhd_os_sdlock(bus->dhd);
2883 dhdsdio_checkdied(bus, NULL, 0);
2884 dhd_os_sdunlock(bus->dhd);
2885 }
2886 }
2887 #ifdef DHD_FW_COREDUMP
2888 /* Dump the ram image */
2889 if (bus->dhd->memdump_enabled && !bus->dhd->dongle_trap_occured)
2890 dhdsdio_mem_dump(bus);
2891 #endif /* DHD_FW_COREDUMP */
2892 }
2893 if (timeleft == 0) {
2894 if (rxlen == 0)
2895 bus->dhd->rxcnt_timeout++;
2896 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2897 bus->dhd->rxcnt_timeout, rxlen));
2898 #ifdef DHD_FW_COREDUMP
2899 /* collect socram dump */
2900 if (bus->dhd->memdump_enabled) {
2901 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT_RX;
2902 dhd_bus_mem_dump(bus->dhd);
2903 }
2904 #endif /* DHD_FW_COREDUMP */
2905 } else {
2906 bus->dhd->rxcnt_timeout = 0;
2907 }
2908
2909 if (rxlen)
2910 bus->dhd->rx_ctlpkts++;
2911 else
2912 bus->dhd->rx_ctlerrs++;
2913
2914 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) {
2915 #ifdef DHD_PM_CONTROL_FROM_FILE
2916 if (g_pm_control == TRUE) {
2917 return -BCME_ERROR;
2918 } else {
2919 return -ETIMEDOUT;
2920 }
2921 #else
2922 return -ETIMEDOUT;
2923 #endif /* DHD_PM_CONTROL_FROM_FILE */
2924 }
2925 if (bus->dhd->dongle_trap_occured)
2926 return -EREMOTEIO;
2927
2928 return rxlen ? (int)rxlen : -EIO;
2929 }
2930
2931 /* IOVar table */
2932 enum {
2933 IOV_INTR = 1,
2934 IOV_POLLRATE,
2935 IOV_SDREG,
2936 IOV_SBREG,
2937 IOV_SDCIS,
2938 IOV_RAMSIZE,
2939 IOV_RAMSTART,
2940 #ifdef DHD_DEBUG
2941 IOV_CHECKDIED,
2942 IOV_SERIALCONS,
2943 #endif /* DHD_DEBUG */
2944 IOV_SET_DOWNLOAD_STATE,
2945 IOV_SOCRAM_STATE,
2946 IOV_FORCEEVEN,
2947 IOV_SDIOD_DRIVE,
2948 IOV_READAHEAD,
2949 IOV_SDRXCHAIN,
2950 IOV_ALIGNCTL,
2951 IOV_SDALIGN,
2952 IOV_DEVRESET,
2953 IOV_CPU,
2954 #if defined(USE_SDIOFIFO_IOVAR)
2955 IOV_WATERMARK,
2956 IOV_MESBUSYCTRL,
2957 #endif /* USE_SDIOFIFO_IOVAR */
2958 #ifdef SDTEST
2959 IOV_PKTGEN,
2960 IOV_EXTLOOP,
2961 #endif /* SDTEST */
2962 IOV_SPROM,
2963 IOV_TXBOUND,
2964 IOV_RXBOUND,
2965 IOV_TXMINMAX,
2966 IOV_IDLETIME,
2967 IOV_IDLECLOCK,
2968 IOV_SD1IDLE,
2969 IOV_SLEEP,
2970 IOV_DONGLEISOLATION,
2971 IOV_KSO,
2972 IOV_DEVSLEEP,
2973 IOV_DEVCAP,
2974 IOV_VARS,
2975 #ifdef SOFTAP
2976 IOV_FWPATH,
2977 #endif // endif
2978 IOV_TXGLOMSIZE,
2979 IOV_TXGLOMMODE,
2980 IOV_HANGREPORT,
2981 IOV_TXINRX_THRES,
2982 IOV_SDIO_SUSPEND
2983 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
2984 IOV_GDB_SERVER, /**< starts gdb server on given interface */
2985 #endif /* DEBUGGER || DHD_DSCOPE */
2986 };
2987
2988 const bcm_iovar_t dhdsdio_iovars[] = {
2989 {"intr", IOV_INTR, 0, 0, IOVT_BOOL, 0 },
2990 {"sleep", IOV_SLEEP, 0, 0, IOVT_BOOL, 0 },
2991 {"pollrate", IOV_POLLRATE, 0, 0, IOVT_UINT32, 0 },
2992 {"idletime", IOV_IDLETIME, 0, 0, IOVT_INT32, 0 },
2993 {"idleclock", IOV_IDLECLOCK, 0, 0, IOVT_INT32, 0 },
2994 {"sd1idle", IOV_SD1IDLE, 0, 0, IOVT_BOOL, 0 },
2995 {"ramsize", IOV_RAMSIZE, 0, 0, IOVT_UINT32, 0 },
2996 {"ramstart", IOV_RAMSTART, 0, 0, IOVT_UINT32, 0 },
2997 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0 },
2998 {"socram_state", IOV_SOCRAM_STATE, 0, 0, IOVT_BOOL, 0 },
2999 {"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0 },
3000 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, 0, IOVT_UINT32, 0 },
3001 {"readahead", IOV_READAHEAD, 0, 0, IOVT_BOOL, 0 },
3002 {"sdrxchain", IOV_SDRXCHAIN, 0, 0, IOVT_BOOL, 0 },
3003 {"alignctl", IOV_ALIGNCTL, 0, 0, IOVT_BOOL, 0 },
3004 {"sdalign", IOV_SDALIGN, 0, 0, IOVT_BOOL, 0 },
3005 {"devreset", IOV_DEVRESET, 0, 0, IOVT_BOOL, 0 },
3006 #ifdef DHD_DEBUG
3007 {"sdreg", IOV_SDREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) },
3008 {"sbreg", IOV_SBREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) },
3009 {"sd_cis", IOV_SDCIS, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
3010 {"forcealign", IOV_FORCEEVEN, 0, 0, IOVT_BOOL, 0 },
3011 {"txbound", IOV_TXBOUND, 0, 0, IOVT_UINT32, 0 },
3012 {"rxbound", IOV_RXBOUND, 0, 0, IOVT_UINT32, 0 },
3013 {"txminmax", IOV_TXMINMAX, 0, 0, IOVT_UINT32, 0 },
3014 {"cpu", IOV_CPU, 0, 0, IOVT_BOOL, 0 },
3015 #ifdef DHD_DEBUG
3016 {"checkdied", IOV_CHECKDIED, 0, 0, IOVT_BUFFER, 0 },
3017 {"serial", IOV_SERIALCONS, 0, 0, IOVT_UINT32, 0 },
3018 #endif /* DHD_DEBUG */
3019 #endif /* DHD_DEBUG */
3020 #ifdef SDTEST
3021 {"extloop", IOV_EXTLOOP, 0, 0, IOVT_BOOL, 0 },
3022 {"pktgen", IOV_PKTGEN, 0, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
3023 #endif /* SDTEST */
3024 #if defined(USE_SDIOFIFO_IOVAR)
3025 {"watermark", IOV_WATERMARK, 0, 0, IOVT_UINT32, 0 },
3026 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, 0, IOVT_UINT32, 0 },
3027 #endif /* USE_SDIOFIFO_IOVAR */
3028 {"devcap", IOV_DEVCAP, 0, 0, IOVT_UINT32, 0 },
3029 {"dngl_isolation", IOV_DONGLEISOLATION, 0, 0, IOVT_UINT32, 0 },
3030 {"kso", IOV_KSO, 0, 0, IOVT_UINT32, 0 },
3031 {"devsleep", IOV_DEVSLEEP, 0, 0, IOVT_UINT32, 0 },
3032 #ifdef SOFTAP
3033 {"fwpath", IOV_FWPATH, 0, 0, IOVT_BUFFER, 0 },
3034 #endif // endif
3035 {"txglomsize", IOV_TXGLOMSIZE, 0, 0, IOVT_UINT32, 0 },
3036 {"fw_hang_report", IOV_HANGREPORT, 0, 0, IOVT_BOOL, 0 },
3037 {"txinrx_thres", IOV_TXINRX_THRES, 0, 0, IOVT_INT32, 0 },
3038 {"sdio_suspend", IOV_SDIO_SUSPEND, 0, 0, IOVT_UINT32, 0 },
3039 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
3040 {"gdb_server", IOV_GDB_SERVER, 0, 0, IOVT_UINT32, 0 },
3041 #endif /* DEBUGGER || DHD_DSCOPE */
3042 {NULL, 0, 0, 0, 0, 0 }
3043 };
3044
3045 static void
dhd_dump_pct(struct bcmstrbuf * strbuf,char * desc,uint num,uint div)3046 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
3047 {
3048 uint q1, q2;
3049
3050 if (!div) {
3051 bcm_bprintf(strbuf, "%s N/A", desc);
3052 } else {
3053 q1 = num / div;
3054 q2 = (100 * (num - (q1 * div))) / div;
3055 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
3056 }
3057 }
3058
3059 void
dhd_bus_dump(dhd_pub_t * dhdp,struct bcmstrbuf * strbuf)3060 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
3061 {
3062 dhd_bus_t *bus = dhdp->bus;
3063 #if defined(DHD_WAKE_STATUS) && defined(DHD_WAKE_EVENT_STATUS)
3064 int i;
3065 #endif // endif
3066
3067 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
3068 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
3069 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
3070 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
3071 bus->fcstate, pktq_n_pkts_tot(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
3072 bus->rxlen, bus->rx_seq);
3073 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
3074 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
3075
3076 #ifdef DHD_WAKE_STATUS
3077 bcm_bprintf(strbuf, "wake %u rxwake %u readctrlwake %u\n",
3078 bcmsdh_get_total_wake(bus->sdh), bus->wake_counts.rxwake,
3079 bus->wake_counts.rcwake);
3080 #ifdef DHD_WAKE_RX_STATUS
3081 bcm_bprintf(strbuf, " unicast %u multicast %u broadcast %u arp %u\n",
3082 bus->wake_counts.rx_ucast, bus->wake_counts.rx_mcast,
3083 bus->wake_counts.rx_bcast, bus->wake_counts.rx_arp);
3084 bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp6 %u multiother %u\n",
3085 bus->wake_counts.rx_multi_ipv4, bus->wake_counts.rx_multi_ipv6,
3086 bus->wake_counts.rx_icmpv6, bus->wake_counts.rx_multi_other);
3087 bcm_bprintf(strbuf, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n",
3088 bus->wake_counts.rx_icmpv6_ra, bus->wake_counts.rx_icmpv6_na,
3089 bus->wake_counts.rx_icmpv6_ns);
3090 #endif /* DHD_WAKE_RX_STATUS */
3091 #ifdef DHD_WAKE_EVENT_STATUS
3092 for (i = 0; i < WLC_E_LAST; i++)
3093 if (bus->wake_counts.rc_event[i] != 0)
3094 bcm_bprintf(strbuf, " %s = %u\n", bcmevent_get_name(i),
3095 bus->wake_counts.rc_event[i]);
3096 bcm_bprintf(strbuf, "\n");
3097 #endif /* DHD_WAKE_EVENT_STATUS */
3098 #endif /* DHD_WAKE_STATUS */
3099
3100 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
3101 bus->pollrate, bus->pollcnt, bus->regfails);
3102
3103 bcm_bprintf(strbuf, "\nAdditional counters:\n");
3104 #ifdef DHDENABLE_TAILPAD
3105 bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
3106 bus->tx_tailpad_chain, bus->tx_tailpad_pktget);
3107 #endif /* DHDENABLE_TAILPAD */
3108 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
3109 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
3110 bus->rxc_errors);
3111 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
3112 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
3113 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
3114 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
3115 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
3116 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
3117 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
3118 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
3119 bus->f2txdata, bus->f1regdata);
3120 {
3121 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
3122 (bus->f2rxhdrs + bus->f2rxdata));
3123 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
3124 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
3125 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
3126 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
3127 bcm_bprintf(strbuf, "\n");
3128
3129 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
3130 bus->dhd->rx_packets);
3131 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
3132 bcm_bprintf(strbuf, "\n");
3133
3134 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
3135 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
3136 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
3137 (bus->f2txdata + bus->f1regdata));
3138 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
3139 bcm_bprintf(strbuf, "\n");
3140
3141 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
3142 (bus->dhd->tx_packets + bus->dhd->rx_packets),
3143 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
3144 dhd_dump_pct(strbuf, ", pkts/f1sd",
3145 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
3146 dhd_dump_pct(strbuf, ", pkts/sd",
3147 (bus->dhd->tx_packets + bus->dhd->rx_packets),
3148 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
3149 dhd_dump_pct(strbuf, ", pkts/int",
3150 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
3151 bcm_bprintf(strbuf, "\n\n");
3152 }
3153
3154 #ifdef SDTEST
3155 if (bus->pktgen_count) {
3156 bcm_bprintf(strbuf, "pktgen config and count:\n");
3157 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
3158 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
3159 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
3160 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
3161 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
3162 }
3163 #endif /* SDTEST */
3164 #ifdef DHD_DEBUG
3165 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
3166 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
3167 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
3168 #endif /* DHD_DEBUG */
3169 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
3170 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
3171 dhd_dump_pct(strbuf, "Tx: glom pct", (100 * bus->txglompkts), bus->dhd->tx_packets);
3172 dhd_dump_pct(strbuf, ", pkts/glom", bus->txglompkts, bus->txglomframes);
3173 bcm_bprintf(strbuf, "\n");
3174 bcm_bprintf(strbuf, "txglomframes %u, txglompkts %u\n", bus->txglomframes, bus->txglompkts);
3175 bcm_bprintf(strbuf, "\n");
3176 }
3177
3178 void
dhd_bus_clearcounts(dhd_pub_t * dhdp)3179 dhd_bus_clearcounts(dhd_pub_t *dhdp)
3180 {
3181 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
3182
3183 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
3184 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
3185 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
3186 #ifdef DHDENABLE_TAILPAD
3187 bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0;
3188 #endif /* DHDENABLE_TAILPAD */
3189 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
3190 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
3191 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
3192 bus->txglomframes = bus->txglompkts = 0;
3193 }
3194
3195 #ifdef SDTEST
3196 static int
dhdsdio_pktgen_get(dhd_bus_t * bus,uint8 * arg)3197 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
3198 {
3199 dhd_pktgen_t pktgen;
3200
3201 pktgen.version = DHD_PKTGEN_VERSION;
3202 pktgen.freq = bus->pktgen_freq;
3203 pktgen.count = bus->pktgen_count;
3204 pktgen.print = bus->pktgen_print;
3205 pktgen.total = bus->pktgen_total;
3206 pktgen.minlen = bus->pktgen_minlen;
3207 pktgen.maxlen = bus->pktgen_maxlen;
3208 pktgen.numsent = bus->pktgen_sent;
3209 pktgen.numrcvd = bus->pktgen_rcvd;
3210 pktgen.numfail = bus->pktgen_fail;
3211 pktgen.mode = bus->pktgen_mode;
3212 pktgen.stop = bus->pktgen_stop;
3213
3214 bcopy(&pktgen, arg, sizeof(pktgen));
3215
3216 return 0;
3217 }
3218
3219 static int
dhdsdio_pktgen_set(dhd_bus_t * bus,uint8 * arg)3220 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
3221 {
3222 dhd_pktgen_t pktgen;
3223 uint oldcnt, oldmode;
3224
3225 bcopy(arg, &pktgen, sizeof(pktgen));
3226 if (pktgen.version != DHD_PKTGEN_VERSION)
3227 return BCME_BADARG;
3228
3229 oldcnt = bus->pktgen_count;
3230 oldmode = bus->pktgen_mode;
3231
3232 bus->pktgen_freq = pktgen.freq;
3233 bus->pktgen_count = pktgen.count;
3234 bus->pktgen_print = pktgen.print;
3235 bus->pktgen_total = pktgen.total;
3236 bus->pktgen_minlen = pktgen.minlen;
3237 bus->pktgen_maxlen = pktgen.maxlen;
3238 bus->pktgen_mode = pktgen.mode;
3239 bus->pktgen_stop = pktgen.stop;
3240
3241 bus->pktgen_tick = bus->pktgen_ptick = 0;
3242 bus->pktgen_prev_time = jiffies;
3243 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
3244 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
3245
3246 /* Clear counts for a new pktgen (mode change, or was stopped) */
3247 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
3248 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
3249 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
3250 }
3251
3252 return 0;
3253 }
3254 #endif /* SDTEST */
3255
3256 static void
dhdsdio_devram_remap(dhd_bus_t * bus,bool val)3257 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
3258 {
3259 uint8 enable, protect, remap;
3260
3261 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3262 remap = val ? TRUE : FALSE;
3263 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
3264 }
3265
3266 static int
dhdsdio_membytes(dhd_bus_t * bus,bool write,uint32 address,uint8 * data,uint size)3267 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
3268 {
3269 int bcmerror = 0;
3270 uint32 sdaddr;
3271 uint dsize;
3272 uint8 *pdata;
3273
3274 /* In remap mode, adjust address beyond socram and redirect
3275 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
3276 * is not backplane accessible
3277 */
3278 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
3279 address -= bus->orig_ramsize;
3280 address += SOCDEVRAM_BP_ADDR;
3281 }
3282
3283 /* Determine initial transfer parameters */
3284 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3285 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
3286 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3287 else
3288 dsize = size;
3289
3290 /* Set the backplane window to include the start address */
3291 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3292 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3293 goto xfer_done;
3294 }
3295
3296 /* Do the transfer(s) */
3297 while (size) {
3298 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3299 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3300 (address & SBSDIO_SBWINDOW_MASK)));
3301 if (dsize <= MAX_MEM_BUF) {
3302 pdata = bus->membuf;
3303 if (write)
3304 memcpy(bus->membuf, data, dsize);
3305 } else {
3306 pdata = data;
3307 }
3308 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, pdata, dsize))) {
3309 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
3310 break;
3311 }
3312 if (dsize <= MAX_MEM_BUF && !write)
3313 memcpy(data, bus->membuf, dsize);
3314
3315 /* Adjust for next transfer (if any) */
3316 if ((size -= dsize)) {
3317 data += dsize;
3318 address += dsize;
3319 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3320 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3321 break;
3322 }
3323 sdaddr = 0;
3324 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3325 }
3326
3327 }
3328
3329 xfer_done:
3330 /* Return the window to backplane enumeration space for core access */
3331 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
3332 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
3333 bcmsdh_cur_sbwad(bus->sdh)));
3334 }
3335
3336 return bcmerror;
3337 }
3338
3339 static int
dhdsdio_readshared(dhd_bus_t * bus,sdpcm_shared_t * sh)3340 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
3341 {
3342 uint32 addr;
3343 int rv, i;
3344 uint32 shaddr = 0;
3345
3346 if (bus->sih == NULL) {
3347 if (bus->dhd && bus->dhd->dongle_reset) {
3348 DHD_ERROR(("%s: Dongle is in reset state\n", __FUNCTION__));
3349 return BCME_NOTREADY;
3350 } else {
3351 ASSERT(bus->dhd);
3352 ASSERT(bus->sih);
3353 DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__));
3354 return BCME_ERROR;
3355 }
3356 }
3357 if ((CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
3358 CHIPID(bus->sih->chip) == BCM43018_CHIP_ID) && !dhdsdio_sr_cap(bus))
3359 bus->srmemsize = 0;
3360
3361 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
3362 i = 0;
3363 do {
3364 /* Read last word in memory to determine address of sdpcm_shared structure */
3365 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
3366 return rv;
3367
3368 addr = ltoh32(addr);
3369
3370 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
3371
3372 /*
3373 * Check if addr is valid.
3374 * NVRAM length at the end of memory should have been overwritten.
3375 */
3376 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
3377 if ((bus->srmemsize > 0) && (i++ == 0)) {
3378 shaddr -= bus->srmemsize;
3379 } else {
3380 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3381 __FUNCTION__, addr));
3382 return BCME_ERROR;
3383 }
3384 } else
3385 break;
3386 } while (i < 2);
3387
3388 /* Read hndrte_shared structure */
3389 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
3390 return rv;
3391
3392 /* Endianness */
3393 sh->flags = ltoh32(sh->flags);
3394 sh->trap_addr = ltoh32(sh->trap_addr);
3395 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
3396 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
3397 sh->assert_line = ltoh32(sh->assert_line);
3398 sh->console_addr = ltoh32(sh->console_addr);
3399 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
3400
3401 #ifdef BCMSDIO_RXLIM_POST
3402 if (sh->flags & SDPCM_SHARED_RXLIM_POST) {
3403 if (bus->dhd->conf->rxlim_en)
3404 bus->rxlim_en = !!sh->msgtrace_addr;
3405 bus->rxlim_addr = sh->msgtrace_addr;
3406 DHD_INFO(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n",
3407 __FUNCTION__,
3408 bus->dhd->conf->rxlim_en, bus->rxlim_en, bus->rxlim_addr));
3409 sh->flags &= ~SDPCM_SHARED_RXLIM_POST;
3410 } else {
3411 bus->rxlim_en = 0;
3412 DHD_INFO(("%s: FW has no rx limit post support\n", __FUNCTION__));
3413 }
3414 #endif /* BCMSDIO_RXLIM_POST */
3415
3416 #ifdef BCMSDIO_TXSEQ_SYNC
3417 if (bus->dhd->conf->txseq_sync) {
3418 sh->txseq_sync_addr = ltoh32(sh->txseq_sync_addr);
3419 if (sh->flags & SDPCM_SHARED_TXSEQ_SYNC) {
3420 uint8 val = 0;
3421 DHD_INFO(("%s: TXSEQ_SYNC enabled in fw\n", __FUNCTION__));
3422 if (0 == dhdsdio_membytes(bus, FALSE, sh->txseq_sync_addr, (uint8 *)&val, 1)) {
3423 if (bus->tx_seq != val) {
3424 DHD_INFO(("%s: Sync tx_seq from %d to %d\n",
3425 __FUNCTION__, bus->tx_seq, val));
3426 bus->tx_seq = val;
3427 bus->tx_max = bus->tx_seq + 4;
3428 }
3429 }
3430 sh->flags &= ~SDPCM_SHARED_TXSEQ_SYNC;
3431 } else {
3432 bus->dhd->conf->txseq_sync = FALSE;
3433 }
3434 }
3435 #endif /* BCMSDIO_TXSEQ_SYNC */
3436
3437 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
3438 return BCME_OK;
3439
3440 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
3441 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3442 "is different than sdpcm_shared version %d in dongle\n",
3443 __FUNCTION__, SDPCM_SHARED_VERSION,
3444 sh->flags & SDPCM_SHARED_VERSION_MASK));
3445 return BCME_ERROR;
3446 }
3447
3448 return BCME_OK;
3449 }
3450
3451 #define CONSOLE_LINE_MAX 192
3452
3453 #ifdef DHD_DEBUG
3454 static int
dhdsdio_readconsole(dhd_bus_t * bus)3455 dhdsdio_readconsole(dhd_bus_t *bus)
3456 {
3457 dhd_console_t *c = &bus->console;
3458 uint8 line[CONSOLE_LINE_MAX], ch;
3459 uint32 n, idx, addr;
3460 int rv;
3461
3462 /* Don't do anything until FWREADY updates console address */
3463 if (bus->console_addr == 0)
3464 return 0;
3465
3466 if (!KSO_ENAB(bus))
3467 return 0;
3468
3469 /* Read console log struct */
3470 addr = bus->console_addr + OFFSETOF(hnd_cons_t, log);
3471 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
3472 return rv;
3473
3474 /* Allocate console buffer (one time only) */
3475 if (c->buf == NULL) {
3476 c->bufsize = ltoh32(c->log.buf_size);
3477 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
3478 return BCME_NOMEM;
3479 }
3480
3481 idx = ltoh32(c->log.idx);
3482
3483 /* Protect against corrupt value */
3484 if (idx > c->bufsize)
3485 return BCME_ERROR;
3486
3487 /* Skip reading the console buffer if the index pointer has not moved */
3488 if (idx == c->last)
3489 return BCME_OK;
3490
3491 /* Read the console buffer */
3492 addr = ltoh32(c->log.buf);
3493 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
3494 return rv;
3495
3496 while (c->last != idx) {
3497 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3498 if (c->last == idx) {
3499 /* This would output a partial line. Instead, back up
3500 * the buffer pointer and output this line next time around.
3501 */
3502 if (c->last >= n)
3503 c->last -= n;
3504 else
3505 c->last = c->bufsize - n;
3506 goto break2;
3507 }
3508 ch = c->buf[c->last];
3509 c->last = (c->last + 1) % c->bufsize;
3510 if (ch == '\n')
3511 break;
3512 line[n] = ch;
3513 }
3514
3515 if (n > 0) {
3516 if (line[n - 1] == '\r')
3517 n--;
3518 line[n] = 0;
3519 printf("CONSOLE: %s\n", line);
3520 #ifdef LOG_INTO_TCPDUMP
3521 dhd_sendup_log(bus->dhd, line, n);
3522 #endif /* LOG_INTO_TCPDUMP */
3523 }
3524 }
3525 break2:
3526
3527 return BCME_OK;
3528 }
3529 #endif /* DHD_DEBUG */
3530
3531 static int
dhdsdio_checkdied(dhd_bus_t * bus,char * data,uint size)3532 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
3533 {
3534 int bcmerror = 0;
3535 uint msize = 512;
3536 char *mbuffer = NULL;
3537 char *console_buffer = NULL;
3538 uint maxstrlen = 256;
3539 char *str = NULL;
3540 sdpcm_shared_t l_sdpcm_shared;
3541 struct bcmstrbuf strbuf;
3542 uint32 console_ptr, console_size, console_index;
3543 uint8 line[CONSOLE_LINE_MAX], ch;
3544 uint32 n, i, addr;
3545 int rv;
3546
3547 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3548
3549 if (DHD_NOCHECKDIED_ON())
3550 return 0;
3551
3552 if (data == NULL) {
3553 /*
3554 * Called after a rx ctrl timeout. "data" is NULL.
3555 * allocate memory to trace the trap or assert.
3556 */
3557 size = msize;
3558 mbuffer = data = MALLOC(bus->dhd->osh, msize);
3559 if (mbuffer == NULL) {
3560 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
3561 bcmerror = BCME_NOMEM;
3562 goto done;
3563 }
3564 }
3565
3566 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
3567 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
3568 bcmerror = BCME_NOMEM;
3569 goto done;
3570 }
3571
3572 if ((bcmerror = dhdsdio_readshared(bus, &l_sdpcm_shared)) < 0)
3573 goto done;
3574
3575 bcm_binit(&strbuf, data, size);
3576
3577 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
3578 l_sdpcm_shared.msgtrace_addr, l_sdpcm_shared.console_addr);
3579
3580 if ((l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
3581 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3582 * (Avoids conflict with real asserts for programmatic parsing of output.)
3583 */
3584 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3585 }
3586
3587 if ((l_sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3588 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3589 * (Avoids conflict with real asserts for programmatic parsing of output.)
3590 */
3591 bcm_bprintf(&strbuf, "No trap%s in dongle",
3592 (l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3593 ?"/assrt" :"");
3594 } else {
3595 if (l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3596 /* Download assert */
3597 bcm_bprintf(&strbuf, "Dongle assert");
3598 if (l_sdpcm_shared.assert_exp_addr != 0) {
3599 str[0] = '\0';
3600 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3601 l_sdpcm_shared.assert_exp_addr,
3602 (uint8 *)str, maxstrlen)) < 0)
3603 goto done;
3604
3605 str[maxstrlen - 1] = '\0';
3606 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3607 }
3608
3609 if (l_sdpcm_shared.assert_file_addr != 0) {
3610 str[0] = '\0';
3611 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3612 l_sdpcm_shared.assert_file_addr,
3613 (uint8 *)str, maxstrlen)) < 0)
3614 goto done;
3615
3616 str[maxstrlen - 1] = '\0';
3617 bcm_bprintf(&strbuf, " file \"%s\"", str);
3618 }
3619
3620 bcm_bprintf(&strbuf, " line %d ", l_sdpcm_shared.assert_line);
3621 }
3622
3623 if (l_sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3624 trap_t *tr = &bus->dhd->last_trap_info;
3625 bus->dhd->dongle_trap_occured = TRUE;
3626 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3627 l_sdpcm_shared.trap_addr,
3628 (uint8*)tr, sizeof(trap_t))) < 0)
3629 goto done;
3630
3631 bus->dongle_trap_addr = ltoh32(l_sdpcm_shared.trap_addr);
3632
3633 dhd_bus_dump_trap_info(bus, &strbuf);
3634
3635 addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log);
3636 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3637 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3638 goto printbuf;
3639
3640 addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size);
3641 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3642 (uint8 *)&console_size, sizeof(console_size))) < 0)
3643 goto printbuf;
3644
3645 addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx);
3646 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3647 (uint8 *)&console_index, sizeof(console_index))) < 0)
3648 goto printbuf;
3649
3650 console_ptr = ltoh32(console_ptr);
3651 console_size = ltoh32(console_size);
3652 console_index = ltoh32(console_index);
3653
3654 if (console_size > CONSOLE_BUFFER_MAX ||
3655 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3656 goto printbuf;
3657
3658 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3659 (uint8 *)console_buffer, console_size)) < 0)
3660 goto printbuf;
3661
3662 for (i = 0, n = 0; i < console_size; i += n + 1) {
3663 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3664 ch = console_buffer[(console_index + i + n) % console_size];
3665 if (ch == '\n')
3666 break;
3667 line[n] = ch;
3668 }
3669
3670 if (n > 0) {
3671 if (line[n - 1] == '\r')
3672 n--;
3673 line[n] = 0;
3674 /* Don't use DHD_ERROR macro since we print
3675 * a lot of information quickly. The macro
3676 * will truncate a lot of the printfs
3677 */
3678
3679 if (dhd_msg_level & DHD_ERROR_VAL)
3680 printf("CONSOLE: %s\n", line);
3681 }
3682 }
3683 }
3684 }
3685
3686 printbuf:
3687 if (l_sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3688 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3689 }
3690
3691 #if defined(DHD_FW_COREDUMP)
3692 if (bus->dhd->memdump_enabled && (l_sdpcm_shared.flags & SDPCM_SHARED_TRAP)) {
3693 /* Mem dump to a file on device */
3694 bus->dhd->memdump_type = DUMP_TYPE_DONGLE_TRAP;
3695 dhd_os_sdunlock(bus->dhd);
3696 dhdsdio_mem_dump(bus);
3697 dhd_os_sdlock(bus->dhd);
3698 }
3699 #endif /* #if defined(DHD_FW_COREDUMP) */
3700
3701 done:
3702 if (mbuffer)
3703 MFREE(bus->dhd->osh, mbuffer, msize);
3704 if (str)
3705 MFREE(bus->dhd->osh, str, maxstrlen);
3706 if (console_buffer)
3707 MFREE(bus->dhd->osh, console_buffer, console_size);
3708
3709 return bcmerror;
3710 }
3711
3712 #if defined(DHD_FW_COREDUMP)
3713 int
dhd_bus_mem_dump(dhd_pub_t * dhdp)3714 dhd_bus_mem_dump(dhd_pub_t *dhdp)
3715 {
3716 dhd_bus_t *bus = dhdp->bus;
3717 if (dhdp->busstate == DHD_BUS_SUSPEND) {
3718 DHD_ERROR(("%s: Bus is suspend so skip\n", __FUNCTION__));
3719 return 0;
3720 }
3721 return dhdsdio_mem_dump(bus);
3722 }
3723
3724 int
dhd_bus_get_mem_dump(dhd_pub_t * dhdp)3725 dhd_bus_get_mem_dump(dhd_pub_t *dhdp)
3726 {
3727 if (!dhdp) {
3728 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3729 return BCME_ERROR;
3730 }
3731
3732 return dhdsdio_get_mem_dump(dhdp->bus);
3733 }
3734
3735 static int
dhdsdio_get_mem_dump(dhd_bus_t * bus)3736 dhdsdio_get_mem_dump(dhd_bus_t *bus)
3737 {
3738 int ret = BCME_ERROR;
3739 int size = bus->ramsize; /* Full mem size */
3740 uint32 start = bus->dongle_ram_base; /* Start address */
3741 uint read_size = 0; /* Read size of each iteration */
3742 uint8 *p_buf = NULL, *databuf = NULL;
3743
3744 /* Get full mem size */
3745 p_buf = dhd_get_fwdump_buf(bus->dhd, size);
3746 if (!p_buf) {
3747 DHD_ERROR(("%s: Out of memory (%d bytes)\n",
3748 __FUNCTION__, size));
3749 return BCME_ERROR;
3750 }
3751
3752 dhd_os_sdlock(bus->dhd);
3753 BUS_WAKE(bus);
3754 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3755
3756 /* Read mem content */
3757 DHD_ERROR(("Dump dongle memory\n"));
3758 databuf = p_buf;
3759 while (size) {
3760 read_size = MIN(MEMBLOCK, size);
3761 ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size);
3762 if (ret) {
3763 DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret));
3764 ret = BCME_ERROR;
3765 break;
3766 }
3767 /* Decrement size and increment start address */
3768 size -= read_size;
3769 start += read_size;
3770 databuf += read_size;
3771 }
3772
3773 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
3774 NO_OTHER_ACTIVE_BUS_USER(bus)) {
3775 bus->activity = FALSE;
3776 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
3777 }
3778
3779 dhd_os_sdunlock(bus->dhd);
3780
3781 return ret;
3782 }
3783
3784 static int
dhdsdio_mem_dump(dhd_bus_t * bus)3785 dhdsdio_mem_dump(dhd_bus_t *bus)
3786 {
3787 dhd_pub_t *dhdp;
3788 int ret = BCME_ERROR;
3789
3790 dhdp = bus->dhd;
3791 if (!dhdp) {
3792 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3793 return ret;
3794 }
3795
3796 ret = dhdsdio_get_mem_dump(bus);
3797 if (ret) {
3798 DHD_ERROR(("%s: failed to get mem dump, err=%d\n",
3799 __FUNCTION__, ret));
3800 } else {
3801 /* schedule a work queue to perform actual memdump.
3802 * dhd_mem_dump() performs the job
3803 */
3804 dhd_schedule_memdump(dhdp, dhdp->soc_ram, dhdp->soc_ram_length);
3805 /* soc_ram free handled in dhd_{free,clear} */
3806 }
3807
3808 return ret;
3809 }
3810 #endif /* DHD_FW_COREDUMP */
3811
3812 int
dhd_socram_dump(dhd_bus_t * bus)3813 dhd_socram_dump(dhd_bus_t * bus)
3814 {
3815 #if defined(DHD_FW_COREDUMP)
3816 return (dhdsdio_mem_dump(bus));
3817 #else
3818 return -1;
3819 #endif // endif
3820 }
3821
3822 int
dhdsdio_downloadvars(dhd_bus_t * bus,void * arg,int len)3823 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3824 {
3825 int bcmerror = BCME_OK;
3826
3827 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3828
3829 if (bus->dhd->up &&
3830 #ifdef DHD_ULP
3831 (DHD_ULP_DISABLED == dhd_ulp_get_ulp_state(bus->dhd)) &&
3832 #endif /* DHD_ULP */
3833 1) {
3834 bcmerror = BCME_NOTDOWN;
3835 goto err;
3836 }
3837 if (!len) {
3838 bcmerror = BCME_BUFTOOSHORT;
3839 goto err;
3840 }
3841
3842 /* Free the old ones and replace with passed variables */
3843 if (bus->vars)
3844 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3845
3846 bus->vars = MALLOC(bus->dhd->osh, len);
3847 bus->varsz = bus->vars ? len : 0;
3848 if (bus->vars == NULL) {
3849 bcmerror = BCME_NOMEM;
3850 goto err;
3851 }
3852
3853 /* Copy the passed variables, which should include the terminating double-null */
3854 bcopy(arg, bus->vars, bus->varsz);
3855 err:
3856 return bcmerror;
3857 }
3858
3859 #ifdef DHD_DEBUG
3860 static int
dhd_serialconsole(dhd_bus_t * bus,bool set,bool enable,int * bcmerror)3861 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3862 {
3863 int int_val;
3864 uint32 addr, data, uart_enab = 0;
3865
3866 addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
3867 data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
3868 *bcmerror = 0;
3869
3870 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3871 if (bcmsdh_regfail(bus->sdh)) {
3872 *bcmerror = BCME_SDIO_ERROR;
3873 return -1;
3874 }
3875 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3876 if (bcmsdh_regfail(bus->sdh)) {
3877 *bcmerror = BCME_SDIO_ERROR;
3878 return -1;
3879 }
3880
3881 if (!set)
3882 return (int_val & uart_enab);
3883 if (enable)
3884 int_val |= uart_enab;
3885 else
3886 int_val &= ~uart_enab;
3887 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3888 if (bcmsdh_regfail(bus->sdh)) {
3889 *bcmerror = BCME_SDIO_ERROR;
3890 return -1;
3891 }
3892
3893 return (int_val & uart_enab);
3894 }
3895 #endif // endif
3896
3897 static int
dhdsdio_doiovar(dhd_bus_t * bus,const bcm_iovar_t * vi,uint32 actionid,const char * name,void * params,int plen,void * arg,int len,int val_size)3898 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3899 void *params, int plen, void *arg, int len, int val_size)
3900 {
3901 int bcmerror = 0;
3902 int32 int_val = 0;
3903 bool bool_val = 0;
3904
3905 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3906 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3907
3908 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3909 goto exit;
3910
3911 if (plen >= (int)sizeof(int_val))
3912 bcopy(params, &int_val, sizeof(int_val));
3913
3914 bool_val = (int_val != 0) ? TRUE : FALSE;
3915
3916 /* Some ioctls use the bus */
3917 dhd_os_sdlock(bus->dhd);
3918
3919 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3920 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3921 actionid == IOV_GVAL(IOV_DEVRESET))) {
3922 bcmerror = BCME_NOTREADY;
3923 goto exit;
3924 }
3925
3926 /*
3927 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3928 */
3929 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3930 dhdsdio_clk_kso_iovar(bus, bool_val);
3931 goto exit;
3932 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3933 {
3934 dhdsdio_clk_devsleep_iovar(bus, bool_val);
3935 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3936 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3937 bus->dpc_sched));
3938 if (!bus->dpc_sched) {
3939 bus->dpc_sched = TRUE;
3940 dhd_sched_dpc(bus->dhd);
3941 }
3942 }
3943 }
3944 goto exit;
3945 }
3946
3947 /* Handle sleep stuff before any clock mucking */
3948 if (vi->varid == IOV_SLEEP) {
3949 if (IOV_ISSET(actionid)) {
3950 bcmerror = dhdsdio_bussleep(bus, bool_val);
3951 } else {
3952 int_val = (int32)bus->sleeping;
3953 bcopy(&int_val, arg, val_size);
3954 }
3955 goto exit;
3956 }
3957
3958 /* Request clock to allow SDIO accesses */
3959 if (!bus->dhd->dongle_reset) {
3960 BUS_WAKE(bus);
3961 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3962 }
3963
3964 switch (actionid) {
3965 case IOV_GVAL(IOV_INTR):
3966 int_val = (int32)bus->intr;
3967 bcopy(&int_val, arg, val_size);
3968 break;
3969
3970 case IOV_SVAL(IOV_INTR):
3971 bus->intr = bool_val;
3972 bus->intdis = FALSE;
3973 if (bus->dhd->up) {
3974 if (bus->intr) {
3975 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3976 // terence 20141207: enbale intdis
3977 bus->intdis = TRUE;
3978 bcmsdh_intr_enable(bus->sdh);
3979 } else {
3980 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3981 bcmsdh_intr_disable(bus->sdh);
3982 }
3983 }
3984 break;
3985
3986 case IOV_GVAL(IOV_POLLRATE):
3987 int_val = (int32)bus->pollrate;
3988 bcopy(&int_val, arg, val_size);
3989 break;
3990
3991 case IOV_SVAL(IOV_POLLRATE):
3992 bus->pollrate = (uint)int_val;
3993 bus->poll = (bus->pollrate != 0);
3994 break;
3995
3996 case IOV_GVAL(IOV_IDLETIME):
3997 int_val = bus->idletime;
3998 bcopy(&int_val, arg, val_size);
3999 break;
4000
4001 case IOV_SVAL(IOV_IDLETIME):
4002 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
4003 bcmerror = BCME_BADARG;
4004 } else {
4005 bus->idletime = int_val;
4006 }
4007 break;
4008
4009 case IOV_GVAL(IOV_IDLECLOCK):
4010 int_val = (int32)bus->idleclock;
4011 bcopy(&int_val, arg, val_size);
4012 break;
4013
4014 case IOV_SVAL(IOV_IDLECLOCK):
4015 bus->idleclock = int_val;
4016 break;
4017
4018 case IOV_GVAL(IOV_SD1IDLE):
4019 int_val = (int32)sd1idle;
4020 bcopy(&int_val, arg, val_size);
4021 break;
4022
4023 case IOV_SVAL(IOV_SD1IDLE):
4024 sd1idle = bool_val;
4025 break;
4026
4027 #ifdef DHD_DEBUG
4028 case IOV_GVAL(IOV_CHECKDIED):
4029 bcmerror = dhdsdio_checkdied(bus, arg, len);
4030 break;
4031 #endif /* DHD_DEBUG */
4032
4033 case IOV_GVAL(IOV_RAMSIZE):
4034 int_val = (int32)bus->ramsize;
4035 bcopy(&int_val, arg, val_size);
4036 break;
4037
4038 case IOV_GVAL(IOV_RAMSTART):
4039 int_val = (int32)bus->dongle_ram_base;
4040 bcopy(&int_val, arg, val_size);
4041 break;
4042
4043 case IOV_GVAL(IOV_SDIOD_DRIVE):
4044 int_val = (int32)dhd_sdiod_drive_strength;
4045 bcopy(&int_val, arg, val_size);
4046 break;
4047
4048 case IOV_SVAL(IOV_SDIOD_DRIVE):
4049 dhd_sdiod_drive_strength = int_val;
4050 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
4051 break;
4052
4053 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
4054 bcmerror = dhdsdio_download_state(bus, bool_val);
4055 break;
4056
4057 case IOV_SVAL(IOV_SOCRAM_STATE):
4058 bcmerror = dhdsdio_download_state(bus, bool_val);
4059 break;
4060
4061 case IOV_SVAL(IOV_VARS):
4062 bcmerror = dhdsdio_downloadvars(bus, arg, len);
4063 break;
4064
4065 case IOV_GVAL(IOV_READAHEAD):
4066 int_val = (int32)dhd_readahead;
4067 bcopy(&int_val, arg, val_size);
4068 break;
4069
4070 case IOV_SVAL(IOV_READAHEAD):
4071 if (bool_val && !dhd_readahead)
4072 bus->nextlen = 0;
4073 dhd_readahead = bool_val;
4074 break;
4075
4076 case IOV_GVAL(IOV_SDRXCHAIN):
4077 int_val = (int32)bus->use_rxchain;
4078 bcopy(&int_val, arg, val_size);
4079 break;
4080
4081 case IOV_SVAL(IOV_SDRXCHAIN):
4082 if (bool_val && !bus->sd_rxchain)
4083 bcmerror = BCME_UNSUPPORTED;
4084 else
4085 bus->use_rxchain = bool_val;
4086 break;
4087 #ifndef BCMSPI
4088 case IOV_GVAL(IOV_ALIGNCTL):
4089 int_val = (int32)dhd_alignctl;
4090 bcopy(&int_val, arg, val_size);
4091 break;
4092
4093 case IOV_SVAL(IOV_ALIGNCTL):
4094 dhd_alignctl = bool_val;
4095 break;
4096 #endif /* BCMSPI */
4097
4098 case IOV_GVAL(IOV_SDALIGN):
4099 int_val = DHD_SDALIGN;
4100 bcopy(&int_val, arg, val_size);
4101 break;
4102
4103 #ifdef DHD_DEBUG
4104 case IOV_GVAL(IOV_VARS):
4105 if (bus->varsz < (uint)len)
4106 bcopy(bus->vars, arg, bus->varsz);
4107 else
4108 bcmerror = BCME_BUFTOOSHORT;
4109 break;
4110 #endif /* DHD_DEBUG */
4111
4112 #ifdef DHD_DEBUG
4113 case IOV_GVAL(IOV_SDREG):
4114 {
4115 sdreg_t *sd_ptr;
4116 uintptr addr;
4117 uint size;
4118
4119 sd_ptr = (sdreg_t *)params;
4120
4121 addr = ((uintptr)bus->regs + sd_ptr->offset);
4122 size = sd_ptr->func;
4123 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
4124 if (bcmsdh_regfail(bus->sdh))
4125 bcmerror = BCME_SDIO_ERROR;
4126 bcopy(&int_val, arg, sizeof(int32));
4127 break;
4128 }
4129
4130 case IOV_SVAL(IOV_SDREG):
4131 {
4132 sdreg_t *sd_ptr;
4133 uintptr addr;
4134 uint size;
4135
4136 sd_ptr = (sdreg_t *)params;
4137
4138 addr = ((uintptr)bus->regs + sd_ptr->offset);
4139 size = sd_ptr->func;
4140 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
4141 if (bcmsdh_regfail(bus->sdh))
4142 bcmerror = BCME_SDIO_ERROR;
4143 break;
4144 }
4145
4146 /* Same as above, but offset is not backplane (not SDIO core) */
4147 case IOV_GVAL(IOV_SBREG):
4148 {
4149 sdreg_t sdreg;
4150 uint32 addr, size;
4151
4152 bcopy(params, &sdreg, sizeof(sdreg));
4153
4154 addr = SI_ENUM_BASE(bus->sih) + sdreg.offset;
4155 size = sdreg.func;
4156 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
4157 if (bcmsdh_regfail(bus->sdh))
4158 bcmerror = BCME_SDIO_ERROR;
4159 bcopy(&int_val, arg, sizeof(int32));
4160 break;
4161 }
4162
4163 case IOV_SVAL(IOV_SBREG):
4164 {
4165 sdreg_t sdreg;
4166 uint32 addr, size;
4167
4168 bcopy(params, &sdreg, sizeof(sdreg));
4169
4170 addr = SI_ENUM_BASE(bus->sih) + sdreg.offset;
4171 size = sdreg.func;
4172 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
4173 if (bcmsdh_regfail(bus->sdh))
4174 bcmerror = BCME_SDIO_ERROR;
4175 break;
4176 }
4177
4178 case IOV_GVAL(IOV_SDCIS):
4179 {
4180 *(char *)arg = 0;
4181
4182 bcmstrcat(arg, "\nFunc 0\n");
4183 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4184 bcmstrcat(arg, "\nFunc 1\n");
4185 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4186 bcmstrcat(arg, "\nFunc 2\n");
4187 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4188 break;
4189 }
4190
4191 case IOV_GVAL(IOV_FORCEEVEN):
4192 int_val = (int32)forcealign;
4193 bcopy(&int_val, arg, val_size);
4194 break;
4195
4196 case IOV_SVAL(IOV_FORCEEVEN):
4197 forcealign = bool_val;
4198 break;
4199
4200 case IOV_GVAL(IOV_TXBOUND):
4201 int_val = (int32)dhd_txbound;
4202 bcopy(&int_val, arg, val_size);
4203 break;
4204
4205 case IOV_SVAL(IOV_TXBOUND):
4206 dhd_txbound = (uint)int_val;
4207 break;
4208
4209 case IOV_GVAL(IOV_RXBOUND):
4210 int_val = (int32)dhd_rxbound;
4211 bcopy(&int_val, arg, val_size);
4212 break;
4213
4214 case IOV_SVAL(IOV_RXBOUND):
4215 dhd_rxbound = (uint)int_val;
4216 break;
4217
4218 case IOV_GVAL(IOV_TXMINMAX):
4219 int_val = (int32)dhd_txminmax;
4220 bcopy(&int_val, arg, val_size);
4221 break;
4222
4223 case IOV_SVAL(IOV_TXMINMAX):
4224 dhd_txminmax = (uint)int_val;
4225 break;
4226
4227 #ifdef DHD_DEBUG
4228 case IOV_GVAL(IOV_SERIALCONS):
4229 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
4230 if (bcmerror != 0)
4231 break;
4232
4233 bcopy(&int_val, arg, val_size);
4234 break;
4235
4236 case IOV_SVAL(IOV_SERIALCONS):
4237 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
4238 break;
4239 #endif /* DHD_DEBUG */
4240
4241 #endif /* DHD_DEBUG */
4242
4243 #ifdef SDTEST
4244 case IOV_GVAL(IOV_EXTLOOP):
4245 int_val = (int32)bus->ext_loop;
4246 bcopy(&int_val, arg, val_size);
4247 break;
4248
4249 case IOV_SVAL(IOV_EXTLOOP):
4250 bus->ext_loop = bool_val;
4251 break;
4252
4253 case IOV_GVAL(IOV_PKTGEN):
4254 bcmerror = dhdsdio_pktgen_get(bus, arg);
4255 break;
4256
4257 case IOV_SVAL(IOV_PKTGEN):
4258 bcmerror = dhdsdio_pktgen_set(bus, arg);
4259 break;
4260 #endif /* SDTEST */
4261
4262 #if defined(USE_SDIOFIFO_IOVAR)
4263 case IOV_GVAL(IOV_WATERMARK):
4264 int_val = (int32)watermark;
4265 bcopy(&int_val, arg, val_size);
4266 break;
4267
4268 case IOV_SVAL(IOV_WATERMARK):
4269 watermark = (uint)int_val;
4270 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
4271 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
4272 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
4273 break;
4274
4275 case IOV_GVAL(IOV_MESBUSYCTRL):
4276 int_val = (int32)mesbusyctrl;
4277 bcopy(&int_val, arg, val_size);
4278 break;
4279
4280 case IOV_SVAL(IOV_MESBUSYCTRL):
4281 mesbusyctrl = (uint)int_val;
4282 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
4283 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
4284 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
4285 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
4286 ((uint8)mesbusyctrl | 0x80), NULL);
4287 break;
4288 #endif // endif
4289
4290 case IOV_GVAL(IOV_DONGLEISOLATION):
4291 int_val = bus->dhd->dongle_isolation;
4292 bcopy(&int_val, arg, val_size);
4293 break;
4294
4295 case IOV_SVAL(IOV_DONGLEISOLATION):
4296 bus->dhd->dongle_isolation = bool_val;
4297 break;
4298
4299 case IOV_SVAL(IOV_DEVRESET):
4300 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
4301 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
4302 bus->dhd->busstate));
4303
4304 ASSERT(bus->dhd->osh);
4305 /* ASSERT(bus->cl_devid); */
4306
4307 /* must release sdlock, since devreset also acquires it */
4308 dhd_os_sdunlock(bus->dhd);
4309 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
4310 dhd_os_sdlock(bus->dhd);
4311 break;
4312 /*
4313 * softap firmware is updated through module parameter or android private command
4314 */
4315
4316 case IOV_GVAL(IOV_DEVRESET):
4317 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
4318
4319 /* Get its status */
4320 int_val = (bool) bus->dhd->dongle_reset;
4321 bcopy(&int_val, arg, val_size);
4322
4323 break;
4324
4325 case IOV_GVAL(IOV_KSO):
4326 int_val = dhdsdio_sleepcsr_get(bus);
4327 bcopy(&int_val, arg, val_size);
4328 break;
4329
4330 case IOV_GVAL(IOV_DEVCAP):
4331 int_val = dhdsdio_devcap_get(bus);
4332 bcopy(&int_val, arg, val_size);
4333 break;
4334
4335 case IOV_SVAL(IOV_DEVCAP):
4336 dhdsdio_devcap_set(bus, (uint8) int_val);
4337 break;
4338 case IOV_GVAL(IOV_TXGLOMSIZE):
4339 int_val = (int32)bus->txglomsize;
4340 bcopy(&int_val, arg, val_size);
4341 break;
4342
4343 case IOV_SVAL(IOV_TXGLOMSIZE):
4344 if (int_val > SDPCM_MAXGLOM_SIZE) {
4345 bcmerror = BCME_ERROR;
4346 } else {
4347 bus->txglomsize = (uint)int_val;
4348 }
4349 break;
4350 case IOV_SVAL(IOV_HANGREPORT):
4351 bus->dhd->hang_report = bool_val;
4352 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
4353 break;
4354
4355 case IOV_GVAL(IOV_HANGREPORT):
4356 int_val = (int32)bus->dhd->hang_report;
4357 bcopy(&int_val, arg, val_size);
4358 break;
4359
4360 case IOV_GVAL(IOV_TXINRX_THRES):
4361 int_val = bus->txinrx_thres;
4362 bcopy(&int_val, arg, val_size);
4363 break;
4364 case IOV_SVAL(IOV_TXINRX_THRES):
4365 if (int_val < 0) {
4366 bcmerror = BCME_BADARG;
4367 } else {
4368 bus->txinrx_thres = int_val;
4369 }
4370 break;
4371
4372 case IOV_GVAL(IOV_SDIO_SUSPEND):
4373 int_val = (bus->dhd->busstate == DHD_BUS_SUSPEND) ? 1 : 0;
4374 bcopy(&int_val, arg, val_size);
4375 break;
4376
4377 case IOV_SVAL(IOV_SDIO_SUSPEND):
4378 if (bool_val) { /* Suspend */
4379 dhdsdio_suspend(bus);
4380 }
4381 else { /* Resume */
4382 dhdsdio_resume(bus);
4383 }
4384 break;
4385
4386 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
4387 case IOV_SVAL(IOV_GDB_SERVER):
4388 if (bool_val == TRUE) {
4389 debugger_init((void *) bus, &bus_ops, int_val, SI_ENUM_BASE(bus->sih));
4390 } else {
4391 debugger_close();
4392 }
4393 break;
4394 #endif /* DEBUGGER || DHD_DSCOPE */
4395
4396 default:
4397 bcmerror = BCME_UNSUPPORTED;
4398 break;
4399 }
4400
4401 exit:
4402 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
4403 NO_OTHER_ACTIVE_BUS_USER(bus)) {
4404 bus->activity = FALSE;
4405 dhdsdio_bussleep(bus, TRUE);
4406 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4407 }
4408
4409 dhd_os_sdunlock(bus->dhd);
4410
4411 return bcmerror;
4412 }
4413
4414 static int
dhdsdio_write_vars(dhd_bus_t * bus)4415 dhdsdio_write_vars(dhd_bus_t *bus)
4416 {
4417 int bcmerror = 0;
4418 uint32 varsize, phys_size;
4419 uint32 varaddr;
4420 uint8 *vbuffer;
4421 uint32 varsizew;
4422 #ifdef DHD_DEBUG
4423 uint8 *nvram_ularray;
4424 #endif /* DHD_DEBUG */
4425
4426 /* Even if there are no vars are to be written, we still need to set the ramsize. */
4427 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
4428 varaddr = (bus->ramsize - 4) - varsize;
4429
4430 // terence 20150412: fix for nvram failed to download
4431 if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
4432 bus->dhd->conf->chip == BCM43341_CHIP_ID) {
4433 varsize = varsize ? ROUNDUP(varsize, 64) : 0;
4434 varaddr = (bus->ramsize - 64) - varsize;
4435 }
4436
4437 varaddr += bus->dongle_ram_base;
4438
4439 if (bus->vars) {
4440 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
4441 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
4442 DHD_ERROR(("PR85623WAR in place\n"));
4443 varsize += 4;
4444 varaddr -= 4;
4445 }
4446 }
4447
4448 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4449 if (!vbuffer)
4450 return BCME_NOMEM;
4451
4452 bzero(vbuffer, varsize);
4453 bcopy(bus->vars, vbuffer, bus->varsz);
4454
4455 /* Write the vars list */
4456 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
4457 if (bcmerror) {
4458 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
4459 __FUNCTION__, bcmerror, varsize, varaddr));
4460 return bcmerror;
4461 }
4462
4463 #ifdef DHD_DEBUG
4464 /* Verify NVRAM bytes */
4465 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
4466 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
4467 if (!nvram_ularray) {
4468 MFREE(bus->dhd->osh, vbuffer, varsize);
4469 return BCME_NOMEM;
4470 }
4471
4472 /* Upload image to verify downloaded contents. */
4473 memset(nvram_ularray, 0xaa, varsize);
4474
4475 /* Read the vars list to temp buffer for comparison */
4476 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
4477 if (bcmerror) {
4478 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4479 __FUNCTION__, bcmerror, varsize, varaddr));
4480 }
4481 /* Compare the org NVRAM with the one read from RAM */
4482 if (memcmp(vbuffer, nvram_ularray, varsize)) {
4483 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
4484 } else
4485 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4486 __FUNCTION__));
4487
4488 MFREE(bus->dhd->osh, nvram_ularray, varsize);
4489 #endif /* DHD_DEBUG */
4490
4491 MFREE(bus->dhd->osh, vbuffer, varsize);
4492 }
4493
4494 #ifdef MINIME
4495 phys_size = bus->ramsize;
4496 #else
4497 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
4498 #endif
4499
4500 phys_size += bus->dongle_ram_base;
4501
4502 /* adjust to the user specified RAM */
4503 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
4504 phys_size, bus->ramsize));
4505 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
4506 varaddr, varsize));
4507 varsize = ((phys_size - 4) - varaddr);
4508
4509 /*
4510 * Determine the length token:
4511 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4512 */
4513 #ifdef DHD_DEBUG
4514 if (bcmerror) {
4515 varsizew = 0;
4516 } else
4517 #endif /* DHD_DEBUG */
4518 {
4519 varsizew = varsize / 4;
4520 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
4521 varsizew = htol32(varsizew);
4522 }
4523
4524 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
4525
4526 /* Write the length token to the last word */
4527 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
4528 (uint8*)&varsizew, 4);
4529
4530 return bcmerror;
4531 }
4532
4533 bool
dhd_bus_is_multibp_capable(struct dhd_bus * bus)4534 dhd_bus_is_multibp_capable(struct dhd_bus *bus)
4535 {
4536 return MULTIBP_CAP(bus->sih);
4537 }
4538
4539 static int
dhdsdio_download_state(dhd_bus_t * bus,bool enter)4540 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
4541 {
4542 uint retries;
4543 int bcmerror = 0;
4544 int foundcr4 = 0;
4545
4546 if (!bus->sih)
4547 return BCME_ERROR;
4548 /* To enter download state, disable ARM and reset SOCRAM.
4549 * To exit download state, simply reset ARM (default is RAM boot).
4550 */
4551 if (enter) {
4552 bus->alp_only = TRUE;
4553
4554 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4555 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4556 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4557 foundcr4 = 1;
4558 } else {
4559 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4560 bcmerror = BCME_ERROR;
4561 goto fail;
4562 }
4563 }
4564
4565 if (!foundcr4) {
4566 si_core_disable(bus->sih, 0);
4567 if (bcmsdh_regfail(bus->sdh)) {
4568 bcmerror = BCME_SDIO_ERROR;
4569 goto fail;
4570 }
4571
4572 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4573 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4574 bcmerror = BCME_ERROR;
4575 goto fail;
4576 }
4577
4578 si_core_reset(bus->sih, 0, 0);
4579 if (bcmsdh_regfail(bus->sdh)) {
4580 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
4581 __FUNCTION__));
4582 bcmerror = BCME_SDIO_ERROR;
4583 goto fail;
4584 }
4585
4586 /* Disable remap for download */
4587 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
4588 dhdsdio_devram_remap(bus, FALSE);
4589
4590 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
4591 CHIPID(bus->sih->chip) == BCM43018_CHIP_ID) {
4592 /* Disabling Remap for SRAM_3 */
4593 si_socram_set_bankpda(bus->sih, 0x3, 0x0);
4594 }
4595
4596 /* Clear the top bit of memory */
4597 if (bus->ramsize) {
4598 uint32 zeros = 0;
4599 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
4600 (uint8*)&zeros, 4) < 0) {
4601 bcmerror = BCME_SDIO_ERROR;
4602 goto fail;
4603 }
4604 }
4605 } else {
4606 /* For CR4,
4607 * Halt ARM
4608 * Remove ARM reset
4609 * Read RAM base address [0x18_0000]
4610 * [next] Download firmware
4611 * [done at else] Populate the reset vector
4612 * [done at else] Remove ARM halt
4613 */
4614 /* Halt ARM & remove reset */
4615 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
4616 }
4617 } else {
4618 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4619 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4620 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4621 bcmerror = BCME_ERROR;
4622 goto fail;
4623 }
4624
4625 if (!si_iscoreup(bus->sih)) {
4626 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4627 bcmerror = BCME_ERROR;
4628 goto fail;
4629 }
4630
4631 if ((bcmerror = dhdsdio_write_vars(bus))) {
4632 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4633 goto fail;
4634 }
4635
4636 /* Enable remap before ARM reset but after vars.
4637 * No backplane access in remap mode
4638 */
4639 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4640 dhdsdio_devram_remap(bus, TRUE);
4641 #ifdef BCMSDIOLITE
4642 if (!si_setcore(bus->sih, CC_CORE_ID, 0)) {
4643 DHD_ERROR(("%s: Can't set to Chip Common core?\n", __FUNCTION__));
4644 bcmerror = BCME_ERROR;
4645 goto fail;
4646 }
4647 #else
4648 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4649 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4650 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4651 bcmerror = BCME_ERROR;
4652 goto fail;
4653 }
4654 #endif // endif
4655 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4656
4657 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4658 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4659 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4660 bcmerror = BCME_ERROR;
4661 goto fail;
4662 }
4663 } else {
4664 /* cr4 has no socram, but tcm's */
4665 /* write vars */
4666 if ((bcmerror = dhdsdio_write_vars(bus))) {
4667 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4668 goto fail;
4669 }
4670 #ifdef BCMSDIOLITE
4671 if (!si_setcore(bus->sih, CC_CORE_ID, 0)) {
4672 DHD_ERROR(("%s: Can't set to Chip Common core?\n", __FUNCTION__));
4673 bcmerror = BCME_ERROR;
4674 goto fail;
4675 }
4676 #else
4677 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4678 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4679 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4680 bcmerror = BCME_ERROR;
4681 goto fail;
4682 }
4683 #endif // endif
4684 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4685
4686 /* switch back to arm core again */
4687 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4688 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4689 bcmerror = BCME_ERROR;
4690 goto fail;
4691 }
4692 /* write address 0 with reset instruction */
4693 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4694 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4695
4696 if (bcmerror == BCME_OK) {
4697 uint32 tmp;
4698
4699 /* verify write */
4700 bcmerror = dhdsdio_membytes(bus, FALSE, 0,
4701 (uint8 *)&tmp, sizeof(tmp));
4702
4703 if (bcmerror == BCME_OK && tmp != bus->resetinstr) {
4704 DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n",
4705 __FUNCTION__, bus->resetinstr));
4706 DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n",
4707 __FUNCTION__, tmp));
4708 bcmerror = BCME_SDIO_ERROR;
4709 goto fail;
4710 }
4711 }
4712
4713 /* now remove reset and halt and continue to run CR4 */
4714 }
4715
4716 si_core_reset(bus->sih, 0, 0);
4717 if (bcmsdh_regfail(bus->sdh)) {
4718 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4719 bcmerror = BCME_SDIO_ERROR;
4720 goto fail;
4721 }
4722
4723 /* Allow HT Clock now that the ARM is running. */
4724 bus->alp_only = FALSE;
4725
4726 bus->dhd->busstate = DHD_BUS_LOAD;
4727 }
4728
4729 fail:
4730 /* Always return to SDIOD core */
4731 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4732 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4733
4734 return bcmerror;
4735 }
4736
4737 int
dhd_bus_iovar_op(dhd_pub_t * dhdp,const char * name,void * params,int plen,void * arg,int len,bool set)4738 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4739 void *params, int plen, void *arg, int len, bool set)
4740 {
4741 dhd_bus_t *bus = dhdp->bus;
4742 const bcm_iovar_t *vi = NULL;
4743 int bcmerror = 0;
4744 int val_size;
4745 uint32 actionid;
4746
4747 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4748
4749 ASSERT(name);
4750 ASSERT(len >= 0);
4751
4752 /* Get MUST have return space */
4753 ASSERT(set || (arg && len));
4754
4755 /* Set does NOT take qualifiers */
4756 ASSERT(!set || (!params && !plen));
4757
4758 /* Look up var locally; if not found pass to host driver */
4759 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4760 dhd_os_sdlock(bus->dhd);
4761
4762 BUS_WAKE(bus);
4763
4764 /* Turn on clock in case SD command needs backplane */
4765 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4766
4767 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4768
4769 /* Check for bus configuration changes of interest */
4770
4771 /* If it was divisor change, read the new one */
4772 if (set && strcmp(name, "sd_divisor") == 0) {
4773 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4774 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4775 bus->sd_divisor = -1;
4776 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4777 } else {
4778 DHD_INFO(("%s: noted %s update, value now %d\n",
4779 __FUNCTION__, name, bus->sd_divisor));
4780 }
4781 }
4782 /* If it was a mode change, read the new one */
4783 if (set && strcmp(name, "sd_mode") == 0) {
4784 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4785 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4786 bus->sd_mode = -1;
4787 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4788 } else {
4789 DHD_INFO(("%s: noted %s update, value now %d\n",
4790 __FUNCTION__, name, bus->sd_mode));
4791 }
4792 }
4793 /* Similar check for blocksize change */
4794 if (set && strcmp(name, "sd_blocksize") == 0) {
4795 int32 fnum = 2;
4796 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4797 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4798 bus->blocksize = 0;
4799 DHD_ERROR(("%s: fail on fn %d %s get\n",
4800 __FUNCTION__, fnum, "sd_blocksize"));
4801 } else {
4802 DHD_INFO(("%s: noted fn %d %s update, value now %d\n",
4803 __FUNCTION__, fnum, "sd_blocksize", bus->blocksize));
4804
4805 dhdsdio_tune_fifoparam(bus);
4806 }
4807 }
4808 bus->roundup = MIN(max_roundup, bus->blocksize);
4809
4810 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
4811 NO_OTHER_ACTIVE_BUS_USER(bus)) {
4812 bus->activity = FALSE;
4813 dhdsdio_bussleep(bus, TRUE);
4814 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4815 }
4816
4817 dhd_os_sdunlock(bus->dhd);
4818 goto exit;
4819 }
4820
4821 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4822 name, (set ? "set" : "get"), len, plen));
4823
4824 /* set up 'params' pointer in case this is a set command so that
4825 * the convenience int and bool code can be common to set and get
4826 */
4827 if (params == NULL) {
4828 params = arg;
4829 plen = len;
4830 }
4831
4832 if (vi->type == IOVT_VOID)
4833 val_size = 0;
4834 else if (vi->type == IOVT_BUFFER)
4835 val_size = len;
4836 else
4837 /* all other types are integer sized */
4838 val_size = sizeof(int);
4839
4840 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4841 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4842
4843 exit:
4844 return bcmerror;
4845 }
4846
4847 void
dhd_bus_stop(struct dhd_bus * bus,bool enforce_mutex)4848 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4849 {
4850 osl_t *osh;
4851 uint32 local_hostintmask;
4852 uint8 saveclk;
4853 uint retries;
4854 int err;
4855 bool wlfc_enabled = FALSE;
4856 unsigned long flags;
4857
4858 if (!bus->dhd)
4859 return;
4860
4861 osh = bus->dhd->osh;
4862 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4863
4864 bcmsdh_waitlockfree(bus->sdh);
4865
4866 if (enforce_mutex)
4867 dhd_os_sdlock(bus->dhd);
4868
4869 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4870 /* if Firmware already hangs disbale any interrupt */
4871 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
4872 bus->dhd->busstate = DHD_BUS_DOWN;
4873 bus->hostintmask = 0;
4874 bcmsdh_intr_disable(bus->sdh);
4875 } else {
4876
4877 BUS_WAKE(bus);
4878
4879 if (KSO_ENAB(bus)) {
4880
4881 /* Enable clock for device interrupts */
4882 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4883
4884 /* Disable and clear interrupts at the chip level also */
4885 W_SDREG(0, &bus->regs->hostintmask, retries);
4886 local_hostintmask = bus->hostintmask;
4887 bus->hostintmask = 0;
4888
4889 /* Force clocks on backplane to be sure F2 interrupt propagates */
4890 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4891 if (!err) {
4892 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4893 (saveclk | SBSDIO_FORCE_HT), &err);
4894 }
4895 if (err) {
4896 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4897 __FUNCTION__, err));
4898 }
4899
4900 /* Turn off the bus (F2), free any pending packets */
4901 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4902 bcmsdh_intr_disable(bus->sdh);
4903 #ifndef BCMSPI
4904 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4905 #endif /* !BCMSPI */
4906
4907 /* Clear any pending interrupts now that F2 is disabled */
4908 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4909 }
4910
4911 /* Turn off the backplane clock (only) */
4912 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4913
4914 /* Change our idea of bus state */
4915 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
4916 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
4917 bus->dhd->busstate = DHD_BUS_DOWN;
4918 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
4919 }
4920
4921 #ifdef PROP_TXSTATUS
4922 wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED);
4923 #endif // endif
4924 if (!wlfc_enabled) {
4925 #ifdef DHDTCPACK_SUPPRESS
4926 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
4927 * when there is a newly coming packet from network stack.
4928 */
4929 dhd_tcpack_info_tbl_clean(bus->dhd);
4930 #endif /* DHDTCPACK_SUPPRESS */
4931 dhd_os_sdlock_txq(bus->dhd);
4932 /* Clear the data packet queues */
4933 pktq_flush(osh, &bus->txq, TRUE);
4934 dhd_os_sdunlock_txq(bus->dhd);
4935 }
4936
4937 /* Clear any held glomming stuff */
4938 if (bus->glomd)
4939 PKTFREE(osh, bus->glomd, FALSE);
4940
4941 if (bus->glom)
4942 PKTFREE(osh, bus->glom, FALSE);
4943
4944 bus->glom = bus->glomd = NULL;
4945
4946 /* Clear rx control and wake any waiters */
4947 bus->rxlen = 0;
4948 dhd_os_ioctl_resp_wake(bus->dhd);
4949
4950 /* Reset some F2 state stuff */
4951 bus->rxskip = FALSE;
4952 bus->tx_seq = bus->rx_seq = 0;
4953
4954 bus->tx_max = 4;
4955
4956 if (enforce_mutex)
4957 dhd_os_sdunlock(bus->dhd);
4958 }
4959
4960 #if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
4961 extern uint sd_txglom;
4962 #endif // endif
4963 void
dhd_txglom_enable(dhd_pub_t * dhdp,bool enable)4964 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4965 {
4966 /* can't enable host txglom by default, some platforms have no
4967 * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
4968 * panda board)
4969 */
4970 dhd_bus_t *bus = dhdp->bus;
4971 #ifdef BCMSDIOH_TXGLOM
4972 uint32 rxglom;
4973 int32 ret;
4974
4975 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4976
4977 #ifdef BCMSDIOH_STD
4978 if (enable)
4979 enable = sd_txglom;
4980 #endif /* BCMSDIOH_STD */
4981
4982 if (enable) {
4983 rxglom = 1;
4984 ret = dhd_iovar(dhdp, 0, "bus:rxglom", (char *)&rxglom, sizeof(rxglom), NULL, 0,
4985 TRUE);
4986 if (ret >= 0)
4987 bus->txglom_enable = TRUE;
4988 else {
4989 #ifdef BCMSDIOH_STD
4990 sd_txglom = 0;
4991 #endif /* BCMSDIOH_STD */
4992 bus->txglom_enable = FALSE;
4993 }
4994 } else
4995 #endif /* BCMSDIOH_TXGLOM */
4996 bus->txglom_enable = FALSE;
4997 printf("%s: enable %d\n", __FUNCTION__, bus->txglom_enable);
4998 dhd_conf_set_txglom_params(bus->dhd, bus->txglom_enable);
4999 bcmsdh_set_mode(bus->sdh, bus->dhd->conf->txglom_mode);
5000 }
5001
5002 int
dhd_bus_init(dhd_pub_t * dhdp,bool enforce_mutex)5003 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
5004 {
5005 dhd_bus_t *bus = dhdp->bus;
5006 dhd_timeout_t tmo;
5007 uint retries = 0;
5008 uint8 ready, enable;
5009 int err, ret = 0;
5010 #ifdef BCMSPI
5011 uint32 dstatus = 0; /* gSPI device-status bits */
5012 #else /* BCMSPI */
5013 uint8 saveclk;
5014 #endif /* BCMSPI */
5015 #if defined(SDIO_ISR_THREAD)
5016 int intr_extn;
5017 #endif
5018
5019 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5020
5021 ASSERT(bus->dhd);
5022 if (!bus->dhd)
5023 return 0;
5024
5025 if (enforce_mutex)
5026 dhd_os_sdlock(bus->dhd);
5027
5028 if (bus->sih->chip == BCM43362_CHIP_ID) {
5029 printf("%s: delay 100ms for BCM43362\n", __FUNCTION__);
5030 OSL_DELAY(100000); // terence 20131209: delay for 43362
5031 }
5032
5033 /* Make sure backplane clock is on, needed to generate F2 interrupt */
5034 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5035 if (bus->clkstate != CLK_AVAIL) {
5036 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
5037 ret = -1;
5038 goto exit;
5039 }
5040
5041 #ifdef BCMSPI
5042 /* fake "ready" for spi, wake-wlan would have already enabled F1 and F2 */
5043 ready = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
5044 enable = 0;
5045
5046 /* Give the dongle some time to do its thing and set IOR2 */
5047 dhd_timeout_start(&tmo, WAIT_F2RXFIFORDY * WAIT_F2RXFIFORDY_DELAY * 1000);
5048 while (!enable && !dhd_timeout_expired(&tmo)) {
5049 dstatus = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL);
5050 if (dstatus & STATUS_F2_RX_READY)
5051 enable = TRUE;
5052 }
5053
5054 if (enable) {
5055 DHD_ERROR(("Took %u usec before dongle is ready\n", tmo.elapsed));
5056 enable = ready;
5057 } else {
5058 DHD_ERROR(("dstatus when timed out on f2-fifo not ready = 0x%x\n", dstatus));
5059 DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo.elapsed));
5060 ret = -1;
5061 goto exit;
5062 }
5063
5064 #else /* !BCMSPI */
5065 /* Force clocks on backplane to be sure F2 interrupt propagates */
5066 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5067
5068 if (!err) {
5069 if (bus->sih->chip == BCM43012_CHIP_ID) {
5070 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5071 (saveclk | SBSDIO_HT_AVAIL_REQ), &err);
5072 } else {
5073 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5074 (saveclk | SBSDIO_FORCE_HT), &err);
5075 }
5076 }
5077
5078 if (err) {
5079 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
5080 ret = -1;
5081 goto exit;
5082 }
5083
5084 /* Enable function 2 (frame transfers) */
5085 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
5086 &bus->regs->tosbmailboxdata, retries);
5087 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
5088
5089 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
5090
5091 /* Give the dongle some time to do its thing and set IOR2 */
5092 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
5093
5094 ready = 0;
5095 while (ready != enable && !dhd_timeout_expired(&tmo))
5096 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
5097
5098 #endif /* !BCMSPI */
5099
5100 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
5101 __FUNCTION__, enable, ready, tmo.elapsed));
5102
5103 #if defined(SDIO_ISR_THREAD)
5104 if (dhdp->conf->intr_extn) {
5105 intr_extn = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTR_EXTN, NULL);
5106 if (intr_extn & 0x1) {
5107 intr_extn |= 0x2;
5108 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTR_EXTN, intr_extn, NULL);
5109 }
5110 }
5111 #endif
5112
5113 /* If F2 successfully enabled, set core and enable interrupts */
5114 if (ready == enable) {
5115 /* Make sure we're talking to the core. */
5116 #ifdef BCMSDIOLITE
5117 bus->regs = si_setcore(bus->sih, CC_CORE_ID, 0);
5118 ASSERT(bus->regs != NULL);
5119 #else
5120 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
5121 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
5122 ASSERT(bus->regs != NULL);
5123 #endif // endif
5124 /* Set up the interrupt mask and enable interrupts */
5125 bus->hostintmask = HOSTINTMASK;
5126 /* corerev 4 could use the newer interrupt logic to detect the frames */
5127 #ifndef BCMSPI
5128 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
5129 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
5130 bus->hostintmask &= ~I_HMB_FRAME_IND;
5131 bus->hostintmask |= I_XMTDATA_AVAIL;
5132 }
5133 #endif /* BCMSPI */
5134 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
5135
5136 if (bus->sih->buscorerev < 15) {
5137 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
5138 (uint8)watermark, &err);
5139 }
5140
5141 /* Set bus state according to enable result */
5142 dhdp->busstate = DHD_BUS_DATA;
5143
5144 /* Need to set fn2 block size to match fn1 block size.
5145 * Requests to fn2 go thru fn1. *
5146 * faltwig has this code contitioned with #if !BCMSPI_ANDROID.
5147 * It would be cleaner to use the ->sdh->block_sz[fno] instead of
5148 * 64, but this layer has no access to sdh types.
5149 */
5150
5151 /* bcmsdh_intr_unmask(bus->sdh); */
5152
5153 bus->intdis = FALSE;
5154 if (bus->intr) {
5155 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
5156 #ifndef BCMSPI_ANDROID
5157 bcmsdh_intr_enable(bus->sdh);
5158 #endif /* !BCMSPI_ANDROID */
5159 } else {
5160 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
5161 bcmsdh_intr_disable(bus->sdh);
5162 }
5163
5164 }
5165
5166 #ifndef BCMSPI
5167
5168 else {
5169 /* Disable F2 again */
5170 enable = SDIO_FUNC_ENABLE_1;
5171 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
5172 }
5173
5174 if (dhdsdio_sr_cap(bus)) {
5175 dhdsdio_sr_init(bus);
5176 /* Masking the chip active interrupt permanantly */
5177 bus->hostintmask &= ~I_CHIPACTIVE;
5178 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
5179 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
5180 __FUNCTION__, bus->hostintmask));
5181 } else {
5182 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
5183 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
5184 }
5185 #endif /* !BCMSPI */
5186
5187 /* If we didn't come up, turn off backplane clock */
5188 if (dhdp->busstate != DHD_BUS_DATA)
5189 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5190
5191 exit:
5192 if (enforce_mutex)
5193 dhd_os_sdunlock(bus->dhd);
5194
5195 return ret;
5196 }
5197
5198 static void
dhdsdio_rxfail(dhd_bus_t * bus,bool abort,bool rtx)5199 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
5200 {
5201 bcmsdh_info_t *sdh = bus->sdh;
5202 sdpcmd_regs_t *regs = bus->regs;
5203 uint retries = 0;
5204 uint16 lastrbc;
5205 uint8 hi, lo;
5206 int err;
5207
5208 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
5209 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
5210
5211 if (!KSO_ENAB(bus)) {
5212 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
5213 return;
5214 }
5215
5216 if (abort) {
5217 bcmsdh_abort(sdh, SDIO_FUNC_2);
5218 }
5219
5220 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
5221 if (err) {
5222 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
5223 goto fail;
5224 }
5225 bus->f1regdata++;
5226
5227 /* Wait until the packet has been flushed (device/FIFO stable) */
5228 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
5229 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
5230 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
5231 if (err) {
5232 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
5233 goto fail;
5234 }
5235
5236 bus->f1regdata += 2;
5237
5238 if ((hi == 0) && (lo == 0))
5239 break;
5240
5241 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
5242 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
5243 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
5244 }
5245 lastrbc = (hi << 8) + lo;
5246 }
5247
5248 if (!retries) {
5249 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
5250 } else {
5251 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
5252 }
5253
5254 if (rtx) {
5255 bus->rxrtx++;
5256 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
5257 bus->f1regdata++;
5258 if (retries <= retry_limit) {
5259 bus->rxskip = TRUE;
5260 }
5261 }
5262
5263 /* Clear partial in any case */
5264 bus->nextlen = 0;
5265
5266 fail:
5267 /* If we can't reach the device, signal failure */
5268 if (err || bcmsdh_regfail(sdh)) {
5269 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
5270 bus->dhd->busstate = DHD_BUS_DOWN;
5271 }
5272 }
5273
5274 static void
dhdsdio_read_control(dhd_bus_t * bus,uint8 * hdr,uint len,uint doff)5275 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
5276 {
5277 bcmsdh_info_t *sdh = bus->sdh;
5278 uint rdlen, pad;
5279
5280 int sdret;
5281
5282 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5283
5284 /* Control data already received in aligned rxctl */
5285 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
5286 goto gotpkt;
5287
5288 ASSERT(bus->rxbuf);
5289 /* Set rxctl for frame (w/optional alignment) */
5290 bus->rxctl = bus->rxbuf;
5291 if (dhd_alignctl) {
5292 bus->rxctl += firstread;
5293 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5294 bus->rxctl += (DHD_SDALIGN - pad);
5295 bus->rxctl -= firstread;
5296 }
5297 ASSERT(bus->rxctl >= bus->rxbuf);
5298
5299 /* Copy the already-read portion over */
5300 bcopy(hdr, bus->rxctl, firstread);
5301 if (len <= firstread)
5302 goto gotpkt;
5303
5304 /* Copy the full data pkt in gSPI case and process ioctl. */
5305 if (bus->bus == SPI_BUS) {
5306 bcopy(hdr, bus->rxctl, len);
5307 goto gotpkt;
5308 }
5309
5310 /* Raise rdlen to next SDIO block to avoid tail command */
5311 rdlen = len - firstread;
5312 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5313 pad = bus->blocksize - (rdlen % bus->blocksize);
5314 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5315 ((len + pad) < bus->dhd->maxctl))
5316 rdlen += pad;
5317 } else if (rdlen % DHD_SDALIGN) {
5318 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5319 }
5320
5321 /* Satisfy length-alignment requirements */
5322 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5323 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5324
5325 /* Drop if the read is too big or it exceeds our maximum */
5326 if ((rdlen + firstread) > bus->dhd->maxctl) {
5327 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
5328 __FUNCTION__, rdlen, bus->dhd->maxctl));
5329 bus->dhd->rx_errors++;
5330 dhdsdio_rxfail(bus, FALSE, FALSE);
5331 goto done;
5332 }
5333
5334 if ((len - doff) > bus->dhd->maxctl) {
5335 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
5336 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
5337 bus->dhd->rx_errors++; bus->rx_toolong++;
5338 dhdsdio_rxfail(bus, FALSE, FALSE);
5339 goto done;
5340 }
5341
5342 /* Read remainder of frame body into the rxctl buffer */
5343 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5344 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
5345 bus->f2rxdata++;
5346 ASSERT(sdret != BCME_PENDING);
5347
5348 /* Control frame failures need retransmission */
5349 if (sdret < 0) {
5350 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
5351 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
5352 dhdsdio_rxfail(bus, TRUE, TRUE);
5353 goto done;
5354 }
5355
5356 gotpkt:
5357
5358 #ifdef DHD_DEBUG
5359 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
5360 prhex("RxCtrl", bus->rxctl, len);
5361 }
5362 #endif // endif
5363
5364 /* Point to valid data and indicate its length */
5365 bus->rxctl += doff;
5366 bus->rxlen = len - doff;
5367
5368 done:
5369 /* Awake any waiters */
5370 dhd_os_ioctl_resp_wake(bus->dhd);
5371 }
5372 int
5373 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
5374 void **pkt, uint32 *pkt_count);
5375
5376 static uint8
dhdsdio_rxglom(dhd_bus_t * bus,uint8 rxseq)5377 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
5378 {
5379 uint16 dlen, totlen;
5380 uint8 *dptr, num = 0;
5381
5382 uint16 sublen, check;
5383 void *pfirst, *plast, *pnext;
5384 void * list_tail[DHD_MAX_IFS] = { NULL };
5385 void * list_head[DHD_MAX_IFS] = { NULL };
5386 uint8 idx;
5387 osl_t *osh = bus->dhd->osh;
5388
5389 int errcode;
5390 uint8 chan, seq, doff, sfdoff;
5391 uint8 txmax;
5392 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5393 uint reorder_info_len;
5394
5395 int ifidx = 0;
5396 bool usechain = bus->use_rxchain;
5397
5398 /* If packets, issue read(s) and send up packet chain */
5399 /* Return sequence numbers consumed? */
5400
5401 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
5402
5403 /* If there's a descriptor, generate the packet chain */
5404 if (bus->glomd) {
5405 dhd_os_sdlock_rxq(bus->dhd);
5406
5407 pfirst = plast = pnext = NULL;
5408 dlen = (uint16)PKTLEN(osh, bus->glomd);
5409 dptr = PKTDATA(osh, bus->glomd);
5410 if (!dlen || (dlen & 1)) {
5411 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
5412 __FUNCTION__, dlen));
5413 dlen = 0;
5414 }
5415
5416 for (totlen = num = 0; dlen; num++) {
5417 /* Get (and move past) next length */
5418 sublen = ltoh16_ua(dptr);
5419 dlen -= sizeof(uint16);
5420 dptr += sizeof(uint16);
5421 if ((sublen < SDPCM_HDRLEN) ||
5422 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
5423 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
5424 __FUNCTION__, num, sublen));
5425 pnext = NULL;
5426 break;
5427 }
5428 if (sublen % DHD_SDALIGN) {
5429 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
5430 __FUNCTION__, sublen, DHD_SDALIGN));
5431 usechain = FALSE;
5432 }
5433 totlen += sublen;
5434
5435 /* For last frame, adjust read len so total is a block multiple */
5436 if (!dlen) {
5437 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
5438 totlen = ROUNDUP(totlen, bus->blocksize);
5439 }
5440
5441 /* Allocate/chain packet for next subframe */
5442 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
5443 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
5444 __FUNCTION__, num, sublen));
5445 break;
5446 }
5447 ASSERT(!PKTLINK(pnext));
5448 if (!pfirst) {
5449 ASSERT(!plast);
5450 pfirst = plast = pnext;
5451 } else {
5452 ASSERT(plast);
5453 PKTSETNEXT(osh, plast, pnext);
5454 plast = pnext;
5455 }
5456
5457 /* Adhere to start alignment requirements */
5458 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
5459 }
5460
5461 /* If all allocations succeeded, save packet chain in bus structure */
5462 if (pnext) {
5463 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
5464 __FUNCTION__, totlen, num));
5465 if (DHD_GLOM_ON() && bus->nextlen) {
5466 if (totlen != bus->nextlen) {
5467 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
5468 "rxseq %d\n", __FUNCTION__, bus->nextlen,
5469 totlen, rxseq));
5470 }
5471 }
5472 bus->glom = pfirst;
5473 pfirst = pnext = NULL;
5474 } else {
5475 if (pfirst)
5476 PKTFREE(osh, pfirst, FALSE);
5477 bus->glom = NULL;
5478 num = 0;
5479 }
5480
5481 /* Done with descriptor packet */
5482 PKTFREE(osh, bus->glomd, FALSE);
5483 bus->glomd = NULL;
5484 bus->nextlen = 0;
5485
5486 dhd_os_sdunlock_rxq(bus->dhd);
5487 }
5488
5489 /* Ok -- either we just generated a packet chain, or had one from before */
5490 if (bus->glom) {
5491 if (DHD_GLOM_ON()) {
5492 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
5493 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
5494 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
5495 pnext, (uint8*)PKTDATA(osh, pnext),
5496 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
5497 }
5498 }
5499
5500 pfirst = bus->glom;
5501 dlen = (uint16)pkttotlen(osh, pfirst);
5502
5503 /* Do an SDIO read for the superframe. Configurable iovar to
5504 * read directly into the chained packet, or allocate a large
5505 * packet and and copy into the chain.
5506 */
5507 if (usechain) {
5508 errcode = dhd_bcmsdh_recv_buf(bus,
5509 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5510 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
5511 dlen, pfirst, NULL, NULL);
5512 } else if (bus->dataptr) {
5513 errcode = dhd_bcmsdh_recv_buf(bus,
5514 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5515 F2SYNC, bus->dataptr,
5516 dlen, NULL, NULL, NULL);
5517 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
5518 if (sublen != dlen) {
5519 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
5520 __FUNCTION__, dlen, sublen));
5521 errcode = -1;
5522 }
5523 pnext = NULL;
5524 BCM_REFERENCE(pnext);
5525 } else {
5526 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
5527 errcode = -1;
5528 }
5529 bus->f2rxdata++;
5530 ASSERT(errcode != BCME_PENDING);
5531
5532 /* On failure, kill the superframe, allow a couple retries */
5533 if (errcode < 0) {
5534 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
5535 __FUNCTION__, dlen, errcode));
5536 bus->dhd->rx_errors++;
5537
5538 if (bus->glomerr++ < 3) {
5539 dhdsdio_rxfail(bus, TRUE, TRUE);
5540 } else {
5541 bus->glomerr = 0;
5542 dhdsdio_rxfail(bus, TRUE, FALSE);
5543 dhd_os_sdlock_rxq(bus->dhd);
5544 PKTFREE(osh, bus->glom, FALSE);
5545 dhd_os_sdunlock_rxq(bus->dhd);
5546 bus->rxglomfail++;
5547 bus->glom = NULL;
5548 }
5549 return 0;
5550 }
5551
5552 #ifdef DHD_DEBUG
5553 if (DHD_GLOM_ON()) {
5554 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
5555 MIN(PKTLEN(osh, pfirst), 48));
5556 }
5557 #endif // endif
5558
5559 /* Validate the superframe header */
5560 dptr = (uint8 *)PKTDATA(osh, pfirst);
5561 sublen = ltoh16_ua(dptr);
5562 check = ltoh16_ua(dptr + sizeof(uint16));
5563
5564 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5565 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5566 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5567 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5568 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
5569 __FUNCTION__, bus->nextlen, seq));
5570 bus->nextlen = 0;
5571 }
5572 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5573 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5574
5575 errcode = 0;
5576 if ((uint16)~(sublen^check)) {
5577 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
5578 __FUNCTION__, sublen, check));
5579 errcode = -1;
5580 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
5581 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
5582 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
5583 errcode = -1;
5584 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
5585 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
5586 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
5587 errcode = -1;
5588 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
5589 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
5590 errcode = -1;
5591 } else if ((doff < SDPCM_HDRLEN) ||
5592 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
5593 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
5594 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
5595 SDPCM_HDRLEN));
5596 errcode = -1;
5597 }
5598
5599 /* Check sequence number of superframe SW header */
5600 if (rxseq != seq) {
5601 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
5602 __FUNCTION__, seq, rxseq));
5603 bus->rx_badseq++;
5604 rxseq = seq;
5605 }
5606
5607 /* Check window for sanity */
5608 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5609 DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n",
5610 __FUNCTION__, txmax, bus->tx_seq));
5611 txmax = bus->tx_max;
5612 }
5613 bus->tx_max = txmax;
5614
5615 /* Remove superframe header, remember offset */
5616 PKTPULL(osh, pfirst, doff);
5617 sfdoff = doff;
5618
5619 /* Validate all the subframe headers */
5620 for (num = 0, pnext = pfirst; pnext && !errcode;
5621 num++, pnext = PKTNEXT(osh, pnext)) {
5622 dptr = (uint8 *)PKTDATA(osh, pnext);
5623 dlen = (uint16)PKTLEN(osh, pnext);
5624 sublen = ltoh16_ua(dptr);
5625 check = ltoh16_ua(dptr + sizeof(uint16));
5626 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5627 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5628 #ifdef DHD_DEBUG
5629 if (DHD_GLOM_ON()) {
5630 prhex("subframe", dptr, 32);
5631 }
5632 #endif // endif
5633
5634 if ((uint16)~(sublen^check)) {
5635 DHD_ERROR(("%s (subframe %d): HW hdr error: "
5636 "len/check 0x%04x/0x%04x\n",
5637 __FUNCTION__, num, sublen, check));
5638 errcode = -1;
5639 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
5640 DHD_ERROR(("%s (subframe %d): length mismatch: "
5641 "len 0x%04x, expect 0x%04x\n",
5642 __FUNCTION__, num, sublen, dlen));
5643 errcode = -1;
5644 } else if ((chan != SDPCM_DATA_CHANNEL) &&
5645 (chan != SDPCM_EVENT_CHANNEL)) {
5646 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
5647 __FUNCTION__, num, chan));
5648 errcode = -1;
5649 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
5650 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
5651 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
5652 errcode = -1;
5653 }
5654 }
5655
5656 if (errcode) {
5657 /* Terminate frame on error, request a couple retries */
5658 if (bus->glomerr++ < 3) {
5659 /* Restore superframe header space */
5660 PKTPUSH(osh, pfirst, sfdoff);
5661 dhdsdio_rxfail(bus, TRUE, TRUE);
5662 } else {
5663 bus->glomerr = 0;
5664 dhdsdio_rxfail(bus, TRUE, FALSE);
5665 dhd_os_sdlock_rxq(bus->dhd);
5666 PKTFREE(osh, bus->glom, FALSE);
5667 dhd_os_sdunlock_rxq(bus->dhd);
5668 bus->rxglomfail++;
5669 bus->glom = NULL;
5670 }
5671 bus->nextlen = 0;
5672 return 0;
5673 }
5674
5675 /* Basic SD framing looks ok - process each packet (header) */
5676 bus->glom = NULL;
5677 plast = NULL;
5678
5679 dhd_os_sdlock_rxq(bus->dhd);
5680 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
5681 pnext = PKTNEXT(osh, pfirst);
5682 PKTSETNEXT(osh, pfirst, NULL);
5683
5684 dptr = (uint8 *)PKTDATA(osh, pfirst);
5685 sublen = ltoh16_ua(dptr);
5686 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5687 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5688 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5689
5690 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
5691 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
5692 PKTLEN(osh, pfirst), sublen, chan, seq));
5693
5694 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
5695
5696 if (rxseq != seq) {
5697 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
5698 __FUNCTION__, seq, rxseq));
5699 bus->rx_badseq++;
5700 rxseq = seq;
5701 }
5702
5703 #ifdef DHD_DEBUG
5704 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5705 prhex("Rx Subframe Data", dptr, dlen);
5706 }
5707 #endif // endif
5708
5709 PKTSETLEN(osh, pfirst, sublen);
5710 PKTPULL(osh, pfirst, doff);
5711
5712 reorder_info_len = sizeof(reorder_info_buf);
5713
5714 if (PKTLEN(osh, pfirst) == 0) {
5715 PKTFREE(bus->dhd->osh, pfirst, FALSE);
5716 continue;
5717 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
5718 &reorder_info_len) != 0) {
5719 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5720 bus->dhd->rx_errors++;
5721 PKTFREE(osh, pfirst, FALSE);
5722 continue;
5723 }
5724 if (reorder_info_len) {
5725 uint32 free_buf_count;
5726 void *ppfirst;
5727
5728 ppfirst = pfirst;
5729 /* Reordering info from the firmware */
5730 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
5731 reorder_info_len, &ppfirst, &free_buf_count);
5732
5733 if (free_buf_count == 0) {
5734 continue;
5735 } else {
5736 void *temp;
5737
5738 /* go to the end of the chain and attach the pnext there */
5739 temp = ppfirst;
5740 while (PKTNEXT(osh, temp) != NULL) {
5741 temp = PKTNEXT(osh, temp);
5742 }
5743 pfirst = temp;
5744 if (list_tail[ifidx] == NULL)
5745 list_head[ifidx] = ppfirst;
5746 else
5747 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5748 list_tail[ifidx] = pfirst;
5749 }
5750
5751 num += (uint8)free_buf_count;
5752 } else {
5753 /* this packet will go up, link back into chain and count it */
5754
5755 if (list_tail[ifidx] == NULL) {
5756 list_head[ifidx] = list_tail[ifidx] = pfirst;
5757 } else {
5758 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5759 list_tail[ifidx] = pfirst;
5760 }
5761 num++;
5762 }
5763 #ifdef DHD_DEBUG
5764 if (DHD_GLOM_ON()) {
5765 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5766 __FUNCTION__, num, pfirst,
5767 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5768 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5769 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5770 MIN(PKTLEN(osh, pfirst), 32));
5771 }
5772 #endif /* DHD_DEBUG */
5773 }
5774 dhd_os_sdunlock_rxq(bus->dhd);
5775
5776 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5777 if (list_head[idx]) {
5778 void *temp;
5779 uint8 cnt = 0;
5780 temp = list_head[idx];
5781 do {
5782 temp = PKTNEXT(osh, temp);
5783 cnt++;
5784 } while (temp);
5785 if (cnt) {
5786 dhd_os_sdunlock(bus->dhd);
5787 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5788 dhd_os_sdlock(bus->dhd);
5789 #if defined(SDIO_ISR_THREAD)
5790 /* terence 20150615: fix for below error due to bussleep in watchdog after dhd_os_sdunlock here,
5791 * so call BUS_WAKE to wake up bus again
5792 * dhd_bcmsdh_recv_buf: Device asleep
5793 * dhdsdio_readframes: RXHEADER FAILED: -40
5794 * dhdsdio_rxfail: abort command, terminate frame, send NAK
5795 */
5796 BUS_WAKE(bus);
5797 #endif
5798 }
5799 }
5800 }
5801 bus->rxglomframes++;
5802 bus->rxglompkts += num;
5803 }
5804 return num;
5805 }
5806
5807 /* Return TRUE if there may be more frames to read */
5808 static uint
dhdsdio_readframes(dhd_bus_t * bus,uint maxframes,bool * finished)5809 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5810 {
5811 osl_t *osh = bus->dhd->osh;
5812 bcmsdh_info_t *sdh = bus->sdh;
5813
5814 uint16 len, check; /* Extracted hardware header fields */
5815 uint8 chan, seq, doff; /* Extracted software header fields */
5816 uint8 fcbits; /* Extracted fcbits from software header */
5817 uint8 delta;
5818
5819 void *pkt; /* Packet for event or data frames */
5820 uint16 pad; /* Number of pad bytes to read */
5821 uint16 rdlen; /* Total number of bytes to read */
5822 uint8 rxseq; /* Next sequence number to expect */
5823 uint rxleft = 0; /* Remaining number of frames allowed */
5824 int sdret; /* Return code from bcmsdh calls */
5825 uint8 txmax; /* Maximum tx sequence offered */
5826 #ifdef BCMSPI
5827 uint32 dstatus = 0; /* gSPI device status bits of */
5828 #endif /* BCMSPI */
5829 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5830 uint8 *rxbuf;
5831 int ifidx = 0;
5832 uint rxcount = 0; /* Total frames read */
5833 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5834 uint reorder_info_len;
5835 uint pkt_count;
5836
5837 #if defined(DHD_DEBUG) || defined(SDTEST)
5838 bool sdtest = FALSE; /* To limit message spew from test mode */
5839 #endif // endif
5840
5841 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5842 bus->readframes = TRUE;
5843
5844 if (!KSO_ENAB(bus)) {
5845 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5846 bus->readframes = FALSE;
5847 return 0;
5848 }
5849
5850 ASSERT(maxframes);
5851
5852 #ifdef SDTEST
5853 /* Allow pktgen to override maxframes */
5854 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5855 maxframes = bus->pktgen_count;
5856 sdtest = TRUE;
5857 }
5858 #endif // endif
5859
5860 /* Not finished unless we encounter no more frames indication */
5861 *finished = FALSE;
5862
5863 #ifdef BCMSPI
5864 /* Get pktlen from gSPI device F0 reg. */
5865 if (bus->bus == SPI_BUS) {
5866 /* Peek in dstatus bits and find out size to do rx-read. */
5867 dstatus = bcmsdh_get_dstatus(bus->sdh);
5868 if (dstatus == 0)
5869 DHD_ERROR(("%s:ZERO spi dstatus, a case observed in PR61352 hit !!!\n",
5870 __FUNCTION__));
5871
5872 DHD_TRACE(("Device status from regread = 0x%x\n", dstatus));
5873 DHD_TRACE(("Device status from bit-reconstruction = 0x%x\n",
5874 bcmsdh_get_dstatus((void *)bus->sdh)));
5875
5876 if ((dstatus & STATUS_F2_PKT_AVAILABLE) && (((dstatus & STATUS_UNDERFLOW)) == 0)) {
5877 bus->nextlen = ((dstatus & STATUS_F2_PKT_LEN_MASK) >>
5878 STATUS_F2_PKT_LEN_SHIFT);
5879 /* '0' size with pkt-available interrupt is eqvt to 2048 bytes */
5880 bus->nextlen = (bus->nextlen == 0) ? SPI_MAX_PKT_LEN : bus->nextlen;
5881 if (bus->dwordmode)
5882 bus->nextlen = bus->nextlen << 2;
5883 DHD_TRACE(("Entering %s: length to be read from gSPI = %d\n",
5884 __FUNCTION__, bus->nextlen));
5885 } else {
5886 if (dstatus & STATUS_F2_PKT_AVAILABLE)
5887 DHD_ERROR(("Underflow during %s.\n", __FUNCTION__));
5888 else
5889 DHD_ERROR(("False pkt-available intr.\n"));
5890 *finished = TRUE;
5891 return (maxframes - rxleft);
5892 }
5893 }
5894 #endif /* BCMSPI */
5895
5896 for (rxseq = bus->rx_seq, rxleft = maxframes;
5897 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5898 rxseq++, rxleft--) {
5899 #ifdef DHDTCPACK_SUP_DBG
5900 if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) {
5901 if (bus->dotxinrx == FALSE)
5902 DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n",
5903 __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode));
5904 }
5905 #ifdef DEBUG_COUNTER
5906 else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) {
5907 tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++;
5908 }
5909 #endif /* DEBUG_COUNTER */
5910 #endif /* DHDTCPACK_SUP_DBG */
5911 /* tx more to improve rx performance */
5912 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5913 dhdsdio_sendpendctl(bus);
5914 } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
5915 !bus->fcstate && DATAOK(bus) &&
5916 (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) {
5917 dhdsdio_sendfromq(bus, dhd_txbound);
5918 #ifdef DHDTCPACK_SUPPRESS
5919 /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
5920 * 1. Any DATA packet to TX
5921 * 2. TCPACK to TCPDATA PSH packets.
5922 * in bus txq.
5923 */
5924 bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ?
5925 FALSE : TRUE;
5926 #endif // endif
5927 }
5928
5929 /* Handle glomming separately */
5930 if (bus->glom || bus->glomd) {
5931 uint8 cnt;
5932 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5933 __FUNCTION__, bus->glomd, bus->glom));
5934 cnt = dhdsdio_rxglom(bus, rxseq);
5935 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5936 rxseq += cnt - 1;
5937 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5938 continue;
5939 }
5940
5941 /* Try doing single read if we can */
5942 if (dhd_readahead && bus->nextlen) {
5943 uint16 nextlen = bus->nextlen;
5944 bus->nextlen = 0;
5945
5946 if (bus->bus == SPI_BUS) {
5947 rdlen = len = nextlen;
5948 } else {
5949 rdlen = len = nextlen << 4;
5950
5951 /* Pad read to blocksize for efficiency */
5952 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5953 pad = bus->blocksize - (rdlen % bus->blocksize);
5954 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5955 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5956 rdlen += pad;
5957 } else if (rdlen % DHD_SDALIGN) {
5958 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5959 }
5960 }
5961
5962 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5963 * Later we use buffer-poll for data as well as control packets.
5964 * This is required because dhd receives full frame in gSPI unlike SDIO.
5965 * After the frame is received we have to distinguish whether it is data
5966 * or non-data frame.
5967 */
5968 /* Allocate a packet buffer */
5969 dhd_os_sdlock_rxq(bus->dhd);
5970 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5971 if (bus->bus == SPI_BUS) {
5972 bus->usebufpool = FALSE;
5973 bus->rxctl = bus->rxbuf;
5974 if (dhd_alignctl) {
5975 bus->rxctl += firstread;
5976 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5977 bus->rxctl += (DHD_SDALIGN - pad);
5978 bus->rxctl -= firstread;
5979 }
5980 ASSERT(bus->rxctl >= bus->rxbuf);
5981 rxbuf = bus->rxctl;
5982 /* Read the entire frame */
5983 sdret = dhd_bcmsdh_recv_buf(bus,
5984 bcmsdh_cur_sbwad(sdh),
5985 SDIO_FUNC_2,
5986 F2SYNC, rxbuf, rdlen,
5987 NULL, NULL, NULL);
5988 bus->f2rxdata++;
5989 ASSERT(sdret != BCME_PENDING);
5990
5991 #ifdef BCMSPI
5992 if (bcmsdh_get_dstatus((void *)bus->sdh) &
5993 STATUS_UNDERFLOW) {
5994 bus->nextlen = 0;
5995 *finished = TRUE;
5996 DHD_ERROR(("%s: read %d control bytes failed "
5997 "due to spi underflow\n",
5998 __FUNCTION__, rdlen));
5999 /* dhd.rx_ctlerrs is higher level */
6000 bus->rxc_errors++;
6001 dhd_os_sdunlock_rxq(bus->dhd);
6002 continue;
6003 }
6004 #endif /* BCMSPI */
6005
6006 /* Control frame failures need retransmission */
6007 if (sdret < 0) {
6008 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
6009 __FUNCTION__, rdlen, sdret));
6010 /* dhd.rx_ctlerrs is higher level */
6011 bus->rxc_errors++;
6012 dhd_os_sdunlock_rxq(bus->dhd);
6013 dhdsdio_rxfail(bus, TRUE,
6014 (bus->bus == SPI_BUS) ? FALSE : TRUE);
6015 continue;
6016 }
6017 } else {
6018 /* Give up on data, request rtx of events */
6019 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
6020 "expected rxseq %d\n",
6021 __FUNCTION__, len, rdlen, rxseq));
6022 /* Just go try again w/normal header read */
6023 dhd_os_sdunlock_rxq(bus->dhd);
6024 continue;
6025 }
6026 } else {
6027 if (bus->bus == SPI_BUS)
6028 bus->usebufpool = TRUE;
6029
6030 ASSERT(!PKTLINK(pkt));
6031 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
6032 rxbuf = (uint8 *)PKTDATA(osh, pkt);
6033 /* Read the entire frame */
6034 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
6035 SDIO_FUNC_2,
6036 F2SYNC, rxbuf, rdlen,
6037 pkt, NULL, NULL);
6038 bus->f2rxdata++;
6039 ASSERT(sdret != BCME_PENDING);
6040 #ifdef BCMSPI
6041 if (bcmsdh_get_dstatus((void *)bus->sdh) & STATUS_UNDERFLOW) {
6042 bus->nextlen = 0;
6043 *finished = TRUE;
6044 DHD_ERROR(("%s (nextlen): read %d bytes failed due "
6045 "to spi underflow\n",
6046 __FUNCTION__, rdlen));
6047 PKTFREE(bus->dhd->osh, pkt, FALSE);
6048 bus->dhd->rx_errors++;
6049 dhd_os_sdunlock_rxq(bus->dhd);
6050 continue;
6051 }
6052 #endif /* BCMSPI */
6053
6054 if (sdret < 0) {
6055 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
6056 __FUNCTION__, rdlen, sdret));
6057 PKTFREE(bus->dhd->osh, pkt, FALSE);
6058 bus->dhd->rx_errors++;
6059 dhd_os_sdunlock_rxq(bus->dhd);
6060 /* Force retry w/normal header read. Don't attempt NAK for
6061 * gSPI
6062 */
6063 dhdsdio_rxfail(bus, TRUE,
6064 (bus->bus == SPI_BUS) ? FALSE : TRUE);
6065 continue;
6066 }
6067 }
6068 dhd_os_sdunlock_rxq(bus->dhd);
6069
6070 /* Now check the header */
6071 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
6072
6073 /* Extract hardware header fields */
6074 len = ltoh16_ua(bus->rxhdr);
6075 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
6076
6077 /* All zeros means readahead info was bad */
6078 if (!(len|check)) {
6079 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
6080 __FUNCTION__));
6081 dhd_os_sdlock_rxq(bus->dhd);
6082 PKTFREE2();
6083 dhd_os_sdunlock_rxq(bus->dhd);
6084 GSPI_PR55150_BAILOUT;
6085 continue;
6086 }
6087
6088 /* Validate check bytes */
6089 if ((uint16)~(len^check)) {
6090 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
6091 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
6092 len, check));
6093 dhd_os_sdlock_rxq(bus->dhd);
6094 PKTFREE2();
6095 dhd_os_sdunlock_rxq(bus->dhd);
6096 bus->rx_badhdr++;
6097 dhdsdio_rxfail(bus, FALSE, FALSE);
6098 GSPI_PR55150_BAILOUT;
6099 continue;
6100 }
6101
6102 /* Validate frame length */
6103 if (len < SDPCM_HDRLEN) {
6104 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
6105 __FUNCTION__, len));
6106 dhd_os_sdlock_rxq(bus->dhd);
6107 PKTFREE2();
6108 dhd_os_sdunlock_rxq(bus->dhd);
6109 GSPI_PR55150_BAILOUT;
6110 continue;
6111 }
6112
6113 /* Check for consistency with readahead info */
6114 #ifdef BCMSPI
6115 if (bus->bus == SPI_BUS) {
6116 if (bus->dwordmode) {
6117 uint16 spilen;
6118 spilen = ROUNDUP(len, 4);
6119 len_consistent = (nextlen != spilen);
6120 } else
6121 len_consistent = (nextlen != len);
6122 } else
6123 #endif /* BCMSPI */
6124 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
6125 if (len_consistent) {
6126 /* Mismatch, force retry w/normal header (may be >4K) */
6127 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
6128 "expected rxseq %d\n",
6129 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
6130 dhd_os_sdlock_rxq(bus->dhd);
6131 PKTFREE2();
6132 dhd_os_sdunlock_rxq(bus->dhd);
6133 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
6134 GSPI_PR55150_BAILOUT;
6135 continue;
6136 }
6137
6138 /* Extract software header fields */
6139 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6140 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6141 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6142 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6143
6144 #ifdef BCMSPI
6145 /* Save the readahead length if there is one */
6146 if (bus->bus == SPI_BUS) {
6147 /* Use reconstructed dstatus bits and find out readahead size */
6148 dstatus = bcmsdh_get_dstatus((void *)bus->sdh);
6149 DHD_INFO(("Device status from bit-reconstruction = 0x%x\n",
6150 bcmsdh_get_dstatus((void *)bus->sdh)));
6151 if (dstatus & STATUS_F2_PKT_AVAILABLE) {
6152 bus->nextlen = ((dstatus & STATUS_F2_PKT_LEN_MASK) >>
6153 STATUS_F2_PKT_LEN_SHIFT);
6154 bus->nextlen = (bus->nextlen == 0) ?
6155 SPI_MAX_PKT_LEN : bus->nextlen;
6156 if (bus->dwordmode)
6157 bus->nextlen = bus->nextlen << 2;
6158 DHD_INFO(("readahead len from gSPI = %d \n",
6159 bus->nextlen));
6160 bus->dhd->rx_readahead_cnt ++;
6161 } else {
6162 bus->nextlen = 0;
6163 *finished = TRUE;
6164 }
6165 } else {
6166 #endif /* BCMSPI */
6167 bus->nextlen =
6168 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6169 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
6170 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
6171 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
6172 seq));
6173 bus->nextlen = 0;
6174 }
6175
6176 bus->dhd->rx_readahead_cnt ++;
6177 #ifdef BCMSPI
6178 }
6179 #endif /* BCMSPI */
6180 /* Handle Flow Control */
6181 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6182
6183 delta = 0;
6184 if (~bus->flowcontrol & fcbits) {
6185 bus->fc_xoff++;
6186 delta = 1;
6187 }
6188 if (bus->flowcontrol & ~fcbits) {
6189 bus->fc_xon++;
6190 delta = 1;
6191 }
6192
6193 if (delta) {
6194 bus->fc_rcvd++;
6195 bus->flowcontrol = fcbits;
6196 }
6197
6198 /* Check and update sequence number */
6199 if (rxseq != seq) {
6200 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
6201 __FUNCTION__, seq, rxseq));
6202 bus->rx_badseq++;
6203 rxseq = seq;
6204 }
6205
6206 /* Check window for sanity */
6207 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6208 #ifdef BCMSPI
6209 if ((bus->bus == SPI_BUS) && !(dstatus & STATUS_F2_RX_READY)) {
6210 DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n",
6211 __FUNCTION__, txmax, bus->tx_seq));
6212 txmax = bus->tx_seq + 2;
6213 } else {
6214 #endif /* BCMSPI */
6215 DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n",
6216 __FUNCTION__, txmax, bus->tx_seq));
6217 txmax = bus->tx_max;
6218 #ifdef BCMSPI
6219 }
6220 #endif /* BCMSPI */
6221 }
6222 bus->tx_max = txmax;
6223
6224 #ifdef DHD_DEBUG
6225 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6226 prhex("Rx Data", rxbuf, len);
6227 } else if (DHD_HDRS_ON()) {
6228 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
6229 }
6230 #endif // endif
6231
6232 if (chan == SDPCM_CONTROL_CHANNEL) {
6233 if (bus->bus == SPI_BUS) {
6234 dhdsdio_read_control(bus, rxbuf, len, doff);
6235 if (bus->usebufpool) {
6236 dhd_os_sdlock_rxq(bus->dhd);
6237 PKTFREE(bus->dhd->osh, pkt, FALSE);
6238 dhd_os_sdunlock_rxq(bus->dhd);
6239 }
6240 continue;
6241 } else {
6242 DHD_ERROR(("%s (nextlen): readahead on control"
6243 " packet %d?\n", __FUNCTION__, seq));
6244 /* Force retry w/normal header read */
6245 bus->nextlen = 0;
6246 dhdsdio_rxfail(bus, FALSE, TRUE);
6247 dhd_os_sdlock_rxq(bus->dhd);
6248 PKTFREE2();
6249 dhd_os_sdunlock_rxq(bus->dhd);
6250 continue;
6251 }
6252 }
6253
6254 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
6255 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
6256 "rx pktbuf's or not yet malloced.\n", len, chan));
6257 continue;
6258 }
6259
6260 /* Validate data offset */
6261 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
6262 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
6263 __FUNCTION__, doff, len, SDPCM_HDRLEN));
6264 dhd_os_sdlock_rxq(bus->dhd);
6265 PKTFREE2();
6266 dhd_os_sdunlock_rxq(bus->dhd);
6267 ASSERT(0);
6268 dhdsdio_rxfail(bus, FALSE, FALSE);
6269 continue;
6270 }
6271
6272 /* All done with this one -- now deliver the packet */
6273 goto deliver;
6274 }
6275 /* gSPI frames should not be handled in fractions */
6276 if (bus->bus == SPI_BUS) {
6277 break;
6278 }
6279
6280 /* Read frame header (hardware and software) */
6281 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
6282 bus->rxhdr, firstread, NULL, NULL, NULL);
6283 bus->f2rxhdrs++;
6284 ASSERT(sdret != BCME_PENDING);
6285
6286 if (sdret < 0) {
6287 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
6288 bus->rx_hdrfail++;
6289 dhdsdio_rxfail(bus, TRUE, TRUE);
6290 continue;
6291 }
6292
6293 #ifdef DHD_DEBUG
6294 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
6295 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
6296 }
6297 #endif // endif
6298
6299 /* Extract hardware header fields */
6300 len = ltoh16_ua(bus->rxhdr);
6301 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
6302
6303 /* All zeros means no more frames */
6304 if (!(len|check)) {
6305 *finished = TRUE;
6306 break;
6307 }
6308
6309 /* Validate check bytes */
6310 if ((uint16)~(len^check)) {
6311 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
6312 __FUNCTION__, len, check));
6313 bus->rx_badhdr++;
6314 dhdsdio_rxfail(bus, FALSE, FALSE);
6315 continue;
6316 }
6317
6318 /* Validate frame length */
6319 if (len < SDPCM_HDRLEN) {
6320 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
6321 continue;
6322 }
6323
6324 /* Extract software header fields */
6325 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6326 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6327 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6328 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6329
6330 /* Validate data offset */
6331 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
6332 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
6333 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
6334 bus->rx_badhdr++;
6335 ASSERT(0);
6336 dhdsdio_rxfail(bus, FALSE, FALSE);
6337 continue;
6338 }
6339
6340 /* Save the readahead length if there is one */
6341 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6342 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
6343 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
6344 __FUNCTION__, bus->nextlen, seq));
6345 bus->nextlen = 0;
6346 }
6347
6348 /* Handle Flow Control */
6349 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6350
6351 delta = 0;
6352 if (~bus->flowcontrol & fcbits) {
6353 bus->fc_xoff++;
6354 delta = 1;
6355 }
6356 if (bus->flowcontrol & ~fcbits) {
6357 bus->fc_xon++;
6358 delta = 1;
6359 }
6360
6361 if (delta) {
6362 bus->fc_rcvd++;
6363 bus->flowcontrol = fcbits;
6364 }
6365
6366 /* Check and update sequence number */
6367 if (rxseq != seq) {
6368 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
6369 bus->rx_badseq++;
6370 rxseq = seq;
6371 }
6372
6373 /* Check window for sanity */
6374 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6375 DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n",
6376 __FUNCTION__, txmax, bus->tx_seq));
6377 txmax = bus->tx_max;
6378 }
6379 bus->tx_max = txmax;
6380
6381 /* Call a separate function for control frames */
6382 if (chan == SDPCM_CONTROL_CHANNEL) {
6383 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
6384 continue;
6385 }
6386
6387 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
6388 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
6389
6390 /* Length to read */
6391 rdlen = (len > firstread) ? (len - firstread) : 0;
6392
6393 /* May pad read to blocksize for efficiency */
6394 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
6395 pad = bus->blocksize - (rdlen % bus->blocksize);
6396 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
6397 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
6398 rdlen += pad;
6399 } else if (rdlen % DHD_SDALIGN) {
6400 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
6401 }
6402
6403 /* Satisfy length-alignment requirements */
6404 if (forcealign && (rdlen & (ALIGNMENT - 1)))
6405 rdlen = ROUNDUP(rdlen, ALIGNMENT);
6406
6407 if ((rdlen + firstread) > MAX_RX_DATASZ) {
6408 /* Too long -- skip this frame */
6409 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
6410 bus->dhd->rx_errors++; bus->rx_toolong++;
6411 dhdsdio_rxfail(bus, FALSE, FALSE);
6412 continue;
6413 }
6414
6415 dhd_os_sdlock_rxq(bus->dhd);
6416 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
6417 /* Give up on data, request rtx of events */
6418 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
6419 __FUNCTION__, rdlen, chan));
6420 bus->dhd->rx_dropped++;
6421 dhd_os_sdunlock_rxq(bus->dhd);
6422 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
6423 continue;
6424 }
6425 dhd_os_sdunlock_rxq(bus->dhd);
6426
6427 ASSERT(!PKTLINK(pkt));
6428
6429 /* Leave room for what we already read, and align remainder */
6430 ASSERT(firstread < (PKTLEN(osh, pkt)));
6431 PKTPULL(osh, pkt, firstread);
6432 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
6433
6434 /* Read the remaining frame data */
6435 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
6436 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
6437 bus->f2rxdata++;
6438 ASSERT(sdret != BCME_PENDING);
6439
6440 if (sdret < 0) {
6441 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
6442 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
6443 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
6444 dhd_os_sdlock_rxq(bus->dhd);
6445 PKTFREE(bus->dhd->osh, pkt, FALSE);
6446 dhd_os_sdunlock_rxq(bus->dhd);
6447 bus->dhd->rx_errors++;
6448 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
6449 continue;
6450 }
6451
6452 /* Copy the already-read portion */
6453 PKTPUSH(osh, pkt, firstread);
6454 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
6455
6456 #ifdef DHD_DEBUG
6457 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6458 prhex("Rx Data", PKTDATA(osh, pkt), len);
6459 }
6460 #endif // endif
6461
6462 deliver:
6463 /* Save superframe descriptor and allocate packet frame */
6464 if (chan == SDPCM_GLOM_CHANNEL) {
6465 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
6466 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
6467 __FUNCTION__, len));
6468 #ifdef DHD_DEBUG
6469 if (DHD_GLOM_ON()) {
6470 prhex("Glom Data", PKTDATA(osh, pkt), len);
6471 }
6472 #endif // endif
6473 PKTSETLEN(osh, pkt, len);
6474 ASSERT(doff == SDPCM_HDRLEN);
6475 PKTPULL(osh, pkt, SDPCM_HDRLEN);
6476 bus->glomd = pkt;
6477 } else {
6478 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
6479 dhdsdio_rxfail(bus, FALSE, FALSE);
6480 }
6481 continue;
6482 }
6483
6484 /* Fill in packet len and prio, deliver upward */
6485 PKTSETLEN(osh, pkt, len);
6486 PKTPULL(osh, pkt, doff);
6487
6488 #ifdef SDTEST
6489 /* Test channel packets are processed separately */
6490 if (chan == SDPCM_TEST_CHANNEL) {
6491 dhdsdio_testrcv(bus, pkt, seq);
6492 continue;
6493 }
6494 #endif /* SDTEST */
6495
6496 if (PKTLEN(osh, pkt) == 0) {
6497 dhd_os_sdlock_rxq(bus->dhd);
6498 PKTFREE(bus->dhd->osh, pkt, FALSE);
6499 dhd_os_sdunlock_rxq(bus->dhd);
6500 continue;
6501 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
6502 &reorder_info_len) != 0) {
6503 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
6504 dhd_os_sdlock_rxq(bus->dhd);
6505 PKTFREE(bus->dhd->osh, pkt, FALSE);
6506 dhd_os_sdunlock_rxq(bus->dhd);
6507 bus->dhd->rx_errors++;
6508 continue;
6509 }
6510
6511 if (reorder_info_len) {
6512 /* Reordering info from the firmware */
6513 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
6514 &pkt, &pkt_count);
6515 if (pkt_count == 0)
6516 continue;
6517 } else {
6518 pkt_count = 1;
6519 }
6520
6521 /* Unlock during rx call */
6522 dhd_os_sdunlock(bus->dhd);
6523 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
6524 dhd_os_sdlock(bus->dhd);
6525 #if defined(SDIO_ISR_THREAD)
6526 /* terence 20150615: fix for below error due to bussleep in watchdog after dhd_os_sdunlock here,
6527 * so call BUS_WAKE to wake up bus again
6528 * dhd_bcmsdh_recv_buf: Device asleep
6529 * dhdsdio_readframes: RXHEADER FAILED: -40
6530 * dhdsdio_rxfail: abort command, terminate frame, send NAK
6531 */
6532 BUS_WAKE(bus);
6533 #endif
6534 }
6535 rxcount = maxframes - rxleft;
6536 #ifdef DHD_DEBUG
6537 /* Message if we hit the limit */
6538 if (!rxleft && !sdtest)
6539 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
6540 else
6541 #endif /* DHD_DEBUG */
6542 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
6543 /* Back off rxseq if awaiting rtx, update rx_seq */
6544 if (bus->rxskip)
6545 rxseq--;
6546 bus->rx_seq = rxseq;
6547
6548 if (bus->reqbussleep)
6549 {
6550 dhdsdio_bussleep(bus, TRUE);
6551 bus->reqbussleep = FALSE;
6552 }
6553 bus->readframes = FALSE;
6554
6555 return rxcount;
6556 }
6557
6558 static uint32
dhdsdio_hostmail(dhd_bus_t * bus,uint32 * hmbd)6559 dhdsdio_hostmail(dhd_bus_t *bus, uint32 *hmbd)
6560 {
6561 sdpcmd_regs_t *regs = bus->regs;
6562 uint32 intstatus = 0;
6563 uint32 hmb_data;
6564 uint8 fcbits;
6565 uint retries = 0;
6566
6567 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6568
6569 /* Read mailbox data and ack that we did so */
6570 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
6571 if (retries <= retry_limit)
6572 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
6573 bus->f1regdata += 2;
6574
6575 /* Dongle recomposed rx frames, accept them again */
6576 if (hmb_data & HMB_DATA_NAKHANDLED) {
6577 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
6578 if (!bus->rxskip) {
6579 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
6580 }
6581 bus->rxskip = FALSE;
6582 intstatus |= FRAME_AVAIL_MASK(bus);
6583 }
6584
6585 /*
6586 * DEVREADY does not occur with gSPI.
6587 */
6588 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
6589 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
6590 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
6591 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
6592 bus->sdpcm_ver, SDPCM_PROT_VERSION));
6593 else
6594 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
6595 #ifndef BCMSPI
6596 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
6597 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
6598 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
6599 uint32 val;
6600
6601 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
6602 val &= ~CC_XMTDATAAVAIL_MODE;
6603 val |= CC_XMTDATAAVAIL_CTRL;
6604 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
6605
6606 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
6607 }
6608 #endif /* BCMSPI */
6609
6610 #ifdef DHD_DEBUG
6611 /* Retrieve console state address now that firmware should have updated it */
6612 {
6613 sdpcm_shared_t shared;
6614 if (dhdsdio_readshared(bus, &shared) == 0)
6615 bus->console_addr = shared.console_addr;
6616 }
6617 #endif /* DHD_DEBUG */
6618 }
6619
6620 /*
6621 * Flow Control has been moved into the RX headers and this out of band
6622 * method isn't used any more. Leave this here for possibly remaining backward
6623 * compatible with older dongles
6624 */
6625 if (hmb_data & HMB_DATA_FC) {
6626 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
6627
6628 if (fcbits & ~bus->flowcontrol)
6629 bus->fc_xoff++;
6630 if (bus->flowcontrol & ~fcbits)
6631 bus->fc_xon++;
6632
6633 bus->fc_rcvd++;
6634 bus->flowcontrol = fcbits;
6635 }
6636
6637 /* At least print a message if FW halted */
6638 if (hmb_data & HMB_DATA_FWHALT) {
6639 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
6640 dhdsdio_checkdied(bus, NULL, 0);
6641 DHD_ERROR(("Not doing bus down untill memdump done \n"));
6642 }
6643
6644 /* Shouldn't be any others */
6645 if (hmb_data & ~(HMB_DATA_DEVREADY |
6646 HMB_DATA_FWHALT |
6647 HMB_DATA_NAKHANDLED |
6648 HMB_DATA_FC |
6649 HMB_DATA_FWREADY |
6650 HMB_DATA_FCDATA_MASK |
6651 HMB_DATA_VERSION_MASK)) {
6652 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
6653 }
6654
6655 if (hmbd) {
6656 *hmbd = hmb_data;
6657 }
6658
6659 return intstatus;
6660 }
6661
6662 static bool
dhdsdio_dpc(dhd_bus_t * bus)6663 dhdsdio_dpc(dhd_bus_t *bus)
6664 {
6665 bcmsdh_info_t *sdh = bus->sdh;
6666 sdpcmd_regs_t *regs = bus->regs;
6667 uint32 intstatus, newstatus = 0;
6668 uint retries = 0;
6669 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
6670 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
6671 uint framecnt = 0; /* Temporary counter of tx/rx frames */
6672 bool rxdone = TRUE; /* Flag for no more read data */
6673 bool resched = FALSE; /* Flag indicating resched wanted */
6674 unsigned long flags;
6675 #ifdef DEBUG_DPC_THREAD_WATCHDOG
6676 bool is_resched_by_readframe = FALSE;
6677 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
6678 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6679
6680 dhd_os_sdlock(bus->dhd);
6681 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
6682 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6683 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
6684 bus->intstatus = 0;
6685 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
6686 dhd_os_sdunlock(bus->dhd);
6687 return 0;
6688 }
6689
6690 DHD_BUS_BUSY_SET_IN_DPC(bus->dhd);
6691 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
6692
6693 /* Start with leftover status bits */
6694 intstatus = bus->intstatus;
6695
6696 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
6697 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
6698 goto exit;
6699 }
6700
6701 /* If waiting for HTAVAIL, check status */
6702 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
6703 int err;
6704 uint8 clkctl, devctl = 0;
6705
6706 #ifdef DHD_DEBUG
6707 /* Check for inconsistent device control */
6708 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6709 if (err) {
6710 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
6711 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
6712 bus->dhd->busstate = DHD_BUS_DOWN;
6713 } else {
6714 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
6715 }
6716 #endif /* DHD_DEBUG */
6717
6718 /* Read CSR, if clock on switch to AVAIL, else ignore */
6719 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
6720 if (err) {
6721 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
6722 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
6723 bus->dhd->busstate = DHD_BUS_DOWN;
6724 }
6725
6726 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
6727
6728 if (SBSDIO_HTAV(clkctl)) {
6729 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6730 if (err) {
6731 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
6732 __FUNCTION__, err));
6733 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
6734 bus->dhd->busstate = DHD_BUS_DOWN;
6735 }
6736 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
6737 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
6738 if (err) {
6739 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
6740 __FUNCTION__, err));
6741 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
6742 bus->dhd->busstate = DHD_BUS_DOWN;
6743 }
6744 bus->clkstate = CLK_AVAIL;
6745 } else {
6746 goto clkwait;
6747 }
6748 }
6749
6750 BUS_WAKE(bus);
6751
6752 /* Make sure backplane clock is on */
6753 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
6754 if (bus->clkstate != CLK_AVAIL)
6755 goto clkwait;
6756
6757 /* Pending interrupt indicates new device status */
6758 if (bus->ipend) {
6759 bus->ipend = FALSE;
6760 #if defined(BT_OVER_SDIO)
6761 bcmsdh_btsdio_process_f3_intr();
6762 #endif /* defined (BT_OVER_SDIO) */
6763
6764 R_SDREG(newstatus, ®s->intstatus, retries);
6765 bus->f1regdata++;
6766 if (bcmsdh_regfail(bus->sdh))
6767 newstatus = 0;
6768 newstatus &= bus->hostintmask;
6769 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
6770 if (newstatus) {
6771 bus->f1regdata++;
6772 #ifndef BCMSPI
6773 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
6774 (newstatus == I_XMTDATA_AVAIL)) {
6775 } else
6776 #endif /* BCMSPI */
6777 W_SDREG(newstatus, ®s->intstatus, retries);
6778 }
6779 }
6780
6781 /* Merge new bits with previous */
6782 intstatus |= newstatus;
6783 bus->intstatus = 0;
6784
6785 /* Handle flow-control change: read new state in case our ack
6786 * crossed another change interrupt. If change still set, assume
6787 * FC ON for safety, let next loop through do the debounce.
6788 */
6789 if (intstatus & I_HMB_FC_CHANGE) {
6790 intstatus &= ~I_HMB_FC_CHANGE;
6791 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
6792 R_SDREG(newstatus, ®s->intstatus, retries);
6793 bus->f1regdata += 2;
6794 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
6795 intstatus |= (newstatus & bus->hostintmask);
6796 }
6797
6798 /* Handle host mailbox indication */
6799 if (intstatus & I_HMB_HOST_INT) {
6800 uint32 hmbdata = 0;
6801
6802 intstatus &= ~I_HMB_HOST_INT;
6803 intstatus |= dhdsdio_hostmail(bus, &hmbdata);
6804
6805 #ifdef DHD_ULP
6806 /* ULP prototyping. Redowload fw on oob interupt */
6807
6808 /* all the writes after this point CAN use cached sbwad value */
6809 bcmsdh_force_sbwad_calc(bus->sdh, FALSE);
6810
6811 if (dhd_ulp_pre_redownload_check(bus->dhd, bus->sdh, hmbdata)) {
6812 if (dhd_bus_ulp_reinit_fw(bus) < 0) {
6813 DHD_ERROR(("%s:%d FW redownload failed\n",
6814 __FUNCTION__, __LINE__));
6815 goto exit;
6816 }
6817 }
6818 #endif // endif
6819
6820 }
6821
6822 #ifdef DHD_UCODE_DOWNLOAD
6823 exit_ucode:
6824 #endif /* DHD_UCODE_DOWNLOAD */
6825
6826 /* Just being here means nothing more to do for chipactive */
6827 if (intstatus & I_CHIPACTIVE) {
6828 /* ASSERT(bus->clkstate == CLK_AVAIL); */
6829 intstatus &= ~I_CHIPACTIVE;
6830 }
6831
6832 /* Handle host mailbox indication */
6833 if (intstatus & I_HMB_HOST_INT) {
6834 intstatus &= ~I_HMB_HOST_INT;
6835 intstatus |= dhdsdio_hostmail(bus, NULL);
6836 }
6837
6838 /* Generally don't ask for these, can get CRC errors... */
6839 if (intstatus & I_WR_OOSYNC) {
6840 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
6841 intstatus &= ~I_WR_OOSYNC;
6842 }
6843
6844 if (intstatus & I_RD_OOSYNC) {
6845 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
6846 intstatus &= ~I_RD_OOSYNC;
6847 }
6848
6849 if (intstatus & I_SBINT) {
6850 DHD_ERROR(("Dongle reports SBINT\n"));
6851 intstatus &= ~I_SBINT;
6852 }
6853
6854 /* Would be active due to wake-wlan in gSPI */
6855 if (intstatus & I_CHIPACTIVE) {
6856 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
6857 intstatus &= ~I_CHIPACTIVE;
6858 }
6859
6860 if (intstatus & I_HMB_FC_STATE) {
6861 DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
6862 intstatus &= ~I_HMB_FC_STATE;
6863 }
6864
6865 /* Ignore frame indications if rxskip is set */
6866 if (bus->rxskip) {
6867 intstatus &= ~FRAME_AVAIL_MASK(bus);
6868 }
6869
6870 /* On frame indication, read available frames */
6871 if (PKT_AVAILABLE(bus, intstatus)) {
6872
6873 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
6874 if (rxdone || bus->rxskip)
6875 intstatus &= ~FRAME_AVAIL_MASK(bus);
6876 rxlimit -= MIN(framecnt, rxlimit);
6877 }
6878
6879 /* Keep still-pending events for next scheduling */
6880 bus->intstatus = intstatus;
6881
6882 clkwait:
6883 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
6884 * or clock availability. (Allows tx loop to check ipend if desired.)
6885 * (Unless register access seems hosed, as we may not be able to ACK...)
6886 */
6887 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh) &&
6888 !(bus->dhd->conf->oob_enabled_later && !bus->ctrl_frame_stat)) {
6889 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
6890 __FUNCTION__, rxdone, framecnt));
6891 bus->intdis = FALSE;
6892 #if defined(OOB_INTR_ONLY)
6893 bcmsdh_oob_intr_set(bus->sdh, TRUE);
6894 #endif /* defined(OOB_INTR_ONLY) */
6895 bcmsdh_intr_enable(sdh);
6896 #ifdef BCMSPI_ANDROID
6897 if (*dhd_spi_lockcount == 0)
6898 bcmsdh_oob_intr_set(bus->sdh, TRUE);
6899 #endif /* BCMSPI_ANDROID */
6900 }
6901
6902 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
6903 /* In case of SW-OOB(using edge trigger),
6904 * Check interrupt status in the dongle again after enable irq on the host.
6905 * and rechedule dpc if interrupt is pended in the dongle.
6906 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6907 * No need to do this with HW-OOB(level trigger)
6908 */
6909 R_SDREG(newstatus, ®s->intstatus, retries);
6910 if (bcmsdh_regfail(bus->sdh))
6911 newstatus = 0;
6912 if (newstatus & bus->hostintmask) {
6913 bus->ipend = TRUE;
6914 resched = TRUE;
6915 }
6916 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6917
6918 #ifdef BCMSDIO_RXLIM_POST
6919 if (!DATAOK(bus) && bus->rxlim_en) {
6920 uint8 rxlim = 0;
6921 if (0 == dhdsdio_membytes(bus, FALSE, bus->rxlim_addr, (uint8 *)&rxlim, 1)) {
6922 if (bus->tx_max != rxlim) {
6923 DHD_INFO(("%s: bus->tx_max/rxlim=%d/%d\n", __FUNCTION__,
6924 bus->tx_max, rxlim));
6925 bus->tx_max = rxlim;
6926 }
6927 }
6928 }
6929 #endif /* BCMSDIO_RXLIM_POST */
6930
6931 #ifdef PROP_TXSTATUS
6932 dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE);
6933 #endif // endif
6934
6935 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6936 dhdsdio_sendpendctl(bus);
6937 #ifdef CONSOLE_DPC
6938 else if (DATAOK(bus) && strlen(bus->cons_cmd) && (bus->clkstate == CLK_AVAIL) &&
6939 !bus->fcstate) {
6940 dhd_bus_console_in(bus->dhd, bus->cons_cmd, strlen(bus->cons_cmd));
6941 }
6942 #endif
6943
6944 /* Send queued frames (limit 1 if rx may still be pending) */
6945 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6946 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6947
6948 #ifdef DHD_ULP
6949 if (dhd_ulp_f2_ready(bus->dhd, bus->sdh)) {
6950 #endif /* DHD_ULP */
6951 if (bus->dhd->conf->dhd_txminmax < 0)
6952 framecnt = rxdone ? txlimit : MIN(txlimit, DATABUFCNT(bus));
6953 else
6954 framecnt = rxdone ? txlimit : MIN(txlimit, bus->dhd->conf->dhd_txminmax);
6955 framecnt = dhdsdio_sendfromq(bus, framecnt);
6956 txlimit -= framecnt;
6957 #ifdef DHD_ULP
6958 } else {
6959 /* In other transient states like DHD_ULP_, after the states are
6960 * DHD_ULP_F2ENAB_CLEARING and DHD_ULP_F2ENAB_SETTING,
6961 * dpc is scheduled after steady-state and dhdsdio_sendfromq() will
6962 * execute again
6963 */
6964 }
6965 #endif /* DHD_ULP */
6966 }
6967 /* Resched the DPC if ctrl cmd is pending on bus credit */
6968 if (bus->ctrl_frame_stat) {
6969 if (bus->dhd->conf->txctl_tmo_fix) {
6970 set_current_state(TASK_INTERRUPTIBLE);
6971 if (!kthread_should_stop())
6972 schedule_timeout(1);
6973 set_current_state(TASK_RUNNING);
6974 }
6975 resched = TRUE;
6976 }
6977
6978 /* Resched if events or tx frames are pending, else await next interrupt */
6979 /* On failed register access, all bets are off: no resched or interrupts */
6980 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6981 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6982 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6983 /* Bus failed because of KSO */
6984 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6985 bus->kso = FALSE;
6986 } else {
6987 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6988 __FUNCTION__));
6989 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
6990 bus->dhd->busstate = DHD_BUS_DOWN;
6991 bus->intstatus = 0;
6992 }
6993 } else if (bus->clkstate == CLK_PENDING) {
6994 /* Awaiting I_CHIPACTIVE; don't resched */
6995 } else if (bus->intstatus || bus->ipend ||
6996 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6997 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
6998 resched = TRUE;
6999 }
7000
7001 bus->dpc_sched = resched;
7002
7003 /* If we're done for now, turn off clock request. */
7004 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING) &&
7005 NO_OTHER_ACTIVE_BUS_USER(bus)) {
7006 bus->activity = FALSE;
7007 dhdsdio_bussleep(bus, TRUE);
7008 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7009 }
7010
7011 exit:
7012
7013 if (!resched) {
7014 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
7015 * or clock availability. (Allows tx loop to check ipend if desired.)
7016 * (Unless register access seems hosed, as we may not be able to ACK...)
7017 */
7018 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh) &&
7019 (bus->dhd->conf->oob_enabled_later && !bus->ctrl_frame_stat)) {
7020 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
7021 __FUNCTION__, rxdone, framecnt));
7022 bus->intdis = FALSE;
7023 #if defined(OOB_INTR_ONLY)
7024 bcmsdh_oob_intr_set(bus->sdh, TRUE);
7025 #endif /* defined(OOB_INTR_ONLY) */
7026 bcmsdh_intr_enable(sdh);
7027 }
7028 if (dhd_dpcpoll) {
7029 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
7030 resched = TRUE;
7031 #ifdef DEBUG_DPC_THREAD_WATCHDOG
7032 is_resched_by_readframe = TRUE;
7033 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
7034 }
7035 }
7036 }
7037
7038 #ifdef HOST_TPUT_TEST
7039 dhd_conf_tput_measure(bus->dhd);
7040 #endif
7041
7042 if (bus->ctrl_wait && TXCTLOK(bus))
7043 wake_up_interruptible(&bus->ctrl_tx_wait);
7044 dhd_os_sdunlock(bus->dhd);
7045 #ifdef DEBUG_DPC_THREAD_WATCHDOG
7046 if (bus->dhd->dhd_bug_on) {
7047 DHD_INFO(("%s: resched = %d ctrl_frame_stat = %d intstatus 0x%08x"
7048 " ipend = %d pktq_mlen = %d is_resched_by_readframe = %d \n",
7049 __FUNCTION__, resched, bus->ctrl_frame_stat,
7050 bus->intstatus, bus->ipend,
7051 pktq_mlen(&bus->txq, ~bus->flowcontrol), is_resched_by_readframe));
7052
7053 bus->dhd->dhd_bug_on = FALSE;
7054 }
7055 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
7056
7057 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
7058 DHD_BUS_BUSY_CLEAR_IN_DPC(bus->dhd);
7059 dhd_os_busbusy_wake(bus->dhd);
7060 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
7061
7062 return resched;
7063 }
7064
7065 bool
dhd_bus_dpc(struct dhd_bus * bus)7066 dhd_bus_dpc(struct dhd_bus *bus)
7067 {
7068 bool resched;
7069
7070 /* Call the DPC directly. */
7071 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
7072 resched = dhdsdio_dpc(bus);
7073
7074 return resched;
7075 }
7076
7077 void
dhdsdio_isr(void * arg)7078 dhdsdio_isr(void *arg)
7079 {
7080 dhd_bus_t *bus = (dhd_bus_t*)arg;
7081 bcmsdh_info_t *sdh;
7082
7083 if (!bus) {
7084 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
7085 return;
7086 }
7087 sdh = bus->sdh;
7088
7089 if (bus->dhd->busstate == DHD_BUS_DOWN) {
7090 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
7091 return;
7092 }
7093
7094 DHD_INTR(("%s: Enter\n", __FUNCTION__));
7095
7096 /* Count the interrupt call */
7097 bus->intrcount++;
7098 bus->ipend = TRUE;
7099
7100 /* Shouldn't get this interrupt if we're sleeping? */
7101 if (!SLPAUTO_ENAB(bus)) {
7102 if (bus->sleeping) {
7103 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
7104 return;
7105 } else if (!KSO_ENAB(bus)) {
7106 DHD_ERROR(("ISR in devsleep 1\n"));
7107 }
7108 }
7109
7110 /* Disable additional interrupts (is this needed now)? */
7111 if (bus->intr) {
7112 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
7113 } else {
7114 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
7115 }
7116
7117 #ifdef BCMSPI_ANDROID
7118 bcmsdh_oob_intr_set(bus->sdh, FALSE);
7119 #endif /* BCMSPI_ANDROID */
7120 bcmsdh_intr_disable(sdh);
7121 bus->intdis = TRUE;
7122
7123 #if defined(SDIO_ISR_THREAD)
7124 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
7125 DHD_OS_WAKE_LOCK(bus->dhd);
7126 /* terence 20150209: dpc should be scheded again if dpc_sched is TRUE or dhd_bus_txdata can
7127 not schedule anymore because dpc_sched is TRUE now.
7128 */
7129 if (dhdsdio_dpc(bus)) {
7130 bus->dpc_sched = TRUE;
7131 dhd_sched_dpc(bus->dhd);
7132 }
7133 DHD_OS_WAKE_UNLOCK(bus->dhd);
7134 #else
7135 bus->dpc_sched = TRUE;
7136 dhd_sched_dpc(bus->dhd);
7137 #endif /* defined(SDIO_ISR_THREAD) */
7138
7139 }
7140
7141 #ifdef PKT_STATICS
dhd_bus_dump_txpktstatics(struct dhd_bus * bus)7142 void dhd_bus_dump_txpktstatics(struct dhd_bus *bus)
7143 {
7144 uint i;
7145 uint32 total = 0;
7146
7147 printf("%s: TYPE EVENT: %d pkts (size=%d) transfered\n",
7148 __FUNCTION__, bus->tx_statics.event_count, bus->tx_statics.event_size);
7149 printf("%s: TYPE CTRL: %d pkts (size=%d) transfered\n",
7150 __FUNCTION__, bus->tx_statics.ctrl_count, bus->tx_statics.ctrl_size);
7151 printf("%s: TYPE DATA: %d pkts (size=%d) transfered\n",
7152 __FUNCTION__, bus->tx_statics.data_count, bus->tx_statics.data_size);
7153 printf("%s: Glom size distribution:\n", __FUNCTION__);
7154 for (i=0;i<bus->tx_statics.glom_max;i++) {
7155 total += bus->tx_statics.glom_cnt[i];
7156 }
7157 printk(KERN_CONT DHD_LOG_PREFIXS);
7158 for (i=0;i<bus->tx_statics.glom_max;i++) {
7159 printk(KERN_CONT "%02d: %5d", i+1, bus->tx_statics.glom_cnt[i]);
7160 if ((i+1)%8)
7161 printk(KERN_CONT ", ");
7162 else {
7163 printk("\n");
7164 printk(KERN_CONT DHD_LOG_PREFIXS);
7165 }
7166 }
7167 printk("\n");
7168 printk(KERN_CONT DHD_LOG_PREFIXS);
7169 for (i=0;i<bus->tx_statics.glom_max;i++) {
7170 printk(KERN_CONT "%02d:%5d%%", i+1, (bus->tx_statics.glom_cnt[i]*100)/total);
7171 if ((i+1)%8)
7172 printk(KERN_CONT ", ");
7173 else {
7174 printk("\n");
7175 printk(KERN_CONT DHD_LOG_PREFIXS);
7176 }
7177 }
7178 printk("\n");
7179 printf("%s: Glom spend time distribution(us):\n", __FUNCTION__);
7180 printk(KERN_CONT DHD_LOG_PREFIXS);
7181 for (i=0;i<bus->tx_statics.glom_max;i++) {
7182 printk(KERN_CONT "%02d: %5u", i+1, bus->tx_statics.glom_cnt_us[i]);
7183 if ((i+1)%8)
7184 printk(KERN_CONT ", ");
7185 else {
7186 printk("\n");
7187 printk(KERN_CONT DHD_LOG_PREFIXS);
7188 }
7189 }
7190 printk("\n");
7191 if (total) {
7192 printf("%s: data(%d)/glom(%d)=%d, glom_max=%d\n",
7193 __FUNCTION__, bus->tx_statics.data_count, total,
7194 bus->tx_statics.data_count/total, bus->tx_statics.glom_max);
7195 }
7196 printf("%s: TYPE RX GLOM: %d pkts (size=%d) transfered\n",
7197 __FUNCTION__, bus->tx_statics.glom_count, bus->tx_statics.glom_size);
7198 printf("%s: TYPE TEST: %d pkts (size=%d) transfered\n",
7199 __FUNCTION__, bus->tx_statics.test_count, bus->tx_statics.test_size);
7200 }
7201
dhd_bus_clear_txpktstatics(struct dhd_bus * bus)7202 void dhd_bus_clear_txpktstatics(struct dhd_bus *bus)
7203 {
7204 memset((uint8*) &bus->tx_statics, 0, sizeof(pkt_statics_t));
7205 }
7206 #endif
7207
7208 #ifdef SDTEST
7209 static void
dhdsdio_pktgen_init(dhd_bus_t * bus)7210 dhdsdio_pktgen_init(dhd_bus_t *bus)
7211 {
7212 /* Default to specified length, or full range */
7213 if (dhd_pktgen_len) {
7214 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
7215 bus->pktgen_minlen = bus->pktgen_maxlen;
7216 } else {
7217 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
7218 bus->pktgen_minlen = 0;
7219 }
7220 bus->pktgen_len = (uint16)bus->pktgen_minlen;
7221
7222 /* Default to per-watchdog burst with 10s print time */
7223 bus->pktgen_freq = 1;
7224 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
7225 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
7226
7227 /* Default to echo mode */
7228 bus->pktgen_mode = DHD_PKTGEN_ECHO;
7229 bus->pktgen_stop = 1;
7230 }
7231
7232 static void
dhdsdio_pktgen(dhd_bus_t * bus)7233 dhdsdio_pktgen(dhd_bus_t *bus)
7234 {
7235 void *pkt;
7236 uint8 *data;
7237 uint pktcount;
7238 uint fillbyte;
7239 osl_t *osh = bus->dhd->osh;
7240 uint16 len;
7241 ulong time_lapse;
7242 uint sent_pkts;
7243 uint rcvd_pkts;
7244
7245 /* Display current count if appropriate */
7246 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
7247 bus->pktgen_ptick = 0;
7248 printf("%s: send attempts %d, rcvd %d, errors %d\n",
7249 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
7250
7251 /* Print throughput stats only for constant length packet runs */
7252 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
7253 time_lapse = jiffies - bus->pktgen_prev_time;
7254 bus->pktgen_prev_time = jiffies;
7255 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
7256 bus->pktgen_prev_sent = bus->pktgen_sent;
7257 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
7258 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
7259
7260 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
7261 __FUNCTION__,
7262 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
7263 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
7264 }
7265 }
7266
7267 /* For recv mode, just make sure dongle has started sending */
7268 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
7269 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
7270 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
7271 dhdsdio_sdtest_set(bus, bus->pktgen_total);
7272 }
7273 return;
7274 }
7275
7276 /* Otherwise, generate or request the specified number of packets */
7277 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
7278 /* Stop if total has been reached */
7279 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
7280 bus->pktgen_count = 0;
7281 break;
7282 }
7283
7284 /* Allocate an appropriate-sized packet */
7285 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
7286 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
7287 } else {
7288 len = bus->pktgen_len;
7289 }
7290 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
7291 TRUE))) {;
7292 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
7293 break;
7294 }
7295 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
7296 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7297
7298 /* Write test header cmd and extra based on mode */
7299 switch (bus->pktgen_mode) {
7300 case DHD_PKTGEN_ECHO:
7301 *data++ = SDPCM_TEST_ECHOREQ;
7302 *data++ = (uint8)bus->pktgen_sent;
7303 break;
7304
7305 case DHD_PKTGEN_SEND:
7306 *data++ = SDPCM_TEST_DISCARD;
7307 *data++ = (uint8)bus->pktgen_sent;
7308 break;
7309
7310 case DHD_PKTGEN_RXBURST:
7311 *data++ = SDPCM_TEST_BURST;
7312 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
7313 break;
7314
7315 default:
7316 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
7317 PKTFREE(osh, pkt, TRUE);
7318 bus->pktgen_count = 0;
7319 return;
7320 }
7321
7322 /* Write test header length field */
7323 *data++ = (bus->pktgen_len >> 0);
7324 *data++ = (bus->pktgen_len >> 8);
7325
7326 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
7327 * burst mode
7328 */
7329 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
7330 *data++ = (uint8)(bus->pktgen_count >> 0);
7331 *data++ = (uint8)(bus->pktgen_count >> 8);
7332 *data++ = (uint8)(bus->pktgen_count >> 16);
7333 *data++ = (uint8)(bus->pktgen_count >> 24);
7334 } else {
7335
7336 /* Then fill in the remainder -- N/A for burst */
7337 for (fillbyte = 0; fillbyte < len; fillbyte++)
7338 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
7339 }
7340
7341 #ifdef DHD_DEBUG
7342 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
7343 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7344 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
7345 }
7346 #endif // endif
7347
7348 /* Send it */
7349 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
7350 bus->pktgen_fail++;
7351 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
7352 bus->pktgen_count = 0;
7353 }
7354 bus->pktgen_sent++;
7355
7356 /* Bump length if not fixed, wrap at max */
7357 if (++bus->pktgen_len > bus->pktgen_maxlen)
7358 bus->pktgen_len = (uint16)bus->pktgen_minlen;
7359
7360 /* Special case for burst mode: just send one request! */
7361 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
7362 break;
7363 }
7364 }
7365
7366 static void
dhdsdio_sdtest_set(dhd_bus_t * bus,uint count)7367 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
7368 {
7369 void *pkt;
7370 uint8 *data;
7371 osl_t *osh = bus->dhd->osh;
7372
7373 /* Allocate the packet */
7374 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
7375 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
7376 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
7377 return;
7378 }
7379 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
7380 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
7381 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7382
7383 /* Fill in the test header */
7384 *data++ = SDPCM_TEST_SEND;
7385 *data++ = (count > 0)?TRUE:FALSE;
7386 *data++ = (bus->pktgen_maxlen >> 0);
7387 *data++ = (bus->pktgen_maxlen >> 8);
7388 *data++ = (uint8)(count >> 0);
7389 *data++ = (uint8)(count >> 8);
7390 *data++ = (uint8)(count >> 16);
7391 *data++ = (uint8)(count >> 24);
7392
7393 /* Send it */
7394 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK)
7395 bus->pktgen_fail++;
7396 }
7397
7398 static void
dhdsdio_testrcv(dhd_bus_t * bus,void * pkt,uint seq)7399 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
7400 {
7401 osl_t *osh = bus->dhd->osh;
7402 uint8 *data;
7403 uint pktlen;
7404
7405 uint8 cmd;
7406 uint8 extra;
7407 uint16 len;
7408 uint16 offset;
7409
7410 /* Check for min length */
7411 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
7412 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
7413 PKTFREE(osh, pkt, FALSE);
7414 return;
7415 }
7416
7417 /* Extract header fields */
7418 data = PKTDATA(osh, pkt);
7419 cmd = *data++;
7420 extra = *data++;
7421 len = *data++; len += *data++ << 8;
7422 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
7423 /* Check length for relevant commands */
7424 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
7425 if (pktlen != len + SDPCM_TEST_HDRLEN) {
7426 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
7427 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
7428 PKTFREE(osh, pkt, FALSE);
7429 return;
7430 }
7431 }
7432
7433 /* Process as per command */
7434 switch (cmd) {
7435 case SDPCM_TEST_ECHOREQ:
7436 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
7437 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
7438 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) {
7439 bus->pktgen_sent++;
7440 } else {
7441 bus->pktgen_fail++;
7442 PKTFREE(osh, pkt, FALSE);
7443 }
7444 bus->pktgen_rcvd++;
7445 break;
7446
7447 case SDPCM_TEST_ECHORSP:
7448 if (bus->ext_loop) {
7449 PKTFREE(osh, pkt, FALSE);
7450 bus->pktgen_rcvd++;
7451 break;
7452 }
7453
7454 for (offset = 0; offset < len; offset++, data++) {
7455 if (*data != SDPCM_TEST_FILL(offset, extra)) {
7456 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
7457 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
7458 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
7459 break;
7460 }
7461 }
7462 PKTFREE(osh, pkt, FALSE);
7463 bus->pktgen_rcvd++;
7464 break;
7465
7466 case SDPCM_TEST_DISCARD:
7467 {
7468 int i = 0;
7469 uint8 *prn = data;
7470 uint8 testval = extra;
7471 for (i = 0; i < len; i++) {
7472 if (*prn != testval) {
7473 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
7474 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
7475 prn++; testval++;
7476 }
7477 }
7478 }
7479 PKTFREE(osh, pkt, FALSE);
7480 bus->pktgen_rcvd++;
7481 break;
7482
7483 case SDPCM_TEST_BURST:
7484 case SDPCM_TEST_SEND:
7485 default:
7486 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
7487 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
7488 PKTFREE(osh, pkt, FALSE);
7489 break;
7490 }
7491
7492 /* For recv mode, stop at limit (and tell dongle to stop sending) */
7493 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
7494 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
7495 bus->pktgen_rcvd_rcvsession++;
7496
7497 if (bus->pktgen_total &&
7498 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
7499 bus->pktgen_count = 0;
7500 DHD_ERROR(("Pktgen:rcv test complete!\n"));
7501 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
7502 dhdsdio_sdtest_set(bus, FALSE);
7503 bus->pktgen_rcvd_rcvsession = 0;
7504 }
7505 }
7506 }
7507 }
7508 #endif /* SDTEST */
7509
dhd_bus_oob_intr_register(dhd_pub_t * dhdp)7510 int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
7511 {
7512 int err = 0;
7513
7514 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7515 err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
7516 #endif // endif
7517 return err;
7518 }
7519
dhd_bus_oob_intr_unregister(dhd_pub_t * dhdp)7520 void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
7521 {
7522 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7523 bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
7524 #endif // endif
7525 }
7526
dhd_bus_oob_intr_set(dhd_pub_t * dhdp,bool enable)7527 void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
7528 {
7529 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7530 bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
7531 #endif // endif
7532 }
7533
dhd_bus_dev_pm_stay_awake(dhd_pub_t * dhdpub)7534 void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
7535 {
7536 bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh);
7537 }
7538
dhd_bus_dev_pm_relax(dhd_pub_t * dhdpub)7539 void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub)
7540 {
7541 bcmsdh_dev_relax(dhdpub->bus->sdh);
7542 }
7543
dhd_bus_dev_pm_enabled(dhd_pub_t * dhdpub)7544 bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub)
7545 {
7546 bool enabled = FALSE;
7547
7548 enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh);
7549 return enabled;
7550 }
7551
7552 extern bool
dhd_bus_watchdog(dhd_pub_t * dhdp)7553 dhd_bus_watchdog(dhd_pub_t *dhdp)
7554 {
7555 dhd_bus_t *bus;
7556 unsigned long flags;
7557
7558 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
7559
7560 bus = dhdp->bus;
7561
7562 if (bus->dhd->dongle_reset)
7563 return FALSE;
7564
7565 if (bus->dhd->hang_was_sent) {
7566 dhd_os_wd_timer(bus->dhd, 0);
7567 return FALSE;
7568 }
7569
7570 /* Ignore the timer if simulating bus down */
7571 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
7572 return FALSE;
7573
7574 DHD_LINUX_GENERAL_LOCK(dhdp, flags);
7575 if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp) ||
7576 DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) {
7577 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
7578 return FALSE;
7579 }
7580 DHD_BUS_BUSY_SET_IN_WD(dhdp);
7581 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
7582
7583 dhd_os_sdlock(bus->dhd);
7584
7585 /* Poll period: check device if appropriate. */
7586 // terence 20160615: remove !SLPAUTO_ENAB(bus) to fix not able to polling if sr supported
7587 if (1 && (bus->poll && (++bus->polltick >= bus->pollrate))) {
7588 uint32 intstatus = 0;
7589
7590 /* Reset poll tick */
7591 bus->polltick = 0;
7592
7593 /* Check device if no interrupts */
7594 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
7595
7596 #ifndef BCMSPI
7597 if (!bus->dpc_sched) {
7598 uint8 devpend;
7599 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
7600 SDIOD_CCCR_INTPEND, NULL);
7601 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
7602 }
7603 #else
7604 if (!bus->dpc_sched) {
7605 uint32 devpend;
7606 devpend = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0,
7607 SPID_STATUS_REG, NULL);
7608 intstatus = devpend & STATUS_F2_PKT_AVAILABLE;
7609 }
7610 #endif /* !BCMSPI */
7611
7612 /* If there is something, make like the ISR and schedule the DPC */
7613 if (intstatus) {
7614 bus->pollcnt++;
7615 bus->ipend = TRUE;
7616 if (bus->intr) {
7617 bcmsdh_intr_disable(bus->sdh);
7618 }
7619 bus->dpc_sched = TRUE;
7620 dhd_sched_dpc(bus->dhd);
7621 }
7622 }
7623
7624 /* Update interrupt tracking */
7625 bus->lastintrs = bus->intrcount;
7626 }
7627
7628 if ((!bus->dpc_sched) && pktq_n_pkts_tot(&bus->txq)) {
7629 bus->dpc_sched = TRUE;
7630 dhd_sched_dpc(bus->dhd);
7631 }
7632
7633 #ifdef DHD_DEBUG
7634 /* Poll for console output periodically */
7635 if (dhdp->busstate == DHD_BUS_DATA && dhdp->dhd_console_ms != 0) {
7636 bus->console.count += dhd_watchdog_ms;
7637 if (bus->console.count >= dhdp->dhd_console_ms) {
7638 bus->console.count -= dhdp->dhd_console_ms;
7639 /* Make sure backplane clock is on */
7640 if (SLPAUTO_ENAB(bus))
7641 dhdsdio_bussleep(bus, FALSE);
7642 else
7643 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7644 if (dhdsdio_readconsole(bus) < 0)
7645 dhdp->dhd_console_ms = 0; /* On error, stop trying */
7646 }
7647 }
7648 #endif /* DHD_DEBUG */
7649
7650 #ifdef SDTEST
7651 /* Generate packets if configured */
7652 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
7653 /* Make sure backplane clock is on */
7654 if (SLPAUTO_ENAB(bus))
7655 dhdsdio_bussleep(bus, FALSE);
7656 else
7657 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7658 bus->pktgen_tick = 0;
7659 dhdsdio_pktgen(bus);
7660 }
7661 #endif // endif
7662
7663 /* On idle timeout clear activity flag and/or turn off clock */
7664 #ifdef DHD_USE_IDLECOUNT
7665 if (bus->activity)
7666 bus->activity = FALSE;
7667 else {
7668 bus->idlecount++;
7669
7670 /*
7671 * If the condition to switch off the clock is reached And if
7672 * BT is inactive (in case of BT_OVER_SDIO build) turn off clk.
7673 *
7674 * Consider the following case, DHD is configured with
7675 * 1) idletime == DHD_IDLE_IMMEDIATE
7676 * 2) BT is the last user of the clock
7677 * We cannot disable the clock from __dhdsdio_clk_disable
7678 * since WLAN might be using it. If WLAN is active then
7679 * from the respective function/context after doing the job
7680 * the clk is turned off.
7681 * But if WLAN is actually inactive then the watchdog should
7682 * disable the clock. So the condition check below should be
7683 * bus->idletime != 0 instead of idletime == 0
7684 */
7685 if ((bus->idletime != 0) && (bus->idlecount >= bus->idletime) &&
7686 NO_OTHER_ACTIVE_BUS_USER(bus)) {
7687 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
7688 if (!bus->poll && SLPAUTO_ENAB(bus)) {
7689 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
7690 dhd_os_wd_timer(bus->dhd, 0);
7691 } else
7692 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7693
7694 bus->idlecount = 0;
7695 }
7696 }
7697 #else
7698 if ((bus->idletime != 0) && (bus->clkstate == CLK_AVAIL) &&
7699 NO_OTHER_ACTIVE_BUS_USER(bus)) {
7700 if (++bus->idlecount >= bus->idletime) {
7701 bus->idlecount = 0;
7702 if (bus->activity) {
7703 bus->activity = FALSE;
7704 if (!bus->poll && SLPAUTO_ENAB(bus)) {
7705 if (!bus->readframes)
7706 dhdsdio_bussleep(bus, TRUE);
7707 else
7708 bus->reqbussleep = TRUE;
7709 } else {
7710 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7711 }
7712 }
7713 }
7714 }
7715 #endif /* DHD_USE_IDLECOUNT */
7716
7717 dhd_os_sdunlock(bus->dhd);
7718
7719 DHD_LINUX_GENERAL_LOCK(dhdp, flags);
7720 DHD_BUS_BUSY_CLEAR_IN_WD(dhdp);
7721 dhd_os_busbusy_wake(dhdp);
7722 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
7723
7724 return bus->ipend;
7725 }
7726
7727 extern int
dhd_bus_console_in(dhd_pub_t * dhdp,uchar * msg,uint msglen)7728 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
7729 {
7730 dhd_bus_t *bus = dhdp->bus;
7731 uint32 addr, val;
7732 int rv;
7733 void *pkt;
7734
7735 #ifndef CONSOLE_DPC
7736 /* Exclusive bus access */
7737 dhd_os_sdlock(bus->dhd);
7738 #endif
7739
7740 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
7741 if (bus->console_addr == 0) {
7742 rv = BCME_UNSUPPORTED;
7743 goto exit;
7744 }
7745
7746 /* Don't allow input if dongle is in reset */
7747 if (bus->dhd->dongle_reset) {
7748 rv = BCME_NOTREADY;
7749 goto exit;
7750 }
7751
7752 #ifndef CONSOLE_DPC
7753 if (!DATAOK(bus)) {
7754 DHD_CTL(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d, pktq_len %d\n",
7755 __FUNCTION__, bus->tx_max, bus->tx_seq, pktq_n_pkts_tot(&bus->txq)));
7756 rv = BCME_NOTREADY;
7757 goto exit;
7758 }
7759
7760 /* Request clock to allow SDIO accesses */
7761 BUS_WAKE(bus);
7762 /* No pend allowed since txpkt is called later, ht clk has to be on */
7763 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7764 #endif
7765
7766 /* Zero cbuf_index */
7767 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx);
7768 val = htol32(0);
7769 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
7770 goto done;
7771
7772 /* Write message into cbuf */
7773 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf);
7774 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
7775 goto done;
7776
7777 /* Write length into vcons_in */
7778 addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in);
7779 val = htol32(msglen);
7780 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
7781 goto done;
7782
7783 /* Bump dongle by sending an empty packet on the event channel.
7784 * sdpcm_sendup (RX) checks for virtual console input.
7785 */
7786 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
7787 rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE);
7788
7789 done:
7790 #ifndef CONSOLE_DPC
7791 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
7792 NO_OTHER_ACTIVE_BUS_USER(bus)) {
7793 bus->activity = FALSE;
7794 dhdsdio_bussleep(bus, TRUE);
7795 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7796 }
7797 #endif
7798
7799 exit:
7800 #ifdef CONSOLE_DPC
7801 memset(bus->cons_cmd, 0, sizeof(bus->cons_cmd));
7802 #else
7803 dhd_os_sdunlock(bus->dhd);
7804 #endif
7805 return rv;
7806 }
7807
7808 #ifdef CONSOLE_DPC
7809 extern int
dhd_bus_txcons(dhd_pub_t * dhdp,uchar * msg,uint msglen)7810 dhd_bus_txcons(dhd_pub_t *dhdp, uchar *msg, uint msglen)
7811 {
7812 dhd_bus_t *bus = dhdp->bus;
7813 int ret = BCME_OK;
7814
7815 dhd_os_sdlock(bus->dhd);
7816
7817 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
7818 if (bus->console_addr == 0) {
7819 ret = BCME_UNSUPPORTED;
7820 goto exit;
7821 }
7822
7823 /* Don't allow input if dongle is in reset */
7824 if (bus->dhd->dongle_reset) {
7825 ret = BCME_NOTREADY;
7826 goto exit;
7827 }
7828
7829 if (msglen >= sizeof(bus->cons_cmd)) {
7830 DHD_ERROR(("%s: \"%s\"(%d) too long\n", __FUNCTION__, msg, msglen));
7831 ret = BCME_BADARG;
7832 goto exit;
7833 }
7834
7835 if (!strlen(bus->cons_cmd)) {
7836 strncpy(bus->cons_cmd, msg, sizeof(bus->cons_cmd));
7837 DHD_CTL(("%s: \"%s\" delay send, tx_max %d, tx_seq %d, pktq_len %d\n",
7838 __FUNCTION__, bus->cons_cmd, bus->tx_max, bus->tx_seq, pktq_n_pkts_tot(&bus->txq)));
7839 if (!bus->dpc_sched) {
7840 bus->dpc_sched = TRUE;
7841 dhd_sched_dpc(bus->dhd);
7842 }
7843 } else {
7844 DHD_CTL(("%s: \"%s\" is pending, tx_max %d, tx_seq %d, pktq_len %d\n",
7845 __FUNCTION__, bus->cons_cmd, bus->tx_max, bus->tx_seq, pktq_n_pkts_tot(&bus->txq)));
7846 ret = BCME_NOTREADY;
7847 }
7848
7849 exit:
7850 dhd_os_sdunlock(bus->dhd);
7851
7852 return ret;
7853 }
7854 #endif
7855
7856 #if defined(DHD_DEBUG) && !defined(BCMSDIOLITE)
7857 static void
dhd_dump_cis(uint fn,uint8 * cis)7858 dhd_dump_cis(uint fn, uint8 *cis)
7859 {
7860 uint byte, tag, tdata;
7861 DHD_INFO(("Function %d CIS:\n", fn));
7862
7863 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
7864 if ((byte % 16) == 0)
7865 DHD_INFO((" "));
7866 DHD_INFO(("%02x ", cis[byte]));
7867 if ((byte % 16) == 15)
7868 DHD_INFO(("\n"));
7869 if (!tdata--) {
7870 tag = cis[byte];
7871 if (tag == 0xff)
7872 break;
7873 else if (!tag)
7874 tdata = 0;
7875 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
7876 tdata = cis[byte + 1] + 1;
7877 else
7878 DHD_INFO(("]"));
7879 }
7880 }
7881 if ((byte % 16) != 15)
7882 DHD_INFO(("\n"));
7883 }
7884 #endif /* DHD_DEBUG */
7885
7886 static bool
dhdsdio_chipmatch(uint16 chipid)7887 dhdsdio_chipmatch(uint16 chipid)
7888 {
7889 if (chipid == BCM4330_CHIP_ID)
7890 return TRUE;
7891 if (chipid == BCM43362_CHIP_ID)
7892 return TRUE;
7893 if (chipid == BCM43340_CHIP_ID)
7894 return TRUE;
7895 if (chipid == BCM43341_CHIP_ID)
7896 return TRUE;
7897 if (chipid == BCM4334_CHIP_ID)
7898 return TRUE;
7899 if (chipid == BCM4324_CHIP_ID)
7900 return TRUE;
7901 if (chipid == BCM4335_CHIP_ID)
7902 return TRUE;
7903 if (chipid == BCM4339_CHIP_ID)
7904 return TRUE;
7905 if (BCM4345_CHIP(chipid))
7906 return TRUE;
7907 if (chipid == BCM4350_CHIP_ID)
7908 return TRUE;
7909 if (chipid == BCM4354_CHIP_ID)
7910 return TRUE;
7911 if (chipid == BCM4358_CHIP_ID)
7912 return TRUE;
7913 if (chipid == BCM43569_CHIP_ID)
7914 return TRUE;
7915 if (chipid == BCM4371_CHIP_ID)
7916 return TRUE;
7917 if (chipid == BCM43430_CHIP_ID)
7918 return TRUE;
7919 if (chipid == BCM43018_CHIP_ID)
7920 return TRUE;
7921 if (BCM4349_CHIP(chipid))
7922 return TRUE;
7923 if (chipid == BCM4364_CHIP_ID)
7924 return TRUE;
7925
7926 if (chipid == BCM43012_CHIP_ID)
7927 return TRUE;
7928
7929 if (chipid == BCM43014_CHIP_ID)
7930 return TRUE;
7931
7932 if (chipid == BCM4369_CHIP_ID)
7933 return TRUE;
7934 if (chipid == BCM4362_CHIP_ID)
7935 return TRUE;
7936 if (chipid == BCM43751_CHIP_ID)
7937 return TRUE;
7938 if (chipid == BCM43752_CHIP_ID)
7939 return TRUE;
7940
7941 return FALSE;
7942 }
7943
7944 static void *
dhdsdio_probe(uint16 venid,uint16 devid,uint16 bus_no,uint16 slot,uint16 func,uint bustype,void * regsva,osl_t * osh,void * sdh)7945 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
7946 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
7947 {
7948 int ret;
7949 dhd_bus_t *bus;
7950
7951 DHD_MUTEX_LOCK();
7952
7953 /* Init global variables at run-time, not as part of the declaration.
7954 * This is required to support init/de-init of the driver. Initialization
7955 * of globals as part of the declaration results in non-deterministic
7956 * behavior since the value of the globals may be different on the
7957 * first time that the driver is initialized vs subsequent initializations.
7958 */
7959 dhd_txbound = DHD_TXBOUND;
7960 dhd_rxbound = DHD_RXBOUND;
7961 #ifdef BCMSPI
7962 dhd_alignctl = FALSE;
7963 #else
7964 dhd_alignctl = TRUE;
7965 #endif /* BCMSPI */
7966 sd1idle = TRUE;
7967 dhd_readahead = TRUE;
7968 retrydata = FALSE;
7969
7970 #ifdef DISABLE_FLOW_CONTROL
7971 dhd_doflow = FALSE;
7972 #endif /* DISABLE_FLOW_CONTROL */
7973 dhd_dongle_ramsize = 0;
7974 dhd_txminmax = DHD_TXMINMAX;
7975
7976 #ifdef BCMSPI
7977 forcealign = FALSE;
7978 #else
7979 forcealign = TRUE;
7980 #endif /* !BCMSPI */
7981
7982 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7983 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
7984
7985 /* We make assumptions about address window mappings */
7986 ASSERT((uintptr)regsva == si_enum_base(devid));
7987
7988 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
7989 * means early parse could fail, so here we should get either an ID
7990 * we recognize OR (-1) indicating we must request power first.
7991 */
7992 /* Check the Vendor ID */
7993 switch (venid) {
7994 case 0x0000:
7995 case VENDOR_BROADCOM:
7996 break;
7997 default:
7998 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
7999 __FUNCTION__, venid));
8000 goto forcereturn;
8001 }
8002
8003 /* Check the Device ID and make sure it's one that we support */
8004 switch (devid) {
8005 case 0:
8006 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
8007 __FUNCTION__));
8008 break;
8009
8010 default:
8011 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
8012 __FUNCTION__, venid, devid));
8013 goto forcereturn;
8014 }
8015
8016 if (osh == NULL) {
8017 DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__));
8018 goto forcereturn;
8019 }
8020
8021 /* Allocate private bus interface state */
8022 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
8023 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
8024 goto fail;
8025 }
8026 bzero(bus, sizeof(dhd_bus_t));
8027 bus->sdh = sdh;
8028 bus->cl_devid = (uint16)devid;
8029 bus->bus = DHD_BUS;
8030 bus->bus_num = bus_no;
8031 bus->slot_num = slot;
8032 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
8033 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
8034 #ifdef BT_OVER_SDIO
8035 bus->bt_use_count = 0;
8036 #endif // endif
8037
8038 #if defined(SUPPORT_P2P_GO_PS)
8039 init_waitqueue_head(&bus->bus_sleep);
8040 #endif /* LINUX && SUPPORT_P2P_GO_PS */
8041 init_waitqueue_head(&bus->ctrl_tx_wait);
8042
8043 /* attempt to attach to the dongle */
8044 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
8045 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
8046 goto fail;
8047 }
8048
8049 /* Attach to the dhd/OS/network interface */
8050 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
8051 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
8052 goto fail;
8053 }
8054
8055 #if defined(GET_OTP_MAC_ENABLE) || defined(GET_OTP_MODULE_NAME)
8056 dhd_conf_get_otp(bus->dhd, sdh, bus->sih);
8057 #endif
8058
8059 /* Allocate buffers */
8060 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
8061 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
8062 goto fail;
8063 }
8064
8065 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
8066 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
8067 goto fail;
8068 }
8069
8070 if (bus->intr) {
8071 /* Register interrupt callback, but mask it (not operational yet). */
8072 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
8073 bcmsdh_intr_disable(sdh);
8074 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
8075 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
8076 __FUNCTION__, ret));
8077 goto fail;
8078 }
8079 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
8080 } else {
8081 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
8082 __FUNCTION__));
8083 }
8084
8085 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
8086
8087 /* if firmware path present try to download and bring up bus */
8088 bus->dhd->hang_report = TRUE;
8089 #if 0 // terence 20150325: fix for WPA/WPA2 4-way handshake fail in hostapd
8090 if (dhd_download_fw_on_driverload) {
8091 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
8092 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
8093 goto fail;
8094 }
8095 }
8096 else {
8097 /* Set random MAC address during boot time */
8098 get_random_bytes(&bus->dhd->mac.octet[3], 3);
8099 /* Adding BRCM OUI */
8100 bus->dhd->mac.octet[0] = 0;
8101 bus->dhd->mac.octet[1] = 0x90;
8102 bus->dhd->mac.octet[2] = 0x4C;
8103 }
8104 #endif
8105 #if defined(BT_OVER_SDIO)
8106 /* At this point Regulators are turned on and iconditionaly sdio bus is started
8107 * based upon dhd_download_fw_on_driverload check, so
8108 * increase the bus user count, this count will only be disabled inside
8109 * dhd_register_if() function if flag dhd_download_fw_on_driverload is set to false,
8110 * i.e FW download during insmod is not needed, otherwise it will not be decremented
8111 * so that WALN will always hold the bus untill rmmod is done.
8112 */
8113 dhdsdio_bus_usr_cnt_inc(bus->dhd);
8114 #endif /* BT_OVER_SDIO */
8115
8116 /* Ok, have the per-port tell the stack we're open for business */
8117 if (dhd_attach_net(bus->dhd, TRUE) != 0)
8118 {
8119 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
8120 goto fail;
8121 }
8122
8123 #ifdef BCMHOST_XTAL_PU_TIME_MOD
8124 bcmsdh_reg_write(bus->sdh, 0x18000620, 2, 11);
8125 bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x00F80001);
8126 #endif /* BCMHOST_XTAL_PU_TIME_MOD */
8127
8128 #if defined(MULTIPLE_SUPPLICANT)
8129 wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
8130 #endif /* MULTIPLE_SUPPLICANT */
8131 DHD_MUTEX_UNLOCK();
8132
8133 return bus;
8134
8135 fail:
8136 dhdsdio_release(bus, osh);
8137
8138 forcereturn:
8139 DHD_MUTEX_UNLOCK();
8140
8141 return NULL;
8142 }
8143
8144 static bool
dhdsdio_probe_attach(struct dhd_bus * bus,osl_t * osh,void * sdh,void * regsva,uint16 devid)8145 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
8146 uint16 devid)
8147 {
8148 #ifndef BCMSPI
8149 uint8 clkctl = 0;
8150 #endif /* !BCMSPI */
8151 uint fn, numfn;
8152 uint8 *cis[SDIOD_MAX_IOFUNCS];
8153 int32 value;
8154 int err = 0;
8155
8156 BCM_REFERENCE(value);
8157 bus->alp_only = TRUE;
8158 bus->sih = NULL;
8159
8160 /* Return the window to backplane enumeration space for core access */
8161 if (dhdsdio_set_siaddr_window(bus, si_enum_base(devid))) {
8162 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
8163 }
8164
8165 #if defined(DHD_DEBUG)
8166 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
8167 bcmsdh_reg_read(bus->sdh, si_enum_base(devid), 4)));
8168 #endif // endif
8169
8170 #ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. */
8171
8172 /* Force PLL off until si_attach() programs PLL control regs */
8173
8174 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
8175 if (!err)
8176 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
8177
8178 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
8179 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
8180 err, DHD_INIT_CLKCTL1, clkctl));
8181 goto fail;
8182 }
8183
8184 #endif /* !BCMSPI */
8185 #ifndef BCMSPI
8186 numfn = bcmsdh_query_iofnum(sdh);
8187 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
8188
8189 /* Make sure ALP is available before trying to read CIS */
8190 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
8191 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
8192 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
8193
8194 /* Now request ALP be put on the bus */
8195 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
8196 DHD_INIT_CLKCTL2, &err);
8197 OSL_DELAY(65);
8198 #else
8199 numfn = 0; /* internally func is hardcoded to 1 as gSPI has cis on F1 only */
8200 #endif /* !BCMSPI */
8201 #ifndef BCMSDIOLITE
8202 if (DHD_INFO_ON()) {
8203 for (fn = 0; fn <= numfn; fn++) {
8204 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
8205 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
8206 break;
8207 }
8208 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8209
8210 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn],
8211 SBSDIO_CIS_SIZE_LIMIT))) {
8212 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
8213 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8214 break;
8215 }
8216 #if 0
8217 /* Reading the F1, F2 and F3 max blocksize values from CIS
8218 * and writing into the F1, F2 and F3 block size registers.
8219 * There is no max block size register value available for F0 in CIS register.
8220 * So, setting default value for F0 block size as 32 (which was set earlier
8221 * in iovar). IOVAR takes only one arguement.
8222 * So, we are passing the function number alongwith the value (fn<<16)
8223 */
8224 if (!fn)
8225 value = F0_BLOCK_SIZE;
8226 else
8227 value = (cis[fn][25]<<8) | cis[fn][24] | (fn<<16);
8228 /* Get block size from sd */
8229 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fn, sizeof(int32),
8230 &size, sizeof(int32), FALSE) != BCME_OK) {
8231 size = 0;
8232 DHD_ERROR(("%s: fail on fn %d %s get\n",
8233 __FUNCTION__, fn, "sd_blocksize"));
8234 } else {
8235 DHD_INFO(("%s: Initial value for fn %d %s is %d\n",
8236 __FUNCTION__, fn, "sd_blocksize", size));
8237 }
8238 if (size != 0 && size < value) {
8239 value = size;
8240 }
8241 value = fn << 16 | value;
8242 if (bcmsdh_iovar_op(sdh, "sd_blocksize", NULL, 0, &value,
8243 sizeof(value), TRUE) != BCME_OK) {
8244 bus->blocksize = 0;
8245 DHD_ERROR(("%s: fail on fn %d %s set\n", __FUNCTION__,
8246 fn, "sd_blocksize"));
8247 }
8248 #endif
8249 #ifdef DHD_DEBUG
8250 if (DHD_INFO_ON()) {
8251 dhd_dump_cis(fn, cis[fn]);
8252 }
8253 #endif /* DHD_DEBUG */
8254 }
8255 while (fn-- > 0) {
8256 ASSERT(cis[fn]);
8257 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8258 }
8259 }
8260 #else
8261 BCM_REFERENCE(cis);
8262 BCM_REFERENCE(fn);
8263 #endif /* DHD_DEBUG */
8264
8265 if (err) {
8266 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
8267 goto fail;
8268 }
8269 /* si_attach() will provide an SI handle and scan the backplane */
8270 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
8271 &bus->vars, &bus->varsz))) {
8272 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
8273 goto fail;
8274 }
8275
8276 #ifdef DHD_DEBUG
8277 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
8278 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg));
8279 #endif /* DHD_DEBUG */
8280
8281 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
8282
8283 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
8284 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
8285 __FUNCTION__, bus->sih->chip));
8286 goto fail;
8287 }
8288
8289 if (bus->sih->buscorerev >= 12)
8290 dhdsdio_clk_kso_init(bus);
8291 else
8292 bus->kso = TRUE;
8293
8294 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
8295
8296 /* Get info on the ARM and SOCRAM cores... */
8297 if (!DHD_NOPMU(bus)) {
8298 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
8299 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
8300 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
8301 bus->armrev = si_corerev(bus->sih);
8302 } else {
8303 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
8304 goto fail;
8305 }
8306
8307 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8308 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
8309 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
8310 goto fail;
8311 }
8312 } else {
8313 /* cr4 has a different way to find the RAM size from TCM's */
8314 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
8315 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
8316 goto fail;
8317 }
8318 /* also populate base address */
8319 switch ((uint16)bus->sih->chip) {
8320 case BCM4335_CHIP_ID:
8321 case BCM4339_CHIP_ID:
8322 bus->dongle_ram_base = CR4_4335_RAM_BASE;
8323 break;
8324 case BCM4350_CHIP_ID:
8325 case BCM4354_CHIP_ID:
8326 case BCM4358_CHIP_ID:
8327 case BCM43569_CHIP_ID:
8328 case BCM4371_CHIP_ID:
8329 bus->dongle_ram_base = CR4_4350_RAM_BASE;
8330 break;
8331 case BCM4360_CHIP_ID:
8332 bus->dongle_ram_base = CR4_4360_RAM_BASE;
8333 break;
8334 CASE_BCM4345_CHIP:
8335 bus->dongle_ram_base = (bus->sih->chiprev < 6) /* from 4345C0 */
8336 ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
8337 break;
8338 case BCM4349_CHIP_GRPID:
8339 /* RAM based changed from 4349c0(revid=9) onwards */
8340 bus->dongle_ram_base = ((bus->sih->chiprev < 9) ?
8341 CR4_4349_RAM_BASE: CR4_4349_RAM_BASE_FROM_REV_9);
8342 break;
8343 case BCM4364_CHIP_ID:
8344 bus->dongle_ram_base = CR4_4364_RAM_BASE;
8345 break;
8346 case BCM4362_CHIP_ID:
8347 bus->dongle_ram_base = CR4_4362_RAM_BASE;
8348 break;
8349 case BCM43751_CHIP_ID:
8350 bus->dongle_ram_base = CR4_43751_RAM_BASE;
8351 break;
8352 case BCM43752_CHIP_ID:
8353 bus->dongle_ram_base = CR4_43752_RAM_BASE;
8354 break;
8355 case BCM4369_CHIP_ID:
8356 bus->dongle_ram_base = CR4_4369_RAM_BASE;
8357 break;
8358 default:
8359 bus->dongle_ram_base = 0;
8360 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
8361 __FUNCTION__, bus->dongle_ram_base));
8362 }
8363 }
8364 bus->ramsize = bus->orig_ramsize;
8365 if (dhd_dongle_ramsize)
8366 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
8367
8368 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
8369 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
8370
8371 bus->srmemsize = si_socram_srmem_size(bus->sih);
8372 }
8373
8374 /* ...but normally deal with the SDPCMDEV core */
8375 #ifdef BCMSDIOLITE
8376 if (!(bus->regs = si_setcore(bus->sih, CC_CORE_ID, 0))) {
8377 DHD_ERROR(("%s: failed to find Chip Common core!\n", __FUNCTION__));
8378 goto fail;
8379 }
8380 #else
8381 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
8382 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
8383 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
8384 goto fail;
8385 }
8386 #endif // endif
8387 bus->sdpcmrev = si_corerev(bus->sih);
8388
8389 /* Set core control so an SDIO reset does a backplane reset */
8390 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
8391 #ifndef BCMSPI
8392 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
8393
8394 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
8395 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
8396 {
8397 uint32 val;
8398
8399 val = R_REG(osh, &bus->regs->corecontrol);
8400 val &= ~CC_XMTDATAAVAIL_MODE;
8401 val |= CC_XMTDATAAVAIL_CTRL;
8402 W_REG(osh, &bus->regs->corecontrol, val);
8403 }
8404 #endif /* BCMSPI */
8405
8406 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
8407
8408 /* Locate an appropriately-aligned portion of hdrbuf */
8409 #ifndef DYNAMIC_MAX_HDR_READ
8410 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
8411 #endif
8412
8413 /* Set the poll and/or interrupt flags */
8414 bus->intr = (bool)dhd_intr;
8415 if ((bus->poll = (bool)dhd_poll))
8416 bus->pollrate = 1;
8417
8418 /* Setting default Glom size */
8419 bus->txglomsize = SDPCM_DEFGLOM_SIZE;
8420
8421 return TRUE;
8422
8423 fail:
8424 if (bus->sih != NULL) {
8425 si_detach(bus->sih);
8426 bus->sih = NULL;
8427 }
8428 return FALSE;
8429 }
8430
8431 static bool
dhdsdio_probe_malloc(dhd_bus_t * bus,osl_t * osh,void * sdh)8432 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
8433 {
8434 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8435
8436 if (bus->dhd->maxctl) {
8437 bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
8438 if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) {
8439 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
8440 __FUNCTION__, bus->rxblen));
8441 goto fail;
8442 }
8443 }
8444 /* Allocate buffer to receive glomed packet */
8445 if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
8446 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
8447 __FUNCTION__, MAX_DATA_BUF));
8448 /* release rxbuf which was already located as above */
8449 if (!bus->rxblen)
8450 DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
8451 goto fail;
8452 }
8453 /* Allocate buffer to membuf */
8454 bus->membuf = MALLOC(osh, MAX_MEM_BUF);
8455 if (bus->membuf == NULL) {
8456 DHD_ERROR(("%s: MALLOC of %d-byte membuf failed\n",
8457 __FUNCTION__, MAX_MEM_BUF));
8458 if (bus->databuf) {
8459 #ifndef CONFIG_DHD_USE_STATIC_BUF
8460 MFREE(osh, bus->databuf, MAX_DATA_BUF);
8461 #endif
8462 bus->databuf = NULL;
8463 }
8464 /* release rxbuf which was already located as above */
8465 if (!bus->rxblen)
8466 DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
8467 goto fail;
8468 }
8469 memset(bus->membuf, 0, MAX_MEM_BUF);
8470
8471 /* Align the buffer */
8472 if ((uintptr)bus->databuf % DHD_SDALIGN)
8473 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
8474 else
8475 bus->dataptr = bus->databuf;
8476
8477 return TRUE;
8478
8479 fail:
8480 return FALSE;
8481 }
8482
8483 static bool
dhdsdio_probe_init(dhd_bus_t * bus,osl_t * osh,void * sdh)8484 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
8485 {
8486 int32 fnum;
8487
8488 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8489
8490 bus->_srenab = FALSE;
8491
8492 #ifdef SDTEST
8493 dhdsdio_pktgen_init(bus);
8494 #endif /* SDTEST */
8495
8496 #ifndef BCMSPI
8497 /* Disable F2 to clear any intermediate frame state on the dongle */
8498 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
8499 #endif /* !BCMSPI */
8500
8501 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
8502 bus->dhd->busstate = DHD_BUS_DOWN;
8503 bus->sleeping = FALSE;
8504 bus->rxflow = FALSE;
8505 bus->prev_rxlim_hit = 0;
8506
8507 #ifndef BCMSPI
8508 /* Done with backplane-dependent accesses, can drop clock... */
8509 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
8510 #endif /* !BCMSPI */
8511
8512 /* ...and initialize clock/power states */
8513 bus->clkstate = CLK_SDONLY;
8514 bus->idletime = (int32)dhd_idletime;
8515 bus->idleclock = DHD_IDLE_ACTIVE;
8516
8517 /* Query the SD clock speed */
8518 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
8519 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
8520 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
8521 bus->sd_divisor = -1;
8522 } else {
8523 DHD_INFO(("%s: Initial value for %s is %d\n",
8524 __FUNCTION__, "sd_divisor", bus->sd_divisor));
8525 }
8526
8527 /* Query the SD bus mode */
8528 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
8529 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
8530 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
8531 bus->sd_mode = -1;
8532 } else {
8533 DHD_INFO(("%s: Initial value for %s is %d\n",
8534 __FUNCTION__, "sd_mode", bus->sd_mode));
8535 }
8536
8537 /* Query the F2 block size, set roundup accordingly */
8538 fnum = 2;
8539 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
8540 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
8541 bus->blocksize = 0;
8542 DHD_ERROR(("%s: fail on fn %d %s get\n", __FUNCTION__, fnum, "sd_blocksize"));
8543 } else {
8544 DHD_INFO(("%s: Initial value for fn %d %s is %d\n",
8545 __FUNCTION__, fnum, "sd_blocksize", bus->blocksize));
8546
8547 dhdsdio_tune_fifoparam(bus);
8548 }
8549 bus->roundup = MIN(max_roundup, bus->blocksize);
8550
8551 #ifdef DHDENABLE_TAILPAD
8552 if (bus->pad_pkt)
8553 PKTFREE(osh, bus->pad_pkt, FALSE);
8554 bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE);
8555 if (bus->pad_pkt == NULL)
8556 DHD_ERROR(("failed to allocate padding packet\n"));
8557 else {
8558 int alignment_offset = 0;
8559 uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt);
8560 if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN)))
8561 PKTPUSH(osh, bus->pad_pkt, alignment_offset);
8562 PKTSETNEXT(osh, bus->pad_pkt, NULL);
8563 }
8564 #endif /* DHDENABLE_TAILPAD */
8565
8566 /* Query if bus module supports packet chaining, default to use if supported */
8567 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
8568 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
8569 bus->sd_rxchain = FALSE;
8570 } else {
8571 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
8572 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
8573 }
8574 bus->use_rxchain = (bool)bus->sd_rxchain;
8575 bus->txinrx_thres = CUSTOM_TXINRX_THRES;
8576 /* TX first in dhdsdio_readframes() */
8577 bus->dotxinrx = TRUE;
8578
8579 #ifdef PKT_STATICS
8580 dhd_bus_clear_txpktstatics(bus);
8581 #endif
8582
8583 return TRUE;
8584 }
8585
8586 int
dhd_bus_download_firmware(struct dhd_bus * bus,osl_t * osh,char * pfw_path,char * pnv_path,char * pclm_path,char * pconf_path)8587 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
8588 char *pfw_path, char *pnv_path,
8589 char *pclm_path, char *pconf_path)
8590 {
8591 int ret;
8592
8593 bus->fw_path = pfw_path;
8594 bus->nv_path = pnv_path;
8595 bus->dhd->clm_path = pclm_path;
8596 bus->dhd->conf_path = pconf_path;
8597
8598 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
8599
8600 return ret;
8601 }
8602
8603 int
dhd_set_bus_params(struct dhd_bus * bus)8604 dhd_set_bus_params(struct dhd_bus *bus)
8605 {
8606 int ret = 0;
8607
8608 if (bus->dhd->conf->dhd_poll >= 0) {
8609 bus->poll = bus->dhd->conf->dhd_poll;
8610 if (!bus->pollrate)
8611 bus->pollrate = 1;
8612 printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll);
8613 }
8614 if (bus->dhd->conf->use_rxchain >= 0) {
8615 bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
8616 }
8617 if (bus->dhd->conf->txinrx_thres >= 0) {
8618 bus->txinrx_thres = bus->dhd->conf->txinrx_thres;
8619 }
8620 if (bus->dhd->conf->txglomsize >= 0) {
8621 bus->txglomsize = bus->dhd->conf->txglomsize;
8622 }
8623 #ifdef MINIME
8624 if (bus->dhd->conf->fw_type == FW_TYPE_MINIME) {
8625 bus->ramsize = bus->dhd->conf->ramsize;
8626 printf("%s: set ramsize 0x%x\n", __FUNCTION__, bus->ramsize);
8627 }
8628 #endif
8629 #ifdef DYNAMIC_MAX_HDR_READ
8630 if (bus->dhd->conf->max_hdr_read <= 0) {
8631 bus->dhd->conf->max_hdr_read = MAX_HDR_READ;
8632 }
8633 if (bus->hdrbufp) {
8634 MFREE(bus->dhd->osh, bus->hdrbufp, bus->dhd->conf->max_hdr_read + DHD_SDALIGN);
8635 }
8636 bus->hdrbufp = MALLOC(bus->dhd->osh, bus->dhd->conf->max_hdr_read + DHD_SDALIGN);
8637 if (bus->hdrbufp == NULL) {
8638 DHD_ERROR(("%s: MALLOC of %d-byte hdrbufp failed\n",
8639 __FUNCTION__, bus->dhd->conf->max_hdr_read + DHD_SDALIGN));
8640 ret = -1;
8641 goto exit;
8642 }
8643 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)bus->hdrbufp, DHD_SDALIGN);
8644
8645 exit:
8646 #endif
8647 return ret;
8648 }
8649
8650 static int
dhdsdio_download_firmware(struct dhd_bus * bus,osl_t * osh,void * sdh)8651 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
8652 {
8653 int ret;
8654
8655 #if defined(SUPPORT_MULTIPLE_REVISION)
8656 if (concate_revision(bus, bus->fw_path, bus->nv_path) != 0) {
8657 DHD_ERROR(("%s: fail to concatnate revison \n",
8658 __FUNCTION__));
8659 return BCME_BADARG;
8660 }
8661 #endif /* SUPPORT_MULTIPLE_REVISION */
8662
8663 #if defined(DHD_BLOB_EXISTENCE_CHECK)
8664 dhd_set_blob_support(bus->dhd, bus->fw_path);
8665 #endif /* DHD_BLOB_EXISTENCE_CHECK */
8666
8667 DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
8668 __FUNCTION__, bus->fw_path, bus->nv_path));
8669 DHD_OS_WAKE_LOCK(bus->dhd);
8670
8671 dhd_conf_set_path_params(bus->dhd, bus->fw_path, bus->nv_path);
8672 ret = dhd_set_bus_params(bus);
8673 if (ret) {
8674 goto exit;
8675 }
8676
8677 /* Download the firmware */
8678 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8679
8680 ret = _dhdsdio_download_firmware(bus);
8681
8682 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8683
8684 exit:
8685 DHD_OS_WAKE_UNLOCK(bus->dhd);
8686 return ret;
8687 }
8688
8689 /* Detach and free everything */
8690 static void
dhdsdio_release(dhd_bus_t * bus,osl_t * osh)8691 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
8692 {
8693 bool dongle_isolation = FALSE;
8694 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8695
8696 if (bus) {
8697 ASSERT(osh);
8698
8699 if (bus->dhd) {
8700 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
8701 debugger_close();
8702 #endif /* DEBUGGER || DHD_DSCOPE */
8703 dongle_isolation = bus->dhd->dongle_isolation;
8704 dhd_detach(bus->dhd);
8705 }
8706
8707 /* De-register interrupt handler */
8708 bcmsdh_intr_disable(bus->sdh);
8709 bcmsdh_intr_dereg(bus->sdh);
8710
8711 if (bus->dhd) {
8712 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
8713 dhd_free(bus->dhd);
8714 bus->dhd = NULL;
8715 }
8716
8717 dhdsdio_release_malloc(bus, osh);
8718
8719 #ifdef DHD_DEBUG
8720 if (bus->console.buf != NULL)
8721 MFREE(osh, bus->console.buf, bus->console.bufsize);
8722 #endif // endif
8723
8724 #ifdef DHDENABLE_TAILPAD
8725 if (bus->pad_pkt)
8726 PKTFREE(osh, bus->pad_pkt, FALSE);
8727 #endif /* DHDENABLE_TAILPAD */
8728 #ifdef DYNAMIC_MAX_HDR_READ
8729 if (bus->hdrbufp) {
8730 MFREE(osh, bus->hdrbufp, MAX_HDR_READ + DHD_SDALIGN);
8731 }
8732 #endif
8733
8734 MFREE(osh, bus, sizeof(dhd_bus_t));
8735 }
8736
8737 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8738 }
8739
8740 static void
dhdsdio_release_malloc(dhd_bus_t * bus,osl_t * osh)8741 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
8742 {
8743 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8744
8745 if (bus->dhd && bus->dhd->dongle_reset)
8746 return;
8747
8748 if (bus->rxbuf) {
8749 #ifndef CONFIG_DHD_USE_STATIC_BUF
8750 MFREE(osh, bus->rxbuf, bus->rxblen);
8751 #endif // endif
8752 bus->rxctl = bus->rxbuf = NULL;
8753 bus->rxlen = 0;
8754 }
8755
8756 if (bus->databuf) {
8757 #ifndef CONFIG_DHD_USE_STATIC_BUF
8758 MFREE(osh, bus->databuf, MAX_DATA_BUF);
8759 #endif // endif
8760 bus->databuf = NULL;
8761 }
8762
8763 if (bus->membuf) {
8764 MFREE(osh, bus->membuf, MAX_DATA_BUF);
8765 bus->membuf = NULL;
8766 }
8767
8768 if (bus->vars && bus->varsz) {
8769 MFREE(osh, bus->vars, bus->varsz);
8770 bus->vars = NULL;
8771 }
8772
8773 }
8774
8775 static void
dhdsdio_release_dongle(dhd_bus_t * bus,osl_t * osh,bool dongle_isolation,bool reset_flag)8776 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
8777 {
8778 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
8779 bus->dhd, bus->dhd->dongle_reset));
8780
8781 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
8782 return;
8783
8784 if (bus->sih) {
8785 /* In Win10, system will be BSOD if using "sysprep" to do OS image */
8786 /* Skip this will not cause the BSOD. */
8787 #if !defined(BCMLXSDMMC)
8788 if (bus->dhd) {
8789 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8790 }
8791 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
8792 si_watchdog(bus->sih, 4);
8793 #endif /* !defined(BCMLXSDMMC) */
8794 if (bus->dhd) {
8795 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
8796 }
8797 si_detach(bus->sih);
8798 bus->sih = NULL;
8799 if (bus->vars && bus->varsz)
8800 MFREE(osh, bus->vars, bus->varsz);
8801 bus->vars = NULL;
8802 }
8803
8804 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8805 }
8806
8807 static void
dhdsdio_disconnect(void * ptr)8808 dhdsdio_disconnect(void *ptr)
8809 {
8810 dhd_bus_t *bus = (dhd_bus_t *)ptr;
8811
8812 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8813
8814 DHD_MUTEX_LOCK();
8815 if (bus) {
8816 ASSERT(bus->dhd);
8817 /* Advertise bus remove during rmmod */
8818 dhdsdio_advertise_bus_remove(bus->dhd);
8819 dhdsdio_release(bus, bus->dhd->osh);
8820 }
8821 DHD_MUTEX_UNLOCK();
8822
8823 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8824 }
8825
8826 static int
dhdsdio_suspend(void * context)8827 dhdsdio_suspend(void *context)
8828 {
8829 int ret = 0;
8830 #ifdef SUPPORT_P2P_GO_PS
8831 int wait_time = 0;
8832 #endif /* SUPPORT_P2P_GO_PS */
8833
8834 dhd_bus_t *bus = (dhd_bus_t*)context;
8835 unsigned long flags;
8836
8837 DHD_ERROR(("%s Enter\n", __FUNCTION__));
8838 if (bus->dhd == NULL) {
8839 DHD_ERROR(("bus not inited\n"));
8840 return BCME_ERROR;
8841 }
8842 if (bus->dhd->prot == NULL) {
8843 DHD_ERROR(("prot is not inited\n"));
8844 return BCME_ERROR;
8845 }
8846
8847 if (bus->dhd->up == FALSE) {
8848 return BCME_OK;
8849 }
8850
8851 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8852 if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) {
8853 DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
8854 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8855 return BCME_ERROR;
8856 }
8857 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8858 if (bus->dhd->dongle_reset) {
8859 DHD_ERROR(("Dongle is in reset state.\n"));
8860 return -EIO;
8861 }
8862
8863 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8864 /* stop all interface network queue. */
8865 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8866 bus->dhd->busstate = DHD_BUS_SUSPEND;
8867 if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) {
8868 DHD_ERROR(("Tx Request is not ended\n"));
8869 bus->dhd->busstate = DHD_BUS_DATA;
8870 /* resume all interface network queue. */
8871 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8872 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8873 return -EBUSY;
8874 }
8875 DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd);
8876 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8877
8878 #ifdef SUPPORT_P2P_GO_PS
8879 if (bus->idletime > 0) {
8880 wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
8881 }
8882 #endif /* SUPPORT_P2P_GO_PS */
8883 ret = dhd_os_check_wakelock(bus->dhd);
8884 #ifdef SUPPORT_P2P_GO_PS
8885 // terence 20141124: fix for suspend issue
8886 if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) {
8887 if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
8888 if (!bus->sleeping) {
8889 ret = 1;
8890 }
8891 }
8892 }
8893 #endif /* SUPPORT_P2P_GO_PS */
8894
8895 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8896 if (ret) {
8897 bus->dhd->busstate = DHD_BUS_DATA;
8898 /* resume all interface network queue. */
8899 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8900 }
8901 DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd);
8902 dhd_os_busbusy_wake(bus->dhd);
8903 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8904 return ret;
8905 }
8906
8907 static int
dhdsdio_resume(void * context)8908 dhdsdio_resume(void *context)
8909 {
8910 dhd_bus_t *bus = (dhd_bus_t*)context;
8911 ulong flags;
8912
8913 DHD_ERROR(("%s Enter\n", __FUNCTION__));
8914
8915 if (bus->dhd->up == FALSE) {
8916 return BCME_OK;
8917 }
8918
8919 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8920 DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd);
8921 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8922
8923 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
8924 if (dhd_os_check_if_up(bus->dhd))
8925 bcmsdh_oob_intr_set(bus->sdh, TRUE);
8926 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
8927
8928 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8929 DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd);
8930 bus->dhd->busstate = DHD_BUS_DATA;
8931 dhd_os_busbusy_wake(bus->dhd);
8932 /* resume all interface network queue. */
8933 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8934 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8935
8936 return 0;
8937 }
8938
8939 /* Register/Unregister functions are called by the main DHD entry
8940 * point (e.g. module insertion) to link with the bus driver, in
8941 * order to look for or await the device.
8942 */
8943
8944 static bcmsdh_driver_t dhd_sdio = {
8945 dhdsdio_probe,
8946 dhdsdio_disconnect,
8947 dhdsdio_suspend,
8948 dhdsdio_resume
8949 };
8950
8951 int
dhd_bus_register(void)8952 dhd_bus_register(void)
8953 {
8954 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8955
8956 return bcmsdh_register(&dhd_sdio);
8957 }
8958
8959 void
dhd_bus_unregister(void)8960 dhd_bus_unregister(void)
8961 {
8962 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8963
8964 bcmsdh_unregister();
8965 }
8966
8967 #if defined(BCMLXSDMMC)
8968 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
dhd_bus_reg_sdio_notify(void * semaphore)8969 int dhd_bus_reg_sdio_notify(void* semaphore)
8970 {
8971 return bcmsdh_reg_sdio_notify(semaphore);
8972 }
8973
dhd_bus_unreg_sdio_notify(void)8974 void dhd_bus_unreg_sdio_notify(void)
8975 {
8976 bcmsdh_unreg_sdio_notify();
8977 }
8978 #endif /* defined(BCMLXSDMMC) */
8979
8980 static int
dhdsdio_download_code_file(struct dhd_bus * bus,char * pfw_path)8981 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
8982 {
8983 int bcmerror = -1;
8984 int offset = 0;
8985 int len;
8986 void *image = NULL;
8987 uint8 *memblock = NULL, *memptr;
8988 uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
8989 uint memblock_size = MEMBLOCK;
8990 #ifdef DHD_DEBUG_DOWNLOADTIME
8991 unsigned long initial_jiffies = 0;
8992 uint firmware_sz = 0;
8993 #endif // endif
8994
8995 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
8996
8997 image = dhd_os_open_image1(bus->dhd, pfw_path);
8998 if (image == NULL) {
8999 printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
9000 goto err;
9001 }
9002
9003 /* Update the dongle image download block size depending on the F1 block size */
9004 if (sd_f1_blocksize == 512)
9005 memblock_size = MAX_MEMBLOCK;
9006 memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN);
9007 if (memblock == NULL) {
9008 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
9009 memblock_size));
9010 goto err;
9011 }
9012 if (dhd_msg_level & DHD_TRACE_VAL) {
9013 memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
9014 if (memptr_tmp == NULL) {
9015 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
9016 goto err;
9017 }
9018 }
9019 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
9020 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
9021
9022 #ifdef DHD_DEBUG_DOWNLOADTIME
9023 initial_jiffies = jiffies;
9024 #endif // endif
9025
9026 /* Download image */
9027 while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, image))) {
9028 // terence 20150412: fix for firmware failed to download
9029 if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
9030 bus->dhd->conf->chip == BCM43341_CHIP_ID) {
9031 if (len % 64 != 0) {
9032 memset(memptr+len, 0, len%64);
9033 len += (64 - len%64);
9034 }
9035 }
9036 if (len < 0) {
9037 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
9038 bcmerror = BCME_ERROR;
9039 goto err;
9040 }
9041 /* check if CR4 */
9042 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
9043 /* if address is 0, store the reset instruction to be written in 0 */
9044
9045 if (offset == 0) {
9046 bus->resetinstr = *(((uint32*)memptr));
9047 /* Add start of RAM address to the address given by user */
9048 offset += bus->dongle_ram_base;
9049 }
9050 }
9051
9052 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
9053 if (bcmerror) {
9054 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9055 __FUNCTION__, bcmerror, memblock_size, offset));
9056 goto err;
9057 }
9058
9059 if (dhd_msg_level & DHD_TRACE_VAL) {
9060 bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len);
9061 if (bcmerror) {
9062 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
9063 __FUNCTION__, bcmerror, MEMBLOCK, offset));
9064 goto err;
9065 }
9066 if (memcmp(memptr_tmp, memptr, len)) {
9067 DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
9068 goto err;
9069 } else
9070 DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
9071 }
9072
9073 offset += memblock_size;
9074 #ifdef DHD_DEBUG_DOWNLOADTIME
9075 firmware_sz += len;
9076 #endif // endif
9077 }
9078
9079 #ifdef DHD_DEBUG_DOWNLOADTIME
9080 DHD_ERROR(("Firmware download time for %u bytes: %u ms\n",
9081 firmware_sz, jiffies_to_msecs(jiffies - initial_jiffies)));
9082 #endif // endif
9083
9084 err:
9085 if (memblock)
9086 MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN);
9087 if (dhd_msg_level & DHD_TRACE_VAL) {
9088 if (memptr_tmp)
9089 MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
9090 }
9091
9092 if (image)
9093 dhd_os_close_image1(bus->dhd, image);
9094
9095 return bcmerror;
9096 }
9097
9098 #ifdef DHD_UCODE_DOWNLOAD
9099 /* Currently supported only for the chips in which ucode RAM is AXI addressable */
9100 static uint32
dhdsdio_ucode_base(struct dhd_bus * bus)9101 dhdsdio_ucode_base(struct dhd_bus *bus)
9102 {
9103 uint32 ucode_base = 0;
9104
9105 switch ((uint16)bus->sih->chip) {
9106 case BCM43012_CHIP_ID:
9107 ucode_base = 0xE8020000;
9108 break;
9109 default:
9110 DHD_ERROR(("%s: Unsupported!\n", __func__));
9111 break;
9112 }
9113
9114 return ucode_base;
9115 }
9116
9117 static int
dhdsdio_download_ucode_file(struct dhd_bus * bus,char * ucode_path)9118 dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path)
9119 {
9120 int bcmerror = -1;
9121 int offset = 0;
9122 int len;
9123 uint32 ucode_base;
9124 void *image = NULL;
9125 uint8 *memblock = NULL, *memptr;
9126 uint memblock_size = MEMBLOCK;
9127 #ifdef DHD_DEBUG_DOWNLOADTIME
9128 unsigned long initial_jiffies = 0;
9129 uint firmware_sz = 0;
9130 #endif // endif
9131
9132 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, ucode_path));
9133
9134 ucode_base = dhdsdio_ucode_base(bus);
9135
9136 image = dhd_os_open_image1(bus->dhd, ucode_path);
9137 if (image == NULL)
9138 goto err;
9139
9140 /* Update the dongle image download block size depending on the F1 block size */
9141 if (sd_f1_blocksize == 512)
9142 memblock_size = MAX_MEMBLOCK;
9143
9144 memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN);
9145 if (memblock == NULL) {
9146 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
9147 memblock_size));
9148 goto err;
9149 }
9150 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
9151 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
9152
9153 #ifdef DHD_DEBUG_DOWNLOADTIME
9154 initial_jiffies = jiffies;
9155 #endif // endif
9156
9157 /* Download image */
9158 while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, image))) {
9159 if (len < 0) {
9160 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
9161 bcmerror = BCME_ERROR;
9162 goto err;
9163 }
9164
9165 bcmerror = dhdsdio_membytes(bus, TRUE, (ucode_base + offset), memptr, len);
9166 if (bcmerror) {
9167 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9168 __FUNCTION__, bcmerror, memblock_size, offset));
9169 goto err;
9170 }
9171
9172 offset += memblock_size;
9173 #ifdef DHD_DEBUG_DOWNLOADTIME
9174 firmware_sz += len;
9175 #endif // endif
9176 }
9177
9178 #ifdef DHD_DEBUG_DOWNLOADTIME
9179 DHD_ERROR(("ucode download time for %u bytes: %u ms\n",
9180 firmware_sz, jiffies_to_msecs(jiffies - initial_jiffies)));
9181 #endif // endif
9182
9183 err:
9184 if (memblock)
9185 MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN);
9186
9187 if (image)
9188 dhd_os_close_image1(bus->dhd, image);
9189
9190 return bcmerror;
9191 } /* dhdsdio_download_ucode_file */
9192
9193 void
dhd_bus_ucode_download(struct dhd_bus * bus)9194 dhd_bus_ucode_download(struct dhd_bus *bus)
9195 {
9196 uint32 shaddr = 0, shdata = 0;
9197
9198 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
9199 dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&shdata, 4);
9200
9201 DHD_TRACE(("%s: shdata:[0x%08x :0x%08x]\n", __func__, shaddr, shdata));
9202
9203 if (shdata == UCODE_DOWNLOAD_REQUEST)
9204 {
9205 DHD_ERROR(("%s: Received ucode download request!\n", __func__));
9206
9207 /* Download the ucode */
9208 if (!dhd_get_ucode_path(bus->dhd)) {
9209 DHD_ERROR(("%s: bus->uc_path not set!\n", __func__));
9210 return;
9211 }
9212 dhdsdio_download_ucode_file(bus, dhd_get_ucode_path(bus->dhd));
9213
9214 DHD_ERROR(("%s: Ucode downloaded successfully!\n", __func__));
9215
9216 shdata = UCODE_DOWNLOAD_COMPLETE;
9217 dhdsdio_membytes(bus, TRUE, shaddr, (uint8 *)&shdata, 4);
9218 }
9219 }
9220
9221 #endif /* DHD_UCODE_DOWNLOAD */
9222
9223 static int
dhdsdio_download_nvram(struct dhd_bus * bus)9224 dhdsdio_download_nvram(struct dhd_bus *bus)
9225 {
9226 int bcmerror = -1;
9227 uint len;
9228 void * image = NULL;
9229 char * memblock = NULL;
9230 char *bufp;
9231 char *pnv_path;
9232 bool nvram_file_exists;
9233
9234 pnv_path = bus->nv_path;
9235
9236 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
9237
9238 /* For Get nvram from UEFI */
9239 if (nvram_file_exists) {
9240 image = dhd_os_open_image1(bus->dhd, pnv_path);
9241 if (image == NULL) {
9242 printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
9243 goto err;
9244 }
9245 }
9246
9247 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
9248 if (memblock == NULL) {
9249 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
9250 __FUNCTION__, MAX_NVRAMBUF_SIZE));
9251 goto err;
9252 }
9253
9254 /* For Get nvram from image or UEFI (when image == NULL ) */
9255 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
9256
9257 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
9258 bufp = (char *)memblock;
9259 bufp[len] = 0;
9260 len = process_nvram_vars(bufp, len);
9261 if (len % 4) {
9262 len += 4 - (len % 4);
9263 }
9264 bufp += len;
9265 *bufp++ = 0;
9266 if (len)
9267 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
9268 if (bcmerror) {
9269 DHD_ERROR(("%s: error downloading vars: %d\n",
9270 __FUNCTION__, bcmerror));
9271 }
9272 } else {
9273 DHD_ERROR(("%s: error reading nvram file: %d\n",
9274 __FUNCTION__, len));
9275 bcmerror = BCME_SDIO_ERROR;
9276 }
9277
9278 err:
9279 if (memblock)
9280 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
9281
9282 if (image)
9283 dhd_os_close_image1(bus->dhd, image);
9284
9285 return bcmerror;
9286 }
9287
9288 static int
_dhdsdio_download_firmware(struct dhd_bus * bus)9289 _dhdsdio_download_firmware(struct dhd_bus *bus)
9290 {
9291 int bcmerror = -1;
9292
9293 bool embed = FALSE; /* download embedded firmware */
9294 bool dlok = FALSE; /* download firmware succeeded */
9295
9296 /* Out immediately if no image to download */
9297 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
9298 return bcmerror;
9299 }
9300
9301 /* Keep arm in reset */
9302 if (dhdsdio_download_state(bus, TRUE)) {
9303 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
9304 goto err;
9305 }
9306
9307 /* External image takes precedence if specified */
9308 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
9309 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
9310 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
9311 goto err;
9312 } else {
9313 embed = FALSE;
9314 dlok = TRUE;
9315 }
9316 }
9317
9318 BCM_REFERENCE(embed);
9319 if (!dlok) {
9320 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
9321 goto err;
9322 }
9323
9324 /* External nvram takes precedence if specified */
9325 if (dhdsdio_download_nvram(bus)) {
9326 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
9327 goto err;
9328 }
9329
9330 /* Take arm out of reset */
9331 if (dhdsdio_download_state(bus, FALSE)) {
9332 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
9333 goto err;
9334 }
9335
9336 bcmerror = 0;
9337
9338 err:
9339 return bcmerror;
9340 }
9341
9342 static int
dhd_bcmsdh_recv_buf(dhd_bus_t * bus,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete_fn,void * handle)9343 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
9344 void *pkt, bcmsdh_cmplt_fn_t complete_fn, void *handle)
9345 {
9346 int status;
9347
9348 if (!KSO_ENAB(bus)) {
9349 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
9350 return BCME_NODEVICE;
9351 }
9352
9353 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete_fn, handle);
9354
9355 return status;
9356 }
9357
9358 static int
dhd_bcmsdh_send_buf(dhd_bus_t * bus,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete_fn,void * handle,int max_retry)9359 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
9360 void *pkt, bcmsdh_cmplt_fn_t complete_fn, void *handle, int max_retry)
9361 {
9362 int ret;
9363 int i = 0;
9364 int retries = 0;
9365 bcmsdh_info_t *sdh;
9366
9367 if (!KSO_ENAB(bus)) {
9368 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
9369 return BCME_NODEVICE;
9370 }
9371
9372 sdh = bus->sdh;
9373 do {
9374 ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes,
9375 pkt, complete_fn, handle);
9376
9377 bus->f2txdata++;
9378 ASSERT(ret != BCME_PENDING);
9379
9380 if (ret == BCME_NODEVICE) {
9381 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
9382 } else if (ret < 0) {
9383 /* On failure, abort the command and terminate the frame */
9384 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
9385 __FUNCTION__, ret));
9386 bus->tx_sderrs++;
9387 bus->f1regdata++;
9388 bus->dhd->tx_errors++;
9389 bcmsdh_abort(sdh, SDIO_FUNC_2);
9390 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
9391 SFC_WF_TERM, NULL);
9392 for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
9393 uint8 hi, lo;
9394 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
9395 NULL);
9396 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
9397 NULL);
9398 bus->f1regdata += 2;
9399 if ((hi == 0) && (lo == 0))
9400 break;
9401 }
9402 }
9403 } while ((ret < 0) && retrydata && ++retries < max_retry);
9404
9405 return ret;
9406 }
9407
9408 uint8
dhd_bus_is_ioready(struct dhd_bus * bus)9409 dhd_bus_is_ioready(struct dhd_bus *bus)
9410 {
9411 uint8 enable;
9412 bcmsdh_info_t *sdh;
9413 ASSERT(bus);
9414 ASSERT(bus->sih != NULL);
9415 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
9416 sdh = bus->sdh;
9417 return (enable == bcmsdh_cfg_read(sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL));
9418 }
9419
9420 uint
dhd_bus_chip(struct dhd_bus * bus)9421 dhd_bus_chip(struct dhd_bus *bus)
9422 {
9423 ASSERT(bus->sih != NULL);
9424 return bus->sih->chip;
9425 }
9426
9427 uint
dhd_bus_chiprev(struct dhd_bus * bus)9428 dhd_bus_chiprev(struct dhd_bus *bus)
9429 {
9430 ASSERT(bus);
9431 ASSERT(bus->sih != NULL);
9432 return bus->sih->chiprev;
9433 }
9434
9435 void *
dhd_bus_pub(struct dhd_bus * bus)9436 dhd_bus_pub(struct dhd_bus *bus)
9437 {
9438 return bus->dhd;
9439 }
9440
9441 void *
dhd_bus_sih(struct dhd_bus * bus)9442 dhd_bus_sih(struct dhd_bus *bus)
9443 {
9444 return (void *)bus->sih;
9445 }
9446
9447 void *
dhd_bus_txq(struct dhd_bus * bus)9448 dhd_bus_txq(struct dhd_bus *bus)
9449 {
9450 return &bus->txq;
9451 }
9452
9453 uint
dhd_bus_hdrlen(struct dhd_bus * bus)9454 dhd_bus_hdrlen(struct dhd_bus *bus)
9455 {
9456 return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
9457 }
9458
9459 void
dhd_bus_set_dotxinrx(struct dhd_bus * bus,bool val)9460 dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val)
9461 {
9462 bus->dotxinrx = val;
9463 }
9464
9465 /*
9466 * dhdsdio_advertise_bus_cleanup advertises that clean up is under progress
9467 * to other bus user contexts like Tx, Rx, IOVAR, WD etc and it waits for other contexts
9468 * to gracefully exit. All the bus usage contexts before marking busstate as busy, will check for
9469 * whether the busstate is DHD_BUS_DOWN or DHD_BUS_DOWN_IN_PROGRESS, if so
9470 * they will exit from there itself without marking dhd_bus_busy_state as BUSY.
9471 */
9472 static void
dhdsdio_advertise_bus_cleanup(dhd_pub_t * dhdp)9473 dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp)
9474 {
9475 unsigned long flags;
9476 int timeleft;
9477
9478 DHD_LINUX_GENERAL_LOCK(dhdp, flags);
9479 dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS;
9480 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
9481
9482 timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
9483 if ((timeleft == 0) || (timeleft == 1)) {
9484 DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
9485 __FUNCTION__, dhdp->dhd_bus_busy_state));
9486 ASSERT(0);
9487 }
9488
9489 return;
9490 }
9491
9492 static void
dhdsdio_advertise_bus_remove(dhd_pub_t * dhdp)9493 dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp)
9494 {
9495 unsigned long flags;
9496 int timeleft;
9497
9498 DHD_LINUX_GENERAL_LOCK(dhdp, flags);
9499 dhdp->busstate = DHD_BUS_REMOVE;
9500 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
9501
9502 timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
9503 if ((timeleft == 0) || (timeleft == 1)) {
9504 DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
9505 __FUNCTION__, dhdp->dhd_bus_busy_state));
9506 ASSERT(0);
9507 }
9508
9509 return;
9510 }
9511
9512 int
dhd_bus_devreset(dhd_pub_t * dhdp,uint8 flag)9513 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
9514 {
9515 int bcmerror = 0;
9516 dhd_bus_t *bus;
9517 unsigned long flags;
9518
9519 bus = dhdp->bus;
9520
9521 if (flag == TRUE) {
9522 if (!bus->dhd->dongle_reset) {
9523 DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__));
9524 dhdsdio_advertise_bus_cleanup(bus->dhd);
9525 dhd_os_sdlock(dhdp);
9526 dhd_os_wd_timer(dhdp, 0);
9527 #if !defined(IGNORE_ETH0_DOWN)
9528 /* Force flow control as protection when stop come before ifconfig_down */
9529 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
9530 #endif /* !defined(IGNORE_ETH0_DOWN) */
9531 /* Expect app to have torn down any connection before calling */
9532 /* Stop the bus, disable F2 */
9533 dhd_bus_stop(bus, FALSE);
9534 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
9535 /* Clean up any pending IRQ */
9536 dhd_enable_oob_intr(bus, FALSE);
9537 bcmsdh_oob_intr_set(bus->sdh, FALSE);
9538 bcmsdh_oob_intr_unregister(bus->sdh);
9539 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
9540
9541 /* Clean tx/rx buffer pointers, detach from the dongle */
9542 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
9543
9544 bus->dhd->dongle_reset = TRUE;
9545 DHD_ERROR(("%s: making dhdpub up FALSE\n", __FUNCTION__));
9546 bus->dhd->up = FALSE;
9547 dhd_txglom_enable(dhdp, FALSE);
9548 dhd_os_sdunlock(dhdp);
9549
9550 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9551 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
9552 bus->dhd->busstate = DHD_BUS_DOWN;
9553 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9554
9555 printf("%s: WLAN OFF DONE\n", __FUNCTION__);
9556 /* App can now remove power from device */
9557 } else
9558 bcmerror = BCME_SDIO_ERROR;
9559 } else {
9560 /* App must have restored power to device before calling */
9561
9562 printf("%s: == Power ON ==\n", __FUNCTION__);
9563
9564 if (bus->dhd->dongle_reset) {
9565 /* Turn on WLAN */
9566 dhd_os_sdlock(dhdp);
9567 /* Reset SD client -- required if devreset is called
9568 * via 'dhd devreset' iovar
9569 */
9570 bcmsdh_reset(bus->sdh);
9571 /* Attempt to re-attach & download */
9572 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
9573 (uint32 *)(uintptr)si_enum_base(bus->cl_devid),
9574 bus->cl_devid)) {
9575
9576 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9577 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
9578 bus->dhd->busstate = DHD_BUS_DOWN;
9579 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9580
9581 /* Attempt to download binary to the dongle */
9582 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
9583 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) {
9584
9585 /* Re-init bus, enable F2 transfer */
9586 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
9587 if (bcmerror == BCME_OK) {
9588 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
9589 dhd_enable_oob_intr(bus, TRUE);
9590 bcmsdh_oob_intr_register(bus->sdh,
9591 dhdsdio_isr, bus);
9592 bcmsdh_oob_intr_set(bus->sdh, TRUE);
9593 #elif defined(FORCE_WOWLAN)
9594 dhd_enable_oob_intr(bus, TRUE);
9595 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
9596
9597 bus->dhd->dongle_reset = FALSE;
9598 bus->dhd->up = TRUE;
9599
9600 #if !defined(IGNORE_ETH0_DOWN)
9601 /* Restore flow control */
9602 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
9603 #endif // endif
9604 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
9605
9606 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
9607 } else {
9608 dhd_bus_stop(bus, FALSE);
9609 dhdsdio_release_dongle(bus, bus->dhd->osh,
9610 TRUE, FALSE);
9611 }
9612 } else {
9613 DHD_ERROR(("%s Failed to download binary to the dongle\n",
9614 __FUNCTION__));
9615 if (bus->sih != NULL) {
9616 si_detach(bus->sih);
9617 bus->sih = NULL;
9618 }
9619 bcmerror = BCME_SDIO_ERROR;
9620 }
9621 } else
9622 bcmerror = BCME_SDIO_ERROR;
9623
9624 dhd_os_sdunlock(dhdp);
9625 } else {
9626 printf("%s called when dongle is not in reset\n",
9627 __FUNCTION__);
9628 printf("Will call dhd_bus_start instead\n");
9629 dhd_bus_resume(dhdp, 1);
9630 #if defined(HW_OOB) || defined(FORCE_WOWLAN)
9631 dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih); // terence 20120615: fix for OOB initial issue
9632 #endif
9633 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
9634 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
9635 __FUNCTION__, bcmerror));
9636 }
9637 }
9638
9639 #ifdef PKT_STATICS
9640 dhd_bus_clear_txpktstatics(bus);
9641 #endif
9642 return bcmerror;
9643 }
9644
dhd_bus_suspend(dhd_pub_t * dhdpub)9645 int dhd_bus_suspend(dhd_pub_t *dhdpub)
9646 {
9647 return bcmsdh_stop(dhdpub->bus->sdh);
9648 }
9649
dhd_bus_resume(dhd_pub_t * dhdpub,int stage)9650 int dhd_bus_resume(dhd_pub_t *dhdpub, int stage)
9651 {
9652 return bcmsdh_start(dhdpub->bus->sdh, stage);
9653 }
9654
9655 /* Get Chip ID version */
dhd_bus_chip_id(dhd_pub_t * dhdp)9656 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
9657 {
9658 dhd_bus_t *bus = dhdp->bus;
9659
9660 if (bus && bus->sih)
9661 return bus->sih->chip;
9662 else
9663 return 0;
9664 }
9665
9666 /* Get Chip Rev ID version */
dhd_bus_chiprev_id(dhd_pub_t * dhdp)9667 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
9668 {
9669 dhd_bus_t *bus = dhdp->bus;
9670
9671 if (bus && bus->sih)
9672 return bus->sih->chiprev;
9673 else
9674 return 0;
9675 }
9676
9677 /* Get Chip Pkg ID version */
dhd_bus_chippkg_id(dhd_pub_t * dhdp)9678 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
9679 {
9680 dhd_bus_t *bus = dhdp->bus;
9681
9682 return bus->sih->chippkg;
9683 }
9684
dhd_bus_get_ids(struct dhd_bus * bus,uint32 * bus_type,uint32 * bus_num,uint32 * slot_num)9685 int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num)
9686 {
9687 *bus_type = bus->bus;
9688 *bus_num = bus->bus_num;
9689 *slot_num = bus->slot_num;
9690 return 0;
9691 }
9692
9693 int
dhd_bus_membytes(dhd_pub_t * dhdp,bool set,uint32 address,uint8 * data,uint size)9694 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
9695 {
9696 dhd_bus_t *bus;
9697
9698 bus = dhdp->bus;
9699 return dhdsdio_membytes(bus, set, address, data, size);
9700 }
9701
9702 #if defined(SUPPORT_MULTIPLE_REVISION)
9703 static int
concate_revision_bcm4335(dhd_bus_t * bus,char * fw_path,char * nv_path)9704 concate_revision_bcm4335(dhd_bus_t *bus, char *fw_path, char *nv_path)
9705 {
9706
9707 uint chipver;
9708 #if defined(SUPPORT_MULTIPLE_CHIPS)
9709 char chipver_tag[10] = "_4335";
9710 #else
9711 char chipver_tag[4] = {0, };
9712 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9713
9714 DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__));
9715 if (bus->sih->chip != BCM4335_CHIP_ID) {
9716 DHD_ERROR(("%s:Chip is not BCM4335\n", __FUNCTION__));
9717 return -1;
9718 }
9719 chipver = bus->sih->chiprev;
9720 DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
9721 if (chipver == 0x0) {
9722 DHD_ERROR(("----- CHIP bcm4335_A0 -----\n"));
9723 strcat(chipver_tag, "_a0");
9724 } else if (chipver == 0x1) {
9725 DHD_ERROR(("----- CHIP bcm4335_B0 -----\n"));
9726 #if defined(SUPPORT_MULTIPLE_CHIPS)
9727 strcat(chipver_tag, "_b0");
9728 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9729 }
9730
9731 strcat(fw_path, chipver_tag);
9732 strcat(nv_path, chipver_tag);
9733 return 0;
9734 }
9735
9736 static int
concate_revision_bcm4339(dhd_bus_t * bus,char * fw_path,char * nv_path)9737 concate_revision_bcm4339(dhd_bus_t *bus, char *fw_path, char *nv_path)
9738 {
9739
9740 uint chipver;
9741 #if defined(SUPPORT_MULTIPLE_CHIPS)
9742 char chipver_tag[10] = "_4339";
9743 #else
9744 char chipver_tag[4] = {0, };
9745 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9746
9747 DHD_TRACE(("%s: BCM4339 Multiple Revision Check\n", __FUNCTION__));
9748 if (bus->sih->chip != BCM4339_CHIP_ID) {
9749 DHD_ERROR(("%s:Chip is not BCM4339\n", __FUNCTION__));
9750 return -1;
9751 }
9752 chipver = bus->sih->chiprev;
9753 DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
9754 if (chipver == 0x1) {
9755 DHD_ERROR(("----- CHIP bcm4339_A0 -----\n"));
9756 strcat(chipver_tag, "_a0");
9757 } else {
9758 DHD_ERROR(("----- CHIP bcm4339 unknown revision %d -----\n",
9759 chipver));
9760 }
9761
9762 strcat(fw_path, chipver_tag);
9763 strcat(nv_path, chipver_tag);
9764 return 0;
9765 }
9766
concate_revision_bcm4350(dhd_bus_t * bus,char * fw_path,char * nv_path)9767 static int concate_revision_bcm4350(dhd_bus_t *bus, char *fw_path, char *nv_path)
9768 {
9769 uint32 chip_ver;
9770 #if defined(SUPPORT_MULTIPLE_CHIPS)
9771 char chipver_tag[10] = {0, };
9772 #else
9773 char chipver_tag[4] = {0, };
9774 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9775 chip_ver = bus->sih->chiprev;
9776
9777 #if defined(SUPPORT_MULTIPLE_CHIPS)
9778 if (chip_ver == 3)
9779 strcat(chipver_tag, "_4354");
9780 else
9781 strcat(chipver_tag, "_4350");
9782 #endif // endif
9783
9784 if (chip_ver == 3) {
9785 DHD_ERROR(("----- CHIP 4354 A0 -----\n"));
9786 strcat(chipver_tag, "_a0");
9787 } else {
9788 DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver));
9789 }
9790
9791 strcat(fw_path, chipver_tag);
9792 strcat(nv_path, chipver_tag);
9793 return 0;
9794 }
9795
concate_revision_bcm4354(dhd_bus_t * bus,char * fw_path,char * nv_path)9796 static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path, char *nv_path)
9797 {
9798 uint32 chip_ver;
9799 #if defined(SUPPORT_MULTIPLE_CHIPS)
9800 char chipver_tag[10] = "_4354";
9801 #else
9802 char chipver_tag[4] = {0, };
9803 #endif /* SUPPORT_MULTIPLE_CHIPS */
9804
9805 chip_ver = bus->sih->chiprev;
9806 if (chip_ver == 1) {
9807 DHD_ERROR(("----- CHIP 4354 A1 -----\n"));
9808 strcat(chipver_tag, "_a1");
9809 } else {
9810 DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver));
9811 }
9812
9813 strcat(fw_path, chipver_tag);
9814 strcat(nv_path, chipver_tag);
9815
9816 return 0;
9817 }
9818
9819 static int
concate_revision_bcm43454(dhd_bus_t * bus,char * fw_path,char * nv_path)9820 concate_revision_bcm43454(dhd_bus_t *bus, char *fw_path, char *nv_path)
9821 {
9822 char chipver_tag[10] = {0, };
9823 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9824 int base_system_rev_for_nv = 0;
9825 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9826
9827 DHD_TRACE(("%s: BCM43454 Multiple Revision Check\n", __FUNCTION__));
9828 if (bus->sih->chip != BCM43454_CHIP_ID) {
9829 DHD_ERROR(("%s:Chip is not BCM43454!\n", __FUNCTION__));
9830 return -1;
9831 }
9832 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9833 base_system_rev_for_nv = dhd_get_system_rev();
9834 if (base_system_rev_for_nv > 0) {
9835 DHD_ERROR(("----- Board Rev [%d] -----\n", base_system_rev_for_nv));
9836 sprintf(chipver_tag, "_r%02d", base_system_rev_for_nv);
9837 }
9838 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9839 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
9840 DHD_ERROR(("----- Rev [%d] Fot MULTIPLE Board. -----\n", system_hw_rev));
9841 if ((system_hw_rev >= 8) && (system_hw_rev <= 11)) {
9842 DHD_ERROR(("This HW is Rev 08 ~ 11. this is For FD-HW\n"));
9843 strcat(chipver_tag, "_FD");
9844 }
9845 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
9846
9847 strcat(nv_path, chipver_tag);
9848 return 0;
9849 }
9850
9851 int
concate_revision(dhd_bus_t * bus,char * fw_path,char * nv_path)9852 concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path)
9853 {
9854 int res = 0;
9855
9856 if (!bus || !bus->sih) {
9857 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
9858 return -1;
9859 }
9860
9861 switch (bus->sih->chip) {
9862 case BCM4335_CHIP_ID:
9863 res = concate_revision_bcm4335(bus, fw_path, nv_path);
9864
9865 break;
9866 case BCM4339_CHIP_ID:
9867 res = concate_revision_bcm4339(bus, fw_path, nv_path);
9868 break;
9869 case BCM4350_CHIP_ID:
9870 res = concate_revision_bcm4350(bus, fw_path, nv_path);
9871 break;
9872 case BCM4354_CHIP_ID:
9873 res = concate_revision_bcm4354(bus, fw_path, nv_path);
9874 break;
9875 case BCM43454_CHIP_ID:
9876 res = concate_revision_bcm43454(bus, fw_path, nv_path);
9877 break;
9878
9879 default:
9880 DHD_ERROR(("REVISION SPECIFIC feature is not required\n"));
9881 return res;
9882 }
9883
9884 if (res == 0) {
9885 }
9886 return res;
9887 }
9888 #endif /* SUPPORT_MULTIPLE_REVISION */
9889
9890 void
dhd_bus_update_fw_nv_path(struct dhd_bus * bus,char * pfw_path,char * pnv_path,char * pclm_path,char * pconf_path)9891 dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path,
9892 char *pclm_path, char *pconf_path)
9893 {
9894 bus->fw_path = pfw_path;
9895 bus->nv_path = pnv_path;
9896 bus->dhd->clm_path = pclm_path;
9897 bus->dhd->conf_path = pconf_path;
9898 }
9899
9900 int
dhd_enableOOB(dhd_pub_t * dhd,bool sleep)9901 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
9902 {
9903 dhd_bus_t *bus = dhd->bus;
9904 sdpcmd_regs_t *regs = bus->regs;
9905 uint retries = 0;
9906
9907 if (sleep) {
9908 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9909 /* Tell device to start using OOB wakeup */
9910 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
9911 if (retries > retry_limit) {
9912 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
9913 return BCME_BUSY;
9914 }
9915 /* Turn off our contribution to the HT clock request */
9916 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
9917 } else {
9918 /* Make sure the controller has the bus up */
9919 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9920
9921 /* Send misc interrupt to indicate OOB not needed */
9922 W_SDREG(0, ®s->tosbmailboxdata, retries);
9923 if (retries <= retry_limit)
9924 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
9925
9926 if (retries > retry_limit)
9927 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
9928
9929 /* Make sure we have SD bus access */
9930 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
9931 }
9932 return BCME_OK;
9933 }
9934
9935 void
dhd_bus_pktq_flush(dhd_pub_t * dhdp)9936 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
9937 {
9938 dhd_bus_t *bus = dhdp->bus;
9939 bool wlfc_enabled = FALSE;
9940
9941 #ifdef PROP_TXSTATUS
9942 wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED);
9943 #endif // endif
9944 if (!wlfc_enabled) {
9945 #ifdef DHDTCPACK_SUPPRESS
9946 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
9947 * when there is a newly coming packet from network stack.
9948 */
9949 dhd_tcpack_info_tbl_clean(bus->dhd);
9950 #endif /* DHDTCPACK_SUPPRESS */
9951 /* Clear the data packet queues */
9952 pktq_flush(dhdp->osh, &bus->txq, TRUE);
9953 }
9954 }
9955
9956 #ifdef BCMSDIO
9957 int
dhd_sr_config(dhd_pub_t * dhd,bool on)9958 dhd_sr_config(dhd_pub_t *dhd, bool on)
9959 {
9960 dhd_bus_t *bus = dhd->bus;
9961
9962 if (!bus->_srenab)
9963 return -1;
9964
9965 return dhdsdio_clk_devsleep_iovar(bus, on);
9966 }
9967
9968 uint16
dhd_get_chipid(dhd_pub_t * dhd)9969 dhd_get_chipid(dhd_pub_t *dhd)
9970 {
9971 dhd_bus_t *bus = dhd->bus;
9972
9973 if (bus && bus->sih)
9974 return (uint16)bus->sih->chip;
9975 else
9976 return 0;
9977 }
9978 #endif /* BCMSDIO */
9979
9980 #ifdef DEBUGGER
9981 static uint32
dhd_sdio_reg_read(struct dhd_bus * bus,ulong addr)9982 dhd_sdio_reg_read(struct dhd_bus *bus, ulong addr)
9983 {
9984 uint32 rval;
9985
9986 dhd_os_sdlock(bus->dhd);
9987
9988 BUS_WAKE(bus);
9989
9990 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9991
9992 rval = bcmsdh_reg_read(bus->sdh, addr, 4);
9993
9994 dhd_os_sdunlock(bus->dhd);
9995
9996 return rval;
9997 }
9998
9999 static void
dhd_sdio_reg_write(struct dhd_bus * bus,ulong addr,uint32 val)10000 dhd_sdio_reg_write(struct dhd_bus *bus, ulong addr, uint32 val)
10001 {
10002 dhd_os_sdlock(bus->dhd);
10003
10004 BUS_WAKE(bus);
10005
10006 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
10007
10008 bcmsdh_reg_write(bus->sdh, addr, 4, val);
10009
10010 dhd_os_sdunlock(bus->dhd);
10011 }
10012
10013 #endif /* DEBUGGER */
10014
10015 #if defined(BT_OVER_SDIO)
dhd_bus_cfg_read(void * h,uint fun_num,uint32 addr,int * err)10016 uint8 dhd_bus_cfg_read(void *h, uint fun_num, uint32 addr, int *err)
10017 {
10018 uint8 intrd;
10019 dhd_pub_t *dhdp = (dhd_pub_t *)h;
10020 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
10021
10022 dhd_os_sdlock(bus->dhd);
10023
10024 intrd = bcmsdh_cfg_read(bus->sdh, fun_num, addr, err);
10025
10026 dhd_os_sdunlock(bus->dhd);
10027
10028 return intrd;
10029 } EXPORT_SYMBOL(dhd_bus_cfg_read);
10030
dhd_bus_cfg_write(void * h,uint fun_num,uint32 addr,uint8 val,int * err)10031 void dhd_bus_cfg_write(void *h, uint fun_num, uint32 addr, uint8 val, int *err)
10032 {
10033 dhd_pub_t *dhdp = (dhd_pub_t *)h;
10034 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
10035
10036 dhd_os_sdlock(bus->dhd);
10037
10038 bcmsdh_cfg_write(bus->sdh, fun_num, addr, val, err);
10039
10040 dhd_os_sdunlock(bus->dhd);
10041
10042 } EXPORT_SYMBOL(dhd_bus_cfg_write);
10043
10044 static int
extract_hex_field(char * line,uint16 start_pos,uint16 num_chars,uint16 * value)10045 extract_hex_field(char * line, uint16 start_pos, uint16 num_chars, uint16 * value)
10046 {
10047 char field [8];
10048
10049 strncpy(field, line + start_pos, num_chars);
10050 field [num_chars] = '\0';
10051
10052 return (sscanf (field, "%hX", value) == 1);
10053 }
10054
10055 static int
read_more_btbytes(struct dhd_bus * bus,void * file,char * line,int * addr_mode,uint16 * hi_addr,uint32 * dest_addr,uint8 * data_bytes,uint32 * num_bytes)10056 read_more_btbytes(struct dhd_bus *bus, void * file, char *line, int * addr_mode, uint16 * hi_addr,
10057 uint32 * dest_addr, uint8 *data_bytes, uint32 * num_bytes)
10058 {
10059 int str_len;
10060 uint16 num_data_bytes, addr, data_pos, type, w, i;
10061 uint32 abs_base_addr32 = 0;
10062 *num_bytes = 0;
10063
10064 while (!*num_bytes)
10065 {
10066 str_len = dhd_os_gets_image(bus->dhd, line, BTFW_MAX_STR_LEN, file);
10067
10068 DHD_TRACE(("%s: Len :0x%x %s\n", __FUNCTION__, str_len, line));
10069
10070 if (str_len == 0) {
10071 break;
10072 } else if (str_len > 9) {
10073 extract_hex_field(line, 1, 2, &num_data_bytes);
10074 extract_hex_field(line, 3, 4, &addr);
10075 extract_hex_field(line, 7, 2, &type);
10076
10077 data_pos = 9;
10078 for (i = 0; i < num_data_bytes; i++) {
10079 extract_hex_field(line, data_pos, 2, &w);
10080 data_bytes [i] = (uint8)(w & 0x00FF);
10081 data_pos += 2;
10082 }
10083
10084 if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) {
10085 *hi_addr = (data_bytes [0] << 8) | data_bytes [1];
10086 *addr_mode = BTFW_ADDR_MODE_EXTENDED;
10087 } else if (type == BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS) {
10088 *hi_addr = (data_bytes [0] << 8) | data_bytes [1];
10089 *addr_mode = BTFW_ADDR_MODE_SEGMENT;
10090 } else if (type == BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS) {
10091 abs_base_addr32 = (data_bytes [0] << 24) | (data_bytes [1] << 16) |
10092 (data_bytes [2] << 8) | data_bytes [3];
10093 *addr_mode = BTFW_ADDR_MODE_LINEAR32;
10094 } else if (type == BTFW_HEX_LINE_TYPE_DATA) {
10095 *dest_addr = addr;
10096 if (*addr_mode == BTFW_ADDR_MODE_EXTENDED)
10097 *dest_addr += (*hi_addr << 16);
10098 else if (*addr_mode == BTFW_ADDR_MODE_SEGMENT)
10099 *dest_addr += (*hi_addr << 4);
10100 else if (*addr_mode == BTFW_ADDR_MODE_LINEAR32)
10101 *dest_addr += abs_base_addr32;
10102 *num_bytes = num_data_bytes;
10103 }
10104 }
10105 }
10106 return (*num_bytes > 0);
10107 }
10108
10109 static int
_dhdsdio_download_btfw(struct dhd_bus * bus)10110 _dhdsdio_download_btfw(struct dhd_bus *bus)
10111 {
10112 int bcm_error = -1;
10113 void *image = NULL;
10114 uint8 *mem_blk = NULL, *mem_ptr = NULL, *data_ptr = NULL;
10115
10116 uint32 offset_addr = 0, offset_len = 0, bytes_to_write = 0;
10117
10118 char *line = NULL;
10119 uint32 dest_addr = 0, num_bytes;
10120 uint16 hiAddress = 0;
10121 uint32 start_addr, start_data, end_addr, end_data, i, index, pad,
10122 bt2wlan_pwrup_adr;
10123
10124 int addr_mode = BTFW_ADDR_MODE_EXTENDED;
10125
10126 /* Out immediately if no image to download */
10127 if ((bus->btfw_path == NULL) || (bus->btfw_path[0] == '\0')) {
10128 return 0;
10129 }
10130
10131 image = dhd_os_open_image1(bus->dhd, bus->btfw_path);
10132 if (image == NULL)
10133 goto err;
10134
10135 mem_ptr = mem_blk = MALLOC(bus->dhd->osh, BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN);
10136 if (mem_blk == NULL) {
10137 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
10138 BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN));
10139 goto err;
10140 }
10141 if ((uint32)(uintptr)mem_blk % DHD_SDALIGN)
10142 mem_ptr += (DHD_SDALIGN - ((uint32)(uintptr)mem_blk % DHD_SDALIGN));
10143
10144 data_ptr = MALLOC(bus->dhd->osh, BTFW_DOWNLOAD_BLK_SIZE - 8);
10145 if (data_ptr == NULL) {
10146 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
10147 BTFW_DOWNLOAD_BLK_SIZE - 8));
10148 goto err;
10149 }
10150 /* Write to BT register to hold WLAN wake high during BT FW download */
10151 bt2wlan_pwrup_adr = BTMEM_OFFSET + BT2WLAN_PWRUP_ADDR;
10152 bcmsdh_reg_write(bus->sdh, bt2wlan_pwrup_adr, 4, BT2WLAN_PWRUP_WAKE);
10153 /*
10154 * Wait for at least 2msec for the clock to be ready/Available.
10155 */
10156 OSL_DELAY(2000);
10157
10158 line = MALLOC(bus->dhd->osh, BTFW_MAX_STR_LEN);
10159 if (line == NULL) {
10160 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
10161 __FUNCTION__, BTFW_MAX_STR_LEN));
10162 goto err;
10163 }
10164 memset(line, 0, BTFW_MAX_STR_LEN);
10165
10166 while (read_more_btbytes (bus, image, line, &addr_mode, &hiAddress, &dest_addr,
10167 data_ptr, &num_bytes)) {
10168
10169 DHD_TRACE(("read %d bytes at address %08X\n", num_bytes, dest_addr));
10170
10171 start_addr = BTMEM_OFFSET + dest_addr;
10172 index = 0;
10173
10174 /* Make sure the start address is 4 byte aligned to avoid alignment issues
10175 * with SD host controllers
10176 */
10177 if (!ISALIGNED(start_addr, 4)) {
10178 pad = start_addr % 4;
10179 start_addr = ROUNDDN(start_addr, 4);
10180 start_data = bcmsdh_reg_read(bus->sdh, start_addr, 4);
10181 for (i = 0; i < pad; i++, index++) {
10182 mem_ptr[index] = (uint8)((uint8 *)&start_data)[i];
10183 }
10184 }
10185 bcopy(data_ptr, &(mem_ptr[index]), num_bytes);
10186 index += num_bytes;
10187
10188 /* Make sure the length is multiple of 4bytes to avoid alignment issues
10189 * with SD host controllers
10190 */
10191 end_addr = start_addr + index;
10192 if (!ISALIGNED(end_addr, 4)) {
10193 end_addr = ROUNDDN(end_addr, 4);
10194 end_data = bcmsdh_reg_read(bus->sdh, end_addr, 4);
10195 for (i = (index % 4); i < 4; i++, index++) {
10196 mem_ptr[index] = (uint8)((uint8 *)&end_data)[i];
10197 }
10198 }
10199
10200 offset_addr = start_addr & 0xFFF;
10201 offset_len = offset_addr + index;
10202 if (offset_len <= 0x1000) {
10203 bcm_error = dhdsdio_membytes(bus, TRUE, start_addr, mem_ptr, index);
10204 if (bcm_error) {
10205 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
10206 __FUNCTION__, bcm_error, num_bytes, start_addr));
10207 goto err;
10208 }
10209 }
10210 else {
10211 bytes_to_write = 0x1000 - offset_addr;
10212 bcm_error = dhdsdio_membytes(bus, TRUE, start_addr, mem_ptr,
10213 bytes_to_write);
10214 if (bcm_error) {
10215 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
10216 __FUNCTION__, bcm_error, num_bytes, start_addr));
10217 goto err;
10218 }
10219
10220 OSL_DELAY(10000);
10221
10222 bcm_error = dhdsdio_membytes(bus, TRUE, (start_addr + bytes_to_write),
10223 (mem_ptr + bytes_to_write), (index - bytes_to_write));
10224 if (bcm_error) {
10225 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
10226 __FUNCTION__, bcm_error, num_bytes, start_addr));
10227 goto err;
10228 }
10229 }
10230 memset(line, 0, BTFW_MAX_STR_LEN);
10231 }
10232
10233 bcm_error = 0;
10234 err:
10235 if (mem_blk)
10236 MFREE(bus->dhd->osh, mem_blk, BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN);
10237
10238 if (data_ptr)
10239 MFREE(bus->dhd->osh, data_ptr, BTFW_DOWNLOAD_BLK_SIZE - 8);
10240
10241 if (line)
10242 MFREE(bus->dhd->osh, line, BTFW_MAX_STR_LEN);
10243
10244 if (image)
10245 dhd_os_close_image1(bus->dhd, image);
10246
10247 return bcm_error;
10248 }
10249
10250 static int
dhdsdio_download_btfw(struct dhd_bus * bus,osl_t * osh,void * sdh)10251 dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh)
10252 {
10253 int ret;
10254
10255 DHD_TRACE(("%s: btfw path=%s\n",
10256 __FUNCTION__, bus->btfw_path));
10257 DHD_OS_WAKE_LOCK(bus->dhd);
10258 dhd_os_sdlock(bus->dhd);
10259
10260 /* Download the firmware */
10261 ret = _dhdsdio_download_btfw(bus);
10262
10263 dhd_os_sdunlock(bus->dhd);
10264 DHD_OS_WAKE_UNLOCK(bus->dhd);
10265
10266 return ret;
10267 }
10268
10269 int
dhd_bus_download_btfw(struct dhd_bus * bus,osl_t * osh,char * pbtfw_path)10270 dhd_bus_download_btfw(struct dhd_bus *bus, osl_t *osh,
10271 char *pbtfw_path)
10272 {
10273 int ret;
10274
10275 bus->btfw_path = pbtfw_path;
10276
10277 ret = dhdsdio_download_btfw(bus, osh, bus->sdh);
10278
10279 return ret;
10280 }
10281 #endif /* defined (BT_OVER_SDIO) */
10282
10283 void
dhd_bus_dump_trap_info(dhd_bus_t * bus,struct bcmstrbuf * strbuf)10284 dhd_bus_dump_trap_info(dhd_bus_t *bus, struct bcmstrbuf *strbuf)
10285 {
10286 trap_t *tr = &bus->dhd->last_trap_info;
10287
10288 bcm_bprintf(strbuf,
10289 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
10290 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
10291 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
10292 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
10293 ltoh32(tr->type), ltoh32(tr->epc), ltoh32(tr->cpsr), ltoh32(tr->spsr),
10294 ltoh32(tr->r13), ltoh32(tr->r14), ltoh32(tr->pc),
10295 ltoh32(bus->dongle_trap_addr),
10296 ltoh32(tr->r0), ltoh32(tr->r1), ltoh32(tr->r2), ltoh32(tr->r3),
10297 ltoh32(tr->r4), ltoh32(tr->r5), ltoh32(tr->r6), ltoh32(tr->r7));
10298
10299 }
10300
10301 static int
dhd_bcmsdh_send_buffer(void * bus,uint8 * frame,uint16 len)10302 dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len)
10303 {
10304 int ret = -1;
10305
10306 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(((dhd_bus_t*)bus)->sdh),
10307 SDIO_FUNC_2, F2SYNC, frame, len, NULL, NULL, NULL, TXRETRIES);
10308
10309 if (ret == BCME_OK)
10310 ((dhd_bus_t*)bus)->tx_seq = (((dhd_bus_t*)bus)->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
10311
10312 return ret;
10313 }
10314
10315 /* Function to set the min res mask depending on the chip ID used */
10316 bool
dhd_bus_set_default_min_res_mask(struct dhd_bus * bus)10317 dhd_bus_set_default_min_res_mask(struct dhd_bus *bus)
10318 {
10319 if ((bus == NULL) || (bus->sih == NULL)) {
10320 DHD_ERROR(("%s(): Invalid Arguments \r\n", __FUNCTION__));
10321 return FALSE;
10322 }
10323
10324 switch (bus->sih->chip) {
10325 case BCM4339_CHIP_ID:
10326 bcmsdh_reg_write(bus->sdh, SI_ENUM_BASE(bus->sih) + 0x618, 4, 0x3fcaf377);
10327 if (bcmsdh_regfail(bus->sdh)) {
10328 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__));
10329 return FALSE;
10330 }
10331 break;
10332
10333 case BCM43012_CHIP_ID:
10334 bcmsdh_reg_write(bus->sdh,
10335 si_get_pmu_reg_addr(bus->sih, OFFSETOF(pmuregs_t, min_res_mask)),
10336 4, DEFAULT_43012_MIN_RES_MASK);
10337 if (bcmsdh_regfail(bus->sdh)) {
10338 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__));
10339 return FALSE;
10340 }
10341 break;
10342
10343 default:
10344 DHD_ERROR(("%s: Unhandled chip id\n", __FUNCTION__));
10345 return FALSE;
10346 }
10347
10348 return TRUE;
10349 }
10350
10351 /* Function to reset PMU registers */
10352 void
dhd_bus_pmu_reg_reset(dhd_pub_t * dhdp)10353 dhd_bus_pmu_reg_reset(dhd_pub_t *dhdp)
10354 {
10355 struct dhd_bus *bus = dhdp->bus;
10356 bcmsdh_reg_write(bus->sdh, si_get_pmu_reg_addr(bus->sih,
10357 OFFSETOF(pmuregs_t, swscratch)), 4, 0x0);
10358 if (bcmsdh_regfail(bus->sdh)) {
10359 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__));
10360 }
10361 }
10362
10363 #ifdef DHD_ULP
10364
10365 /* Function to disable console messages on entering ULP mode */
10366 void
dhd_bus_ulp_disable_console(dhd_pub_t * dhdp)10367 dhd_bus_ulp_disable_console(dhd_pub_t *dhdp)
10368 {
10369 #ifdef DHD_DEBUG
10370 DHD_ERROR(("Flushing and disabling console messages\n"));
10371
10372 /* Save the console print interval */
10373 dhd_ulp_save_console_interval(dhdp);
10374
10375 /* Flush the console buffer before disabling */
10376 dhdsdio_readconsole(dhdp->bus);
10377 dhdp->dhd_console_ms = 0;
10378 #endif /* DHD_DEBUG */
10379 }
10380
10381 /* Function for redownloading firmaware */
10382 static int
dhd_bus_ulp_reinit_fw(dhd_bus_t * bus)10383 dhd_bus_ulp_reinit_fw(dhd_bus_t *bus)
10384 {
10385 int bcmerror = 0;
10386
10387 /* After firmware redownload tx/rx seq are reset accordingly these values are
10388 reset on DHD side tx_max is initially set to 4, which later is updated by FW
10389 */
10390 bus->tx_seq = bus->rx_seq = 0;
10391 bus->tx_max = 4;
10392
10393 if (dhd_bus_download_firmware(bus, bus->dhd->osh,
10394 bus->fw_path, bus->nv_path) >= 0) {
10395
10396 /* Re-init bus, enable F2 transfer */
10397 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
10398 if (bcmerror == BCME_OK) {
10399 bus->dhd->up = TRUE;
10400 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
10401
10402 dhd_ulp_set_ulp_state(bus->dhd, DHD_ULP_READY);
10403 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
10404 dhd_enable_oob_intr(bus, TRUE);
10405 bcmsdh_oob_intr_set(bus->sdh, TRUE);
10406 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
10407 #ifdef DHD_DEBUG
10408 /* Re-enable the console messages on FW redownload to default value */
10409 dhd_ulp_restore_console_interval(bus->dhd);
10410 #endif /* DHD_DEBUG */
10411 } else {
10412 DHD_ERROR(("bus init failed\n"));
10413 dhd_bus_stop(bus, FALSE);
10414 dhdsdio_release_dongle(bus, bus->dhd->osh,
10415 TRUE, FALSE);
10416 }
10417 } else
10418 bcmerror = BCME_SDIO_ERROR;
10419
10420 return bcmerror;
10421 }
10422 #endif /* DHD_ULP */
10423
10424 int
dhd_bus_readwrite_bp_addr(dhd_pub_t * dhdp,uint addr,uint size,uint * data,bool read)10425 dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint* data, bool read)
10426 {
10427 int bcmerror = 0;
10428 struct dhd_bus *bus = dhdp->bus;
10429
10430 if (read) {
10431 *data = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
10432 } else {
10433 bcmsdh_reg_write(bus->sdh, addr, size, *data);
10434 }
10435
10436 if (bcmsdh_regfail(bus->sdh))
10437 bcmerror = BCME_SDIO_ERROR;
10438
10439 return bcmerror;
10440 }
10441
dhd_get_idletime(dhd_pub_t * dhd)10442 int dhd_get_idletime(dhd_pub_t *dhd)
10443 {
10444 return dhd->bus->idletime;
10445 }
10446
10447 #ifdef DHD_WAKE_STATUS
10448 wake_counts_t*
dhd_bus_get_wakecount(dhd_pub_t * dhd)10449 dhd_bus_get_wakecount(dhd_pub_t *dhd)
10450 {
10451 if (!dhd->bus) {
10452 return NULL;
10453 }
10454 return &dhd->bus->wake_counts;
10455 }
10456 int
dhd_bus_get_bus_wake(dhd_pub_t * dhd)10457 dhd_bus_get_bus_wake(dhd_pub_t *dhd)
10458 {
10459 return bcmsdh_set_get_wake(dhd->bus->sdh, 0);
10460 }
10461 #endif /* DHD_WAKE_STATUS */
10462
10463 int
dhd_bus_sleep(dhd_pub_t * dhdp,bool sleep,uint32 * intstatus)10464 dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus)
10465 {
10466 dhd_bus_t *bus = dhdp->bus;
10467 uint32 retry = 0;
10468 int ret = 0;
10469
10470 if (bus) {
10471 dhd_os_sdlock(dhdp);
10472 BUS_WAKE(bus);
10473 R_SDREG(*intstatus, &bus->regs->intstatus, retry);
10474 if (sleep) {
10475 if (SLPAUTO_ENAB(bus)) {
10476 ret = dhdsdio_bussleep(bus, sleep);
10477 if (ret != BCME_BUSY)
10478 dhd_os_wd_timer(bus->dhd, 0);
10479 } else
10480 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
10481 }
10482 dhd_os_sdunlock(dhdp);
10483 } else {
10484 DHD_ERROR(("bus is NULL\n"));
10485 ret = -1;
10486 }
10487
10488 return ret;
10489 }