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