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