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