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