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