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