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